Hibernate5.2之單向一對多
一. 簡介
Hibernate中最復雜的應該就是各種關聯(單向一對多、單向多對一、雙向一對多、一對一、多對多)關系的映射,於是筆者就想着去寫一些關於Hibernate相關的系列文章,可能最近今年項目上基本上沒怎么用Hibernate,包括身邊的很多人都在唱衰Hibernate,覺得他笨重、低效,但是筆者認為這都不影響其在我心目中的地位,以及他當初給筆者所帶來的震撼,也影響千千萬萬的程序員。本系列博客中沒有關於Hibernate原理性的東西的講解,只是一些基本的示例,其實經驗稍微豐富一點的程序員其實也能夠想象的到其底層的一個實現原理。此篇文章為Hibernate系列的第一篇,在第二節中所創建的基礎代碼會貫穿着整個系列文章,在后續的博客中筆者將不在作任何的贅述。而關於第三節的數據庫的創建會貫穿着一對多、HQL查詢、SQL查詢、QBC查詢系列篇章,故在這些相關篇章中筆者將會依然使用此處所創建的數據庫。本系列教程中所使用的數據庫為Oracle,Hibernate的版本為5.2.0。
二. 基礎代碼的創建
2.1 Session工具類
public class OracleSessionUtils { //獲取SessionFactory public static SessionFactory getSessionFactory(){ StandardServiceRegistry registry = null; SessionFactory sessionFactory = null; try{ registry = new StandardServiceRegistryBuilder().configure("hibernate-oracle.xml").build(); sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory(); }catch(Exception ex){ ex.printStackTrace(); StandardServiceRegistryBuilder.destroy(registry); } return sessionFactory; } //打開並返回一個Session public static Session openSession(){ return getSessionFactory().openSession(); } //關閉Session public static void closeSession(Session session){ if(null != session){ session.close(); } } }
2.2 基礎單元測試代碼
public class HibernateTest { private Session session; @Before public void openSession(){ session = OracleSessionUtils.openSession(); //打開會話 } @After public void closeSession(){ OracleSessionUtils.closeSession(session); } }
三. 數據庫的創建
create table CUSTOMER ( id NUMBER(10) not null, name VARCHAR2(255 CHAR), phone_number VARCHAR2(255 CHAR), primary key (ID) );
create table ORDERS ( id NUMBER(10), order_id VARCHAR2(255 CHAR), create_time TIMESTAMP(6), customer_id NUMBER(10), primary key (ID) );
四. hbm文件的方式
4.1 POJO類的創建
public class Customer { private int id; private String name; private String phoneNum; private Set<Order> orderSet; //setter and getter } public class Order { private int id; private String orderId; private Date createTime; //setter and getter }
4.2 hbm文件的創建
Customer.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.demo.hibernate.one2many.Customer" table="customer"> <id name="id" type="int"> <generator class="sequence"> <param name="sequence">cus_order_seq</param> </generator> </id> <property name="name" type="string" column="name"></property> <property name="phoneNum" type="string" column="phone_number"></property> <set name="orderSet"> <key column="customer_id"></key> <one-to-many class="com.demo.hibernate.one2many.Order"/> </set> </class> </hibernate-mapping>
Order.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.demo.hibernate.one2many.Order" table="orders"> <id name="id" type="int"> <generator class="sequence"> <param name="sequence">cus_order_seq</param> </generator> </id> <property name="orderId" column="order_id" type="string"></property> <property name="createTime" column="create_time" type="timestamp"></property> </class> </hibernate-mapping>
五.注解的方式
注解的方式已經逐漸替代了以前的XML文件配置的方式,擯棄了以往每修改一次POJO類就必須修改XML文件的繁瑣的方式。注:注解可以放在成員變量的上面,也可以放在對應的get方法上面。
Customer.java
@Entity @Table(name="customer") public class Customer { @Id @Column(name="id") @GenericGenerator(name="sequenceGenerator", strategy="sequence", parameters={@Parameter(name="sequence", value="cus_order_seq")}) @GeneratedValue(generator="sequenceGenerator") private int id; @Column(name="name") private String name; @Column(name="phone_number") private String phoneNum; @OneToMany @JoinColumn(name="customer_id") private Set<Order> orderSet; //setter and getter }
Order.java
@Entity @Table(name="orders") public class Order { @Id @Column(name="id") @GenericGenerator(name="sequenceGenerator", strategy="sequence", parameters={@Parameter(name="sequence", value="cus_order_seq")}) @GeneratedValue(generator="sequenceGenerator") private int id; @Column(name="order_id") private String orderId; @Column(name="create_time") @Type(type="timestamp") private Date createTime; //setter and getter }
六. 代碼測試
A.保存
@Test public void save(){ Transaction tx = session.beginTransaction(); Customer customer = new Customer(); customer.setName("AAAAA"); customer.setPhoneNum("334411"); Order order = new Order(); order.setCreateTime(new Date()); order.setOrderId("A"); Order order1 = new Order(); order1.setCreateTime(new Date()); order1.setOrderId("B"); Set<Order> orderSet = new HashSet<Order>(); orderSet.add(order); orderSet.add(order1); customer.setOrderSet(orderSet); session.save(customer); session.save(order); session.save(order1); tx.commit(); }
B.get查詢
@Test public void get(){ Customer customer = session.get(Customer.class, 42); System.out.println("查詢Customer的SQL已經發送"); System.out.println(customer.getPhoneNum() + "::" + customer.getName()); Set<Order> set = customer.getOrderSet(); System.out.println("查詢Order的SQL還未發送,因為延遲加載,只有當在使用Order的時候才會發送SQL"); for(Order o : set){ System.out.println(o.getOrderId() + "::" + o.getCreateTime()); } }
C.load查詢
@Test public void load(){ Customer customer = session.load(Customer.class, 42); System.out.println("查詢Customer的SQL還未發送,只有當使用的時候才會放松SQL"); System.out.println(customer.getPhoneNum() + "::" + customer.getName()); Set<Order> set = customer.getOrderSet(); System.out.println("查詢Order的SQL還未發送,因為延遲加載,只有當在使用Order的時候才會發送SQL"); for(Order o : set){ System.out.println(o.getOrderId() + "::" + o.getCreateTime()); } }
D.刪除
@Test public void delete(){ Customer customer = new Customer(); customer.setId(42); /* 如果設置了Order則會先執行更新 Order order = new Order(); order.setId(43); Order order1 = new Order(); order1.setId(44); Set<Order> orderSet = new HashSet<Order>(); orderSet.add(order); orderSet.add(order1); customer.setOrderSet(orderSet); */ Transaction tx = session.beginTransaction(); session.delete(customer); tx.commit(); }
E.更新
@Test public void update(){ Customer customer = new Customer(); customer.setId(45); //如果沒有設置Id會報錯 customer.setName("BBBNNN"); customer.setPhoneNum("990088"); Order order = new Order(); order.setId(46); //如果沒有Id則會執行插入 order.setCreateTime(new Date()); order.setOrderId("N"); Order order1 = new Order(); order1.setId(47); //如果沒有Id則會執行插入 order1.setCreateTime(new Date()); order1.setOrderId("G"); Set<Order> orderSet = new HashSet<Order>(); orderSet.add(order); orderSet.add(order1); //如果Customer中設置了Order,會先將Order表的customer_id置空,然后再更新customer_id //但是不會更新其他的數據 customer.setOrderSet(orderSet); Transaction tx = session.beginTransaction(); session.update(customer); tx.commit(); }