1 事务的理解
事务
:事务它是一组逻辑上操作,这一组逻辑操作要么全部执行,要么就都不执行。
1.1 事务的特性
事务有四个特性:原子性(atomicity)、一致性(consistency)、隔离型(isolation)、持久性(durability);简称为事务的ACID特性。
-
原子性:事务时最小的执行单元,即一个事务不能再分割成更小的执行单位了。
-
一致性:一个事物执行后,会使得数据库从一种正确的状态转变到另外一种状态。
-
隔离性:多个事务并发执行的时候,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的。
-
持久性:一个事物被提交后,他对数据库中数据的改变是持久的,及时数据库发生了故障,也不应该对其有任何影响。
1.2 事务并发带来的问题
事务高并发状态,经常会操作相同的数据来完成任务(多个事务对统一数据进行操作),这个时候就可能出现以下几类问题:
-
脏读:当一个事务访问数据库数据的时候,访问到了另一个正在访问该数据的事务修改了但还没提交的数据,假如修改数据的事务修改失败回滚了,那当前事务读到的这个数据就是脏数据脏,因而说是脏读。
-
丢失修改:指在一个事务读取一个数据的时候,另外一个事务访问了该数据,第一个事务对这个数据进行了修改后,第二个事务也修改了该数据,那么第一个数据修改的结果就被覆盖丢失了,因此称丢失修改。
-
不可重复读:指在一个事务内多次访问同一个数据的时候,此时该事务还没有结束,另一个事务也访问了该数据,并修改了数据提交了事务,那么,第一个事务在前后两个访问读取到的数据就不一致了,这种情况就是不可重复读。
-
幻读:幻度与不可重复读类似,它发生在一个事务T1读取了几行数据,接着另一事务T2插入了一些数据,而随后在第一个事务T1在查询的过程中就会发现多了些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
不可重复度和幻读的区别:
不可重复读的重点是修改,而幻读的重点在于新增或删除。
1.3 事务的隔离级别
事务的隔离级别主要有以下四种,read uncommitted隔离级别最低,serializable隔离级别最高。下表中“是”表示会出现该情况,“否”表示不会出现该情况。
级别 | 名字 | 隔离级别 | 脏读 | 不可重复度 | 幻读 |
---|---|---|---|---|---|
1 | 读未提交 | read uncommitted | 是 | 是 | 是 |
2 | 读已提交 | read committed | 否 | 是 | 是 |
3 | 可重复读 | repeatable read | 否 | 否 | 是 |
4 | 串行化 | serializable | 否 | 否 | 否 |
当然,事务的隔离级别越高,数据访问就越安全越不会出错,但是隔离级别越高,数据库的操作性能就越差。
2 Spring事务管理
2.1 Spring事务管理的一组API
-
PlatformTransactionManager:平台事务管理器,真正管理事务的对象。
-
TransactionDefinition:事务定义信息。可以定义事务的隔离级别、传播行为、超时行为,是否只读。
-
TransactionStatus:事务的状态:记录事务的状态。
平台事务管理根据事务定义的信息进行事务的管理,事务管理产生的过程就记录在事务的状态里。
2.2 Spring中事务的传播行为
保证在同一个事务中:
- PROPAGATION_REQUIRED:支持当前事务,如果不存在 就新建一个(默认)。
- PROPAGATION_SUPPORTS:支持当前事务,如果不存在,就不使用事务。
- PROPAGATION_MANDATORY:支持当前事务,如果不存在,抛出异常。
保证没有在同一个事物中:
- PROPAGATION_REQUIRES_NEW:如果有事务存在,挂起当前事务,创建一个新的事务。
- PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务。
- PROPAGATION_NEVER:以非事务方式运行,如果有事务存在,抛出异常。
- PROPAGATION_NESTED:如果当前事务存在,则嵌套事务执行。
2.3 编码式实现事务管理
此处指写出核心的配置
<!-- 配置数据源dataSource(代码省略) -->
<!-- 将核心事务管理器配置到Spring容器 封装了所有书屋的操作,依赖于连接池-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 配置事务管理模板对象 -->
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
<!-- 将事务模板注入到Service对象(代码省略) -->
2.3 Spring事务管理注解
首先在配置文件中加入注解识别配置:
<tx:annotation-driven transaction-manager="transactionManager"/>
在配置文件中注解标识识别后就可以用@Transaction注解来表示使用事务管理的的类或者方法了。
- @Transactional注解,它可以作用于接口、接口方法、类和类的方法上,当做用于类上时,该类的所有public方法都有该类型的事务属性,可被方法级事务覆盖。
注意:@Transactional注解应该被应用到public方法上,这是由AOP的本质决定的,如果应用在protected、private的方法上,事务将被忽略。