1 Hibernate实体的状态
1.1 状态的介绍
- 在Hibernate中实体有三种状态,瞬时态、持久态和脱管态。
- 瞬时态:Transient,session中没有缓存,数据库中没有记录,OID没有值。
- 持久态:persistent,session中有缓存,数据库中有记录,OID有值。
- 脱管态:detached,session没有缓存,数据库有记录,OID有值。
1.2 瞬时态-->持久态
- 新创建的对象,经过save或saveOrUpdate方法调用后,会变为持久态。
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); /** * 新创建的对象是瞬时态的:因为此时session中没有值,数据库中没有记录,OID没有值 */ User user = new User(); user.setUsername("xuweiwei"); /** * 经过save方法或saveOrUpdate方法后,会由瞬时态转换为持久态对象 * 因为此时session中有值,数据库中有记录,OID有值 */ session.save(user); System.out.println(user); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
1.3 持久态-->脱管态
- load方法或get方法获取的对象是持久态的,当session关闭后获取session清除后,对象就变为脱管态。
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); //get或load等方法获取的对象是持久态的 User user = session.get(User.class, 1); System.out.println(user); //调用session的clear方法或close方法的时候,对象将由持久态变为脱管态 session.clear(); user = session.get(User.class, 1); System.out.println(user); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
1.4 总结状态的转换过程
- 查询操作:get、load、createQuery、CreateCriteria等查询的都是持久态对象。
- 瞬时态对象通过save、saveOrUpdate方法之后会变为持久态对象。
- 持久态通过如下的方法可以转变为脱管态。
// 关闭session session.close(); // 清除所有 session.clear(); //将指定的POJO对象从session缓存中清除 session.evict(obj);
2 一级缓存
2.1 概念
- 一级缓存:又称为session级别的缓存。当获得一次会话(session),Hibernate在session中创建多个集合(Map),用于存放操作数据(POJO对象),为程序优化服务,如果之后需要相应的数据,Hibernate优先从session缓存中获取,如果有就使用。如果没有,就去查数据库。当session关闭后,一级缓存销毁。
2.2 证明一次缓存的存在
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); User user1 = session.get(User.class, 1); User user2 = session.get(User.class, 1); System.out.println(user1); System.out.println(user2); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
2.3 移除一级缓存
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); User user1 = session.get(User.class, 1); System.out.println(user1); session.evict(user1); User user2 = session.get(User.class, 1); System.out.println(user2); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
2.4 一级缓存的快照
- 和一级缓存的存放位置是一致的,快照区是对一级缓存的数据进行备份。保证数据库的数据和一级缓存的数据必须是一致的。如果一级缓存的数据修改了,在执行事务提交的时候,将自动刷新一级缓存,执行update语句,将一级缓存的数据更新到数据库中。
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); User user1 = session.get(User.class, 1); user1.setPassword("123456"); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
2.5 一级缓存的刷新
- 默认情况下,只有当事务进行提交的时候,才会刷新一级缓存。
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); User user1 = session.get(User.class, 1); user1.setPassword("123456"); user1.setPassword("23456"); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
- 当执行session.flush()会手动保持一级缓存和数据库一致。
- 示例:
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.User; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); User user1 = session.get(User.class, 1); user1.setPassword("1234567"); session.flush(); user1.setPassword("234567"); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
3 其他API
3.1 save和persist方法的异同
- save方法和persist都是将瞬时态对象转换为持久态对象,不同的是在调用save方法之前,设置的OID将被忽略;而persist会直接报错。
4 Hibernate的多表关系
4.1 一对多的关系配置
4.1.1 创建客户和订单的实体
- 示例:客户
package com.sunxiaping.hibernateDemo.domain; import java.util.HashSet; import java.util.Set; /** * 客户 */ public class Customer { /** * 客户的id */ private Integer id; /** * 客户名称 */ private String name; /** * 一个客户有多个订单 */ private Setorders = new HashSet (); public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set getOrders() { return orders; } public void setOrders(Set orders) { this.orders = orders; } @Override public String toString() { return "Customer{" + "id=" + id + ", name='" + name + '\'' + ", orders=" + orders + '}'; } }
- 示例:订单
package com.sunxiaping.hibernateDemo.domain; /** * 订单 */ public class Order { /** * 订单的id */ private Integer id; /** * 订单的名称 */ private String name; /** * 一个订单属于一个客户 */ private Customer customer; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Customer getCustomer() { return customer; } public void setCustomer(Customer customer) { this.customer = customer; } @Override public String toString() { return "Order{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
4.1.2 配置客户和订单的映射文件
- 示例: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 package="com.sunxiaping.hibernateDemo.domain"> <class name="Customer" table="customer" schema="hibernate" dynamic-insert="true" dynamic-update="true"> <id name="id"> <column name="id"/> <generator class="native"/> id> <property name="name"> <column name="name"/> property> <set name="orders" inverse="true"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> 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 package="com.sunxiaping.hibernateDemo.domain"> <class name="Order" table="`order`" schema="hibernate" dynamic-insert="true" dynamic-update="true"> <id name="id"> <column name="id"/> <generator class="native"/> id> <property name="name"> <column name="name"/> property> <many-to-one name="customer" column="customer_id" class="Customer">many-to-one> class> hibernate-mapping>
4.1.3 Hibernate的核心配置文件
- 示例:hibernate.cfg.xml
xml version='1.0' encoding='utf-8'?> DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <property name="connection.url"> jdbc:mysql://localhost:3306/hibernate?useUnicode=true&characterEncoding=utf-8&useSSL=false ]]> property> <property name="connection.driver_class">com.mysql.jdbc.Driverproperty> <property name="connection.username">rootproperty> <property name="connection.password">123456property> <property name="show_sql">trueproperty> <property name="format_sql">trueproperty> <property name="hbm2ddl.auto">updateproperty> <property name="dialect">org.hibernate.dialect.MySQL55Dialectproperty> <property name="connection.autocommit">trueproperty> <property name="current_session_context_class">threadproperty> <mapping resource="com/sunxiaping/hibernateDemo/domain/User.hbm.xml"/> <mapping resource="com/sunxiaping/hibernateDemo/domain/Customer.hbm.xml"/> <mapping resource="com/sunxiaping/hibernateDemo/domain/Order.hbm.xml"/> session-factory> hibernate-configuration>
4.1.4 单元测试
- 示例:保存数据
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import com.sunxiaping.hibernateDemo.domain.Order; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setName("胡歌"); Order order1 = new Order(); order1.setName("iphone X"); order1.setCustomer(customer); Order order2 = new Order(); order2.setName("iMac"); order2.setCustomer(customer); session.save(customer); session.save(order1); session.save(order2); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会话工厂 sessionFactory.close(); } }
- 示例:查询
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import com.sunxiaping.hibernateDemo.domain.Order; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import java.util.Set; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); /** * 默认情况下,如果查询orders是懒加载 */ Customer customer = session.get(Customer.class, 1); System.out.println(customer.getName()); Setorders = customer.getOrders(); System.out.println(orders); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会工厂 sessionFactory.close(); } }
- 示例:删除
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import com.sunxiaping.hibernateDemo.domain.Order; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import java.util.Set; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); /** * 默认情况下,如果客户下面有订单,是不能删除客户的,因为外键的存在 * ①将外键设置为null,然后删除客户 * ②先删除客户下面的所有订单,然后删除客户 */ Customer customer = session.get(Customer.class, 1); Setorders = customer.getOrders(); for (Order order : orders) { order.setCustomer(null); } session.delete(customer); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会工厂 sessionFactory.close(); } }
4.2 cascade级联
4.2.1 概述
- 在实际开发过程中,可能会遇到这种情况,我想删除客户,但是客户下面有订单,怎么办?
- ①将客户下面的订单的外键设置为null,然后再去删除客户。
- ②将客户下面的订单全部删除,然后再去删除客户。
- 但是上面的处理方式,太繁琐了,我能不能让Hibernate帮我,我删除客户的同时将订单也删除(实际开发中不能这么干)。
- 在一方的set标签中有一个cascade的属性,可以配置级联的策略。
4.2.2 级联保存或级联更新
- 在一方的set标签中的cascade属性上设置save-update,这样保存A或更新A的同时,会同时保存B或更新B。
- 示例:
- 没有配置cascade属性:
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 package="com.sunxiaping.hibernateDemo.domain"> <class name="Customer" table="customer" schema="hibernate" dynamic-insert="true" dynamic-update="true"> <id name="id"> <column name="id"/> <generator class="native"/> id> <property name="name"> <column name="name"/> property> <set name="orders" inverse="true"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set> class> hibernate-mapping>
<set name="orders" inverse="true"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set>
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import com.sunxiaping.hibernateDemo.domain.Order; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setName("胡歌"); Order order = new Order(); order.setName("iphone x"); order.setCustomer(customer); Order order1 = new Order(); order1.setName("IMAC"); order1.setCustomer(customer); /** * 在没有配置cascade="save-update"的时候,必须同时保存三个对象 */ session.save(customer); session.save(order); session.save(order1); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会工厂 sessionFactory.close(); } }
/** * 在没有配置cascade="save-update"的时候,必须同时保存三个对象 */ session.save(customer); session.save(order); session.save(order1);
- 配置了cascade属性
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 package="com.sunxiaping.hibernateDemo.domain"> <class name="Customer" table="customer" schema="hibernate" dynamic-insert="true" dynamic-update="true"> <id name="id"> <column name="id"/> <generator class="native"/> id> <property name="name"> <column name="name"/> property> <set name="orders" inverse="true" cascade="save-update"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set> class> hibernate-mapping>
<set name="orders" inverse="true" cascade="save-update"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set>
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import com.sunxiaping.hibernateDemo.domain.Order; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); Customer customer = new Customer(); customer.setName("胡歌"); Order order = new Order(); order.setName("iphone x"); order.setCustomer(customer); Order order1 = new Order(); order1.setName("IMAC"); order1.setCustomer(customer); customer.getOrders().add(order); customer.getOrders().add(order1); /** * 配置cascade="save-update"的时候,只需要保存客户即可 */ session.save(customer); //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会工厂 sessionFactory.close(); } }
order.setCustomer(customer); order1.setCustomer(customer); customer.getOrders().add(order); customer.getOrders().add(order1); /** * 配置cascade="save-update"的时候,只需要保存客户即可 */ session.save(customer);
4.2.3 级联删除
- 在一方的set标签的cascade属性上设置delete,这样删除A的同时,删除B。
- 示例:
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 package="com.sunxiaping.hibernateDemo.domain"> <class name="Customer" table="customer" schema="hibernate" dynamic-insert="true" dynamic-update="true"> <id name="id"> <column name="id"/> <generator class="native"/> id> <property name="name"> <column name="name"/> property> <set name="orders" inverse="true" cascade="delete"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set> class> hibernate-mapping>
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); Customer customer = session.get(Customer.class, 1); if(null != customer){ session.delete(customer); } //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会工厂 sessionFactory.close(); } }
4.2.4 孤儿删除
- 解除关系,将B删除,A存在(A是一方,B是多方)。
- 示例:
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 package="com.sunxiaping.hibernateDemo.domain"> <class name="Customer" table="customer" schema="hibernate" dynamic-insert="true" dynamic-update="true"> <id name="id"> <column name="id"/> <generator class="native"/> id> <property name="name"> <column name="name"/> property> <set name="orders" inverse="true" cascade="delete-orphan"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set> class> hibernate-mapping>
package com.sunxiaping.hibernateDemo; import com.sunxiaping.hibernateDemo.domain.Customer; import com.sunxiaping.hibernateDemo.domain.Order; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.Test; import java.util.Iterator; import java.util.Set; public class HibernateTest { @Test public void test() { //加载hibernate.cfg.xml文件 Configuration configuration = new Configuration().configure(); //创建会话创建工厂 SessionFactory sessionFactory = configuration.buildSessionFactory(); //创建会话 Session session = sessionFactory.openSession(); //开启事务 Transaction transaction = session.beginTransaction(); Customer customer = session.get(Customer.class, 1); if(null != customer){ Setorders = customer.getOrders(); if(null != orders && orders.size() != 0){ Iterator iterator = orders.iterator(); while (iterator.hasNext()){ Order order = iterator.next(); iterator.remove(); } } } //提交事务 transaction.commit(); //关闭会话 session.close(); //关闭会工厂 sessionFactory.close(); } }
4.2.5 级联组合
- 如果需要配置多项级联策略,可以使用逗号隔开
<set name="orders" inverse="true" cascade="save-update,delete,delete-orphan"> <key column="customer_id">key> <one-to-many class="Order">one-to-many> set>
- all表示save-update和delete的组合。
- all-delete-orphan表示save-update、delete和delete-orphan的组合。