所谓的事务就是指逻辑上的一组操作,这个操作要么全都成功,要么全都失败。
1. 事务的特性
事务特性 | 说明 |
---|---|
原子性 | 事务的逻辑操作是一个单位,不可被分割。 |
一致性 | 事务的执行前后,数据完整性要保持一致。 |
隔离性 | 一个事务在执行的过程中不受到其他事务的干扰。 |
持久性 | 一旦事务结束,数据就永久保存数据库。 |
2.并发操作引发的读问题
- 脏读
所谓的脏读就是指一个事务读到另一个事务未提交的数据。 - 不可重复读
所谓的不可重复读就是指一个事务读到另一个已经提交数据(update),导致查询结果不一样。 - 虚读
所谓的虚读就是一个事务读到另一个事务已经提交的数据(insert),导致查询结果不一样。
解决方法:设置事务的隔离级别,然后在hibernate中设置事务的隔离级别。
//在核心配置文件中设置,X的取值为 1、2、4、8(对应隔离级别)
<property name="hibernate.connection.isolation">
X
</property>
隔离级别 | 隔离级别名称 | 作用 |
---|---|---|
1 | Read uncommitted isolation(未提交读) | 以上问题都不能解决 |
2 | Read committed isolation(已提交读) | 只能避免脏读 |
4 | Repeatable read isolation(重复读) | 能够避免脏读和不可重复读 |
8 | Serializable isolation(串行) | 能够解决以上三种问题 |
3. 并发操作引发的写问题
并发操作的时候,很经常会引发丢失更新。为了避免这一情况,解决的方法有乐观锁和悲观锁两种机制。
- 悲观锁(排它锁)
悲观锁又称之为排它锁,这是数据库自带的一种锁机制,它解决丢失更新的方法是在操作的时候获取锁,在操作完成后释放锁,在操作过程中,别的事务无法获取到锁。简而言之就是:A事务在进行更新操作的时候,B事务无法进行更新操作。
//在获取Session后,在事务上设置悲观锁
Customer customer = (Customer) session.get(Customer.class, 3, LockMode.UPGRADE);
- 乐观锁
所谓的乐观锁是在数据库增加某一个字段(Integer类型),以这个字段作为标识,在进行更新的时候进行对比字段是否相同,如果不相同,更新就失败了。如果相同,则提交事务,并且在字段+1
//找到映射文件,在映射文件中将这个字段进行设置,比如Customer中的ver字段作为标识,那么在Customer中进行一下配置
//在class标签下,进行设置version标签
<version name="ver" />
4. session管理
我们在操作事务的时候,经常会遇见两个小事务组成的一个个事务。如果这两个小事务使用的session不是同一个的话,会导致回滚的时候,只有一个小事务回滚。这就要求我们用的session必须是同一个。
//在核心配置文件中设置,在标签hibernate-configuration下的标签session-factory下的子标签property中进行如下设置
<!-- 使用当前线程中的session -->
<property name="hibernate.current_session_context_class">
thread
</property>
//如果没有在核心文件中配置session管理,那么以下两个session是不相同的:
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();
//结果为false,两个session不是同一个
session1 == session2
//如果在核心配置文件中设置了session管理,那么以下两个session就是相同的。
Session session1 = sessionFactory.getCurrentSession();
Session session2 = sessionFactory.getCurrentSession();
//结果为true,两个session是同一个
session1 == session2
5. 本地线程session过程详解
<1>绑定线程
当一个线程(threadA)第一次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法会创建一个新的 Session(sessionA) 对象, 把该对象与 threadA 绑定, 并将 sessionA 返回。
<2>返回线程session
当 threadA 再次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法将返回 sessionA 对象
<3>session提交事务
当 threadA 提交 sessionA 对象关联的事务时, Hibernate 会自动清理 sessionA 对象的缓存, 然后提交事务, 关闭 sessionA 对象. 当 threadA 撤销 sessionA 对象关联的事务时, 也会自动关闭 sessionA 对象
<<4>提交后再使用线程session的情况
若 threadA 再次调用 SessionFactory 对象的 getCurrentSession() 方法时, 该方法会又创建一个新的 Session(sessionB) 对象, 把该对象与 threadB绑定, 并将 sessionB 返回
特别注意:当前线程中的session不需要进行关闭,线程结束后自动关闭!!!