事务的特征以及Hibernate事务
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(atomicity):一个事务是一个不可分割的工作单位,事务中包括的诸多操作要么都做,要么都不做。
一致性(consistency):事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation):一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability):持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。
Hibernate事务
Hibernate封装了JDBC和JTA事务,应用程序可以绕过Hibernate API,直接通过JDBC和JTA的API来声明事务。其中,JTA可以用来处理分布式事务。
应用程序通过Hibernate API声明事务时,必须先获得一个Session对象,每个Session对象都包含一个数据库连接。
过程示例:业务逻辑层->从SessionFactory中获取一个Session->Session开启事务->对数据库进行操作->Transaction提交->Session关闭
事务的并发
对于同时运行的多个事务,当这些事务访问数据库中的相同数据时,如果没有采取必要的隔离机制,就会导致各种并发问题。
脏读:一个事务读到另一个事务未提交的事务
不可重复读:一个事务运行期间两次读取相同的数据但是内容不一致,原因是一个事务对数据进行了更新并提交。可理解为一个事务读取到另一个事务更新并提价的数据。
虚读:一个事务运行期间两次读取相同统计数据但是内容不一致,原因是两次读取期间有其他事务执行了插入或删除符合统计条件的数据并提交。可理解为一个事务读取到另一个事务已经提交的新插入或删除的数据。
第一类丢失更新:撤销一个事务时,把其他事务已经提交的更新数据覆盖,数据恢复到撤销事务的数据原始状态。
第二类丢失更新:这是不可重复读的特例,一个事务覆盖另一个事务已经提交的更新数据。
事务的隔离级别
Read Uncommited(读未提交数据,级别:1)
一个事务在执行过程中可以看到其他事务没有提交的新插入的记录,而且还能看到其他事务没有提交的对已有记录的更新。
Read Commited(读已提交数据,级别:2)
一个事务在执行过程中可以看到其他事务已经提交的新插入的记录,而且还能看到其他事务已经提交的对已有记录的更新。
Repeatable Read(可重复读,级别:4)
一个事务在执行过程中可以看到其他事务已经提交的新插入的数据,但是不能看到其他事务已经提交的对已有记录的更新。
Serializable(串行化,级别8)
一个事务在执行过程中完全看不到其他事务对数据库所做的操作
- 当两个事务同时操作相同数据库时,若第一个事务已经在访问数据库,第二个事务只能停下来等待,必须等待第一个事务结束后才能恢复运行
各种隔离级别避免的并发问题
隔离级别 | 是否出现脏读 | 是否出现不可重复读 | 是否出现虚读 | 是否出现第一类丢失更新 | 是否出现第一类丢失更新 |
---|---|---|---|---|---|
Read Uncommited | 是 | 是 | 是 | 是 | 是 |
Read Commited | 否 | 是 | 是 | 否 | 是 |
Repeatable Read | 否 | 否 | 是 | 否 | 否 |
Serializable | 否 | 否 | 否 | 否 | 否 |
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能影响也越大。
对大多数应用程序,可以优先考虑把数据库系统的隔离级别设置为 Read Commit,它能够避免脏读,而且还具有良好的并发性能。
配置
我们在核心配置文件中设置事务的隔离级别
<session-factory>
......
<property name="hibernate.connection.isolation">2</property>
......
</session-factory>