hibernate学习(二)
hibernate 单向一对多映射
一.数据表设计
数据库名:hibernate5
数据表: ①表名:CUSTOMERS
字段: CUSTOMER_ID
CUSTOMER_NAME
②表名:ORDERS
字段:ORDER_ID
ORDER_NUMBER
CUSTOMER_ID(关联CUSTOMERS表的CUSTOMER_ID,构成单向一对多关系)
二.建立数据表对应的持久化类
1.Customers.java
1 package com.hjj.hibernate.entities.n21; 2 public class Customer { 3 private Integer customerId; 4 private String customerName; 5 6 7 public Customer(String customerName) { 8 super(); 9 this.customerName = customerName; 10 } 11 12 public Customer() { 13 super(); 14 } 15 16 public Integer getCustomerId() { 17 return customerId; 18 } 19 public void setCustomerId(Integer customerId) { 20 this.customerId = customerId; 21 } 22 public String getCustomerName() { 23 return customerName; 24 } 25 public void setCustomerName(String customerName) { 26 this.customerName = customerName; 27 } 28 29 @Override 30 public String toString() { 31 return "Customer [customerId=" + customerId + ", customerName=" + customerName + "]"; 32 } 33 }
2.Orders.java
1 package com.hjj.hibernate.entities.n21; 2 public class Order { 3 private Integer orderId; 4 private Customer customer; 5 private Integer orderNumber; 6 7 public Order() { 8 9 } 10 public Order(Customer customer, Integer orderNumber) { 11 super(); 12 this.customer = customer; 13 this.orderNumber = orderNumber; 14 } 15 public Integer getOrderId() { 16 return orderId; 17 } 18 public void setOrderId(Integer orderId) { 19 this.orderId = orderId; 20 } 21 public Customer getCustomer() { 22 return customer; 23 } 24 public void setCustomer(Customer customer) { 25 this.customer = customer; 26 } 27 public Integer getOrderNumber() { 28 return orderNumber; 29 } 30 public void setOrderNumber(Integer orderNumber) { 31 this.orderNumber = orderNumber; 32 } 33 @Override 34 public String toString() { 35 return "Order [orderId=" + orderId + ", customer=" + customer + ", orderNumber=" + orderNumber + "]"; 36 } 37 38 }
三.添加对象关系映射文件
1.Customer.hbm.xml
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2016-3-12 14:51:58 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping> 6 <class name="com.hjj.hibernate.entities.n21.Customer" table="CUSTOMERS"> 7 <id name="customerId" type="java.lang.Integer"> 8 <column name="CUSTOMER_ID" /> 9 <generator class="native" /> 10 </id> 11 <property name="customerName" type="java.lang.String"> 12 <column name="CUSTOMER_NAME" /> 13 </property> 14 </class> 15 </hibernate-mapping>
2. Order.hbm.xml
1 <?xml version="1.0"?> 2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> 4 <!-- Generated 2016-3-12 14:51:58 by Hibernate Tools 3.4.0.CR1 --> 5 <hibernate-mapping> 6 <class name="com.hjj.hibernate.entities.n21.Order" table="ORDERS"> 7 <id name="orderId" type="java.lang.Integer"> 8 <column name="ORDER_ID" /> 9 <generator class="native" /> 10 </id> 11 12 <property name="orderNumber" type="java.lang.Integer"> 13 <column name="ORDER_NUMBER" /> 14 </property> 15 16 <!-- name:属性名 所对应的 class:实体类 --> 17 <!-- name: 多这一端关联的 一 那一端的属性的名字 18 class:一的那端的类名 19 column:一的那端的数据表字段名 20 21 --> 22 <many-to-one name="customer" class="com.hjj.hibernate.entities.n21.Customer" > 23 <column name="CUSTOMER_ID" /> 24 </many-to-one> 25 </class> 26 </hibernate-mapping>
四.配置hibernate.cfg.xml文件,并且把三中的两个关系映射文件关联到到此配置文件中.
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-configuration PUBLIC 3 "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 4 "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 5 <hibernate-configuration> 6 <session-factory> 7 <property name="connection.password">000000</property> 8 <property name="connection.username">root</property> 9 <property name="connection.url">jdbc:mysql:///hibernate5</property> 10 <property name="connection.driver_class">com.mysql.jdbc.Driver</property> 11 12 <property name="dialect"> org.hibernate.dialect.MySQL5InnoDBDialect </property> 13 <property name="hbm2ddl.auto">update</property> 14 <property name="format_sql">true</property> 15 <property name="show_sql">true</property> 16 17 <!-- 指定关联的 .hbm.xml --> 18 <mapping resource="com/hjj/hibernate/entities/n21/Customer.hbm.xml"/> 19 <mapping resource="com/hjj/hibernate/entities/n21/Order.hbm.xml"/> 20 21 22 </session-factory> 23 </hibernate-configuration>
五.编写访问数据库的代码(使用单元测试类)。
1.关于注解@Test @After @Before
@Test:
@Test注解的public void方法将会被当做测试用例,JUnit每次都会创建一个新的测试实例,然后调用@Test注解方法
@Arter:
使用@After注解一个public void方法会使该方法在@Test注解方法执行后被执行
@Before
使用@Before注解一个public void 方法会使该方法在@Test注解方法被执行前执行
2. @After和@Before所做的事
1 package com.hjj.hibernate.entities.n21; 2 import org.hibernate.Session; 3 import org.hibernate.SessionFactory; 4 import org.hibernate.Transaction; 5 import org.hibernate.cfg.Configuration; 6 import org.junit.After; 7 import org.junit.Before; 8 import org.junit.Test; 9 10 public class HibernateTest { 11 private Session session ; 12 private SessionFactory sessionFactory ; 13 private Transaction transaction; 14 @Before 15 public void init(){ 16 Configuration configuration = new Configuration().configure(); 17 sessionFactory = configuration.buildSessionFactory(); 18 session = sessionFactory.openSession(); 19 transaction = session.beginTransaction(); 20 21 } 22 23 @After 24 public void destory(){ 25 transaction.commit(); 26 session.close(); 27 sessionFactory.close(); 28 } 29 }
3.@Test测试用例之save操作
①第一种save方法:先save customers关联对象(即先save一端),在save多端。
1 @Test 2 public void testSave(){ 3 4 Customer customer = new Customer(); 5 customer.setCustomerName("BB"); 6 7 Order order1 = new Order(); 8 order1.setOrderNumber(11111); 9 10 Order order2 = new Order(); 11 order2.setOrderNumber(22222); 12 //设定关联关系 13 order1.setCustomer(customer); 14 order2.setCustomer(customer); 15 16 session.save(customer); 17 session.save(order1); 18 session.save(order2); 19 20 }
控制台发送三条insert语句
Hibernate: insert into CUSTOMERS (CUSTOMER_NAME) values (?) Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID) values (?, ?) Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID) values (?, ?)
②。第二种save方法:先save order(即先save多端),在save一端。
@Test public void testSave(){ Customer customer = new Customer(); customer.setCustomerName("BB"); Order order1 = new Order(); order1.setOrderNumber(11111); Order order2 = new Order(); order2.setOrderNumber(22222); //设定关联关系 order1.setCustomer(customer); order2.setCustomer(customer); //save操作:先插入多的一端 在插入一的一端 session.save(order1); session.save(order2); session.save(customer); }
控制台会发送三条insert语句,两条update语句.
Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID) values (?, ?) Hibernate: insert into ORDERS (ORDER_NUMBER, CUSTOMER_ID) values (?, ?) Hibernate: insert into CUSTOMERS (CUSTOMER_NAME) values (?) Hibernate: update ORDERS set ORDER_NUMBER=?, CUSTOMER_ID=? where ORDER_ID=? Hibernate: update ORDERS set ORDER_NUMBER=?, CUSTOMER_ID=? where ORDER_ID=?
③两种save方法的比较,可以明显的出第二种效率不如第一种.因此应该使用第一种save方式
④以上两种操作数据库表为下:
CUSTOMERS表
ORDERS表
4.@Test测试用例之get操作
①正常编写代码
@Test public void testGet(){ Order order = (Order) session.get(Order.class, 1); System.out.println(order.getOrderNumber()); }
控制台:
Hibernate:
select
order0_.ORDER_ID as ORDER_ID1_2_0_,
order0_.ORDER_NUMBER as ORDER_NU2_2_0_,
order0_.CUSTOMER_ID as CUSTOMER3_2_0_
from
ORDERS order0_
where
order0_.ORDER_ID=?
order.getOrderNumber:11111
可以看出来这里并没有去查询order关联的customer对象。
②.当使用到的关联对象 或者 关联对象 的属性的时候才会去查询
1 @Test 2 public void testGet(){ 3 Order order = (Order) session.get(Order.class, 1); 4 System.out.println("order.getOrderNumber:"+order.getOrderNumber()); 5 Customer customer = order.getCustomer(); 6 System.out.println(customer); 7 8 }
控制台
Hibernate: select order0_.ORDER_ID as ORDER_ID1_2_0_, order0_.ORDER_NUMBER as ORDER_NU2_2_0_, order0_.CUSTOMER_ID as CUSTOMER3_2_0_ from ORDERS order0_ where order0_.ORDER_ID=? order.getOrderNumber:11111 Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ from CUSTOMERS customer0_ where customer0_.CUSTOMER_ID=? Customer [customerId=1, customerName=AAAAA]
③对于关联对象hibernate采用的是懒加载:对于 关联的对象 得到的是代理对象
1 @Test 2 public void testGet(){ 3 Order order = (Order) session.get(Order.class, 1); 4 System.out.println("order.getOrderNumber:"+order.getOrderNumber()); 5 System.out.println(order.getCustomer().getClass().getName()); 6 7 8 }
控制台:
Hibernate: select order0_.ORDER_ID as ORDER_ID1_2_0_, order0_.ORDER_NUMBER as ORDER_NU2_2_0_, order0_.CUSTOMER_ID as CUSTOMER3_2_0_ from ORDERS order0_ where order0_.ORDER_ID=? com.hjj.hibernate.entities.n21.Customer_$$_jvst392_0 //代理对象
5.@Test测试用例之update操作
1 @Test 2 public void testUpdate(){ 3 Order order = (Order) session.get(Order.class, 1); 4 order.getCustomer().setCustomerName("AAAAA"); 5 6 }
控制台打印sql语句且数据库表中字段的记录也会相应的改变:
Hibernate: select order0_.ORDER_ID as ORDER_ID1_2_0_, order0_.ORDER_NUMBER as ORDER_NU2_2_0_, order0_.CUSTOMER_ID as CUSTOMER3_2_0_ from ORDERS order0_ where order0_.ORDER_ID=? Hibernate: select customer0_.CUSTOMER_ID as CUSTOMER1_0_0_, customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_ from CUSTOMERS customer0_ where customer0_.CUSTOMER_ID=? Hibernate: update CUSTOMERS set CUSTOMER_NAME=? where CUSTOMER_ID=?
6..@Test测试用例之delete操作
1 @Test 2 public void testMany2OneDelete(){ 3 Customer customer = session.get(Customer.class,1); 4 session.delete(customer); 5 6 }
这样是会抛出异常:org.hibernate.exception.ConstraintViolationException: could not execute statement
因为有多端的对象对它还有引用。因此不能直接删除这个对象.