Hibernate事务操作及session与本地线程绑定
事务相关概念
1 什么是事务
事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。
事务的结束有两种,当事务中的所以步骤全部成功执行时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作。
2 事务特性
事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。
(1)、原子性
事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做
(2)、一致性
事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
(3)、隔离性
一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
(4) 、持续性
也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
3 不考虑隔离性产生问题
(1)脏读:是指一个事务读取了另一个事务没有提交的数据。
假如A和B各自有100元钱,A向B转了100元钱,执行update account set money=money+100 while name=‘b’; update account set money=money-100 while name=‘a’;当第一条执行完,第二条还没执行,B查询自己的账户,就会发现自己的账户多了100元,如果此时A再回滚自己的操作,那么B之后再查询自己的账户,就会发现自己的钱和之前并没有变化,还是100
(2)不可重复读:在一个事务内读取表中的某一行数据,多次读取结果不相同。
还是上面那个例子,转账之前,银行查询A的账户是100元钱,A向B转了100之后,银行 对应上面两个sql语句并且已经提交,又查询A账户,发现是0元。这就导致了两次查询结果不相同。
注意:不可重复读有时候是正确的,就像这种情况,正是实际情况需要的,然而有时,不可重复读是不正确的,比如对某个地区统计GDP,两次查询结果不一样,该怎么报道呢?所以这种情况又是错误的。
不可重复读和脏读的区别,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已经提交的数据。
(3)虚读:是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
假如一个人存款100元没有提交,这时银行做报表统计所有用户的总额为600元,然后这个人提交了这时银行再统计发现账户为700元了,这就是虚读。
4 设置事务隔离级别
事务的隔离级别从低到高有:
Read Uncommitted:最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
Read Committed:只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。
Repeated Read:在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读。
Serialization:事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。
通常,在工程实践中,为了性能的考虑会对隔离性进行折中。
mysql默认隔离级别 repeatable read
Hibernate事务代码规范写法
代码结构
try { //开启事务 //提交事务 }catch() { //回滚事务 }finally { //关闭 }
@Test void testName() throws Exception { Session session = null; Transaction tx = null; try { session= HibernateUtils.openSession(); tx = session.beginTransaction(); User user = new User(); user.setUsername("aad阳"); user.setPassword("pdass"); user.setAddress("adssd"); //运行到此时会出错,catch异常,事务回滚 int i = 10/0; session.save(user); tx.commit(); } catch (Exception e) { e.printStackTrace(); tx.rollback(); } finally { session.close(); } }
Hibernate绑定session
1 session类似于jdbc的connection,之前web阶段学过 ThreadLocal
2 帮实现与本地线程绑定session
3 获取与本地线程session
(1)在hibernate核心配置文件中配置(hibernate.cfg.xml)
<!-- 与本地线程绑定 --> <property name="hibernate.current_session_context_class">thread</property>
(2)调用sessionFactory里面的方法得到
public static Session getSessionObject() { return sessionFactory.getCurrentSession(); }
4 获取与本地线程绑定session时候,关闭session报错,不需要手动关闭了