本文共 4078 字,大约阅读时间需要 13 分钟。
在数据库操作中,一项事务(Transaction)是由一条或多条操作数据库的SQL语句组成的一个不可分割的工作单元。当事务中的所有操作都正常完成时,整个事务才能被提交到数据库中,如果有一项操作没有完成,则整个事务会被回滚。
其实事务总结起来理解为:逻辑上的一组操作,组成这组操作的各个单元,要么一起成功,要么一起失败。事务由很严格的定义,需要同时满足四个特性,即原子性、一致性、隔离性、持久性。这四个特性通常称之为ACID特性,具体如下:
在实际应用过程中,数据库是要被多个用户所共同访问的。在多个事务同时使用相同的数据时,可能会发生并发的问题,具体如下:
为了避免事务并发问题的发生,在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同。
隔离级别 | 含义 |
---|---|
READ_UNCOMMITTED | 允许读取还未提交的改变了的数据。可能导致脏、幻、不可重复读。 |
READ_COMMITTED | 允许在并发事务已经提交后读取、可防止脏读,但幻读和不可重复读仍可发生。 |
REPEATABLE_READ | 对相同字段的多次读取是一致的,除非数据被事务本身改变。可防止脏、不可重复读,但幻读然可能发生。 |
SERIALIZABLE | 完全服从ACID的隔离级别,确保不发生脏、幻、不可重复读。这在所有的隔离级别中是最慢的,它是典型的通过完全锁定在事务中设计的数据表来完成的。 |
事务的隔离级,是由数据库提供的,并不是所有数据库都支持四种隔离级别。
在Hibernate中,可以通过代码来操作管理事务,如通过“Transaction tx = session.beginTransaction();” 开启一个事务:持久化操作后,通过“tx.commit();” 提交事务;如果事务出现异常,又通过“tx.rollback();” 操作来撤销事务(事务回滚)。
除了在代码中对事务开启,提交和回滚操作外,还可以在Hibernate的配置文件中对事务进行配置。配置文件中,可以设置事务的隔离级别。具体的配置方法是在hibernate.cfg.xml 文件中的 标签元素中进行的。如下:
4
我们在真正进行事务管理的时候,需要考虑事务的应用场景,也就是说我们的事务控制不应该是在DAO层实现的,应该在Service层实现,并且在Service中调用多个DAO实现一个业务逻辑的操作。
具体操作如下显示:其实使用第二种方式肯定是最优方案,那么具体的实现已经不用我们来完成了,Hibernate的内部已经帮我们将这个事情做完了。我们只需要完成一段配置即可。
Hibernate5 中自身提供了三种管理Session对象的方法:
在hibernate.cfg.xml 中进行如下配置:
thread
Hibernate提供sessionFactory.getCurrentSession() 创建一个session 和ThreadLocal 绑定方法。
书写一个HibernateUtils工具类:
package pers.zhang.utils;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;public class HibernateUtils { private static SessionFactory sf; static{ //1 创建,调用空参构造 Configuration conf = new Configuration().configure(); //2 根据配置信息,创建 SessionFactory对象 sf = conf.buildSessionFactory(); } //获得session => 获得全新session public static Session openSession(){ //3 获得session Session session = sf.openSession(); return session; } //获得session => 获得与线程绑定的session public static Session getCurrentSession(){ //3 获得session Session session = sf.getCurrentSession(); return session; } }
而且Hibernate中提供的这个与线程绑定的session可以不用关闭,当线程执行结束后,就会自动关闭了。
测试方法:
package pers.zhang.test;import org.hibernate.Session;import org.junit.Test;import pers.zhang.utils.HibernateUtils;//测试getCurrentSessionpublic class Demo { @Test //返回同一个与线程绑定的session public void fun1(){ Session session1 = HibernateUtils.getCurrentSession(); Session session2 = HibernateUtils.getCurrentSession(); System.out.println(session1==session2);//true } @Test //返回不同的session public void fun2(){ Session session1 = HibernateUtils.openSession(); Session session2 = HibernateUtils.openSession(); System.out.println(session1==session2);//false } }
运行JUnit测试输出:
truefalse
转载地址:http://fjsqb.baihongyu.com/