目录
- Hibernate的持久化类介绍
- Hibernate持久化对象的状态
- Hibernate的一级缓存
- Hibernate的事务与并发
- 线程ThreadLocal绑定Session
- Hibernate的基本查询(HQL)
1. Hibernate持久化类
1.1 持久化类
就是普通的Java实体类,这个类通过映射文件与数据库表建立关联后就成为持久化类。
1.2 持久化类编写规则
提供无参构造函数(反射)
提供标识属性,映射数据表的主键字段
所有属性提供getter、setter方法
标识属性尽量使用基本数据类型的包装类(如Integer、Long...)
2. Hibernate持久化对象的状态
状态 | 描述 |
---|---|
瞬时态(Transient Object) | 没有持久化标识ID(对象刚刚创建),没有被纳入到Session对象的管理 |
持久态(Persistent Object) | 有持久化标识ID(执行了数据库的操作,如保存或查询等),已经被纳入到Session对象的管理(持久态对象修改数据可以自动更新数据库) |
脱管态(Detached Object) | 有持久化标识ID,已经脱离了Session对象的管理 |
3. Hibernate的一级缓存
Hibernate框架提供了两种缓存:分别是一级缓存以及二级缓存,一级缓存是默认并且不可更改的,它的生命周期与session一致(session级别的缓存);二级缓存默认没有开启,需要我们手动在配置文件中添加(以后补充)是进程或集群范围内的缓存,可以在多个session中共享数据。
接下来我们编写代码,通过在同一个Session对象中进行两次查询来证明一级缓存的存在
@Test
public void twiceQueryTest()
{
Session session = HibernateUtils.getSession();
Transaction transaction = session.beginTransaction();
//通过id查询一条数据
User u1 = session.get(User.class, 1L);
User u2 = session.get(User.class, 1L);
//比较这两个对象的内存地址
System.out.println(u1 == u2);
transaction.commit();
session.close();
}
头铁的我发现SQL只执行了一次,并且这两个对象的内存地址是相等的;这就说明了一级缓存的存在;
控制Session一级缓存的方法
方法 | 描述 |
---|---|
Session.clear() | 清空缓存 |
Session.evict(Object entity) | 从缓存中清除指定的对象 |
Session.flush() | 刷出缓存, 可以强制进行从内存到数据库的同步。 |
4. Hibernate的事务与并发
4.1 事务描述
事务就是一组不可分割的原子操作,操作要么成功要么失败,最经典的例子就是转账了
4.2 事务的特性
- 原子性:事务不可分割
- 一致性:事务执行的前后数据的完整性应该保持一致
- 隔离性:一个事务执行过程中,不应该收到其他事务的干扰
- 持久性:事务一旦提交,数据永久保存到数据库中
4.3 如果不考虑事务的隔离性,可能引发的问题
- 脏读:A事务读到了B事务未提交的数据
- 不可重复读:A事务读到了B事务update更新提交的数据,导致多次查询的结果不一致
- 虚读:A事务读到了B事务插入提交的数据,导入多次查询结构不一致
4.4 Hibernate设置隔离级别
<property name="hibernate.connection.isolation">4</property>
隔离级别 | 描述 |
---|---|
1 | Read uncommitted isolation(未提交读;上面的问题都有可能出现) |
2 | Read committed isolation(已提交读;避免了脏读,其它两个问题有可能出现) |
4 | Repeatable read isolation(可重复读;避免了脏读、不可重复读,但是虚读有可能出现) |
8 | Serializable isolation(串行化;上面的问题都可以避免,但是效率较低) |
4.5 Hibernate并发之数据丢失更新
场景:两个事务同时对一条数据进行操作
解决方法(2种):
- 悲观锁
采用的是数据库提供的一种锁机制,当A事务操作数据是,会把该条数据锁起来,其它事务不能操作;只有当A事务提交后,释放锁才能进行操作。
//通过设置LockMode枚举
session.get(User.class,1L,LockMode.UPGRADE);
LockMode | 描述(待补充) |
---|---|
NONE | 默认模式 |
READ | |
UPGRADE | 已过时 |
UPGRADE_NOWAIT | |
UPGRADE_SKIPLOCKED | |
WRITE | |
FORCE | 已过时 |
OPTIMISTIC | |
OPTIMISTIC_FORCE_INCREMENT | |
PESSIMISTIC_READ | |
PESSIMISTIC_WRITE | |
PESSIMISTIC_FORCE_INCREMENT |
- 乐观锁
采用版本号的机制来解决问题,会给表添加一个字段
verision
,默认值为0,当A事务在操作该条数据提交时,首先会检查版本号,如果发现版本号的值相同时才可以提交事务,并且让version+1;当B事务也提交时,和前面说的一样,发现version变了,程序就会报错。
step1.在对应的JavaBean中添加一个属性,例如
private Integer version;
...
getter setter
step2.在实体类映射文件(User.hbm.xml)中提供<version>标签
<hibernate-mapping>
<class name="com.example.hibernate.User" table="t_user">
<id name="uid" column="uid">
<generator class="native"/>
</id>
<version name="version"/>
...
</class>
</hibernate-mapping>
5. 线程ThreadLocal绑定Session
在开发中我们一般在
Service
中处理业务(然后Service
调用Dao
层处理数据库操作),开启Session
的事务提交;但是我们数据库的操作是放在Dao
层的,这个时候Dao层想要使用Service
层的Session
,只能通过方法将Session
作为实参传递或者使用ThreadLocal
保存在线程中;Hibernate也帮我们提供了ThreadLocal
的方式
step1. 在hibernate.cfg.xml
中配置(到处都是配置,头铁)
<property name="hibernate.current_session_context_class">thread</property>
step2. 使用SessionFactory
的getCurrentSeesion
方法获取Session
对象,需要注意的是该Session
对象线程结束会自动关闭,不需要我们手动调用Session
的close
方法。
...
//创建session对象
Session session = factory.getCurrentSession();
...
6. Hibernate的基本查询(HQL)
6.1 使用Query
查询接口
...
//查询所有记录
Query query = session.createQuery("from User");
List<User> list = query.list();
System.out.println(list);
//条件查询,使用?占位符
Query query = session.createQuery("from User where uname = ?");
query.setString(0,"许渺");
List<User> list = query.list();
System.out.println(list);
//条件查询,使用:占位符
Query query = session.createQuery("from User where uname = :name");
query.setString("name","许渺");
List<User> list = query.list();
System.out.println(list);
...
6.2 使用Criteria查询接口(适合做条件查询)
...
//查询所有
Criteria criteria = session.createCriteria(User.class);
List<User> list = criteria.list();
System.out.println(list);
//条件查询
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name", "许渺"));
List<User> list = criteria.list();
System.out.println(list);
...