1 事务回顾
(1) 什么是事务:
事务是逻辑上的一组操作, 组成这组操作的各个逻辑单元, 要么一起成功, 要么一起失败
(2) 事务特性 (ACID)
原子性 : 强调事务的不可分割
一致性 : 事务的执行的前后数据的完整性保持一致
隔离性 : 一个事务执行的过程中, 不应该受到其他事务的干扰
持久性 : 事务一旦结束, 数据就持久到数据库
(3) 事务并发安全性问题
脏读 : 一个事务读到了另一个事务的未提交的数据
不可重复读 : 一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致
幻读 : 一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致
(4) 事务隔离级别
未提交读 : 脏读, 不可重复读, 幻读都有可能发生
已提交读 : 避免脏读, 但是不可重复读和幻读有可能发生
可重复读 : 避免脏读和不可重复读, 但是幻读有可能发生
串行化 : 避免以上所有读问题
(5) 常见数据库默认事务隔离级别
MySQL: 可重复读
Oracle: 读已提交
2Spring 事务管理
(1) 基本事务操作
打开事务
提交事务
回滚事务
(2) 事务操作对象
Spring 事务管理中提供了 PlatformTransactionManager 接口操作事务, 其中最为核心的对象是 TransactionManager 对象
(3)Spring 事务隔离级别
读未提交
读已提交
可重复读
串行化
(4)Spring 事务传播行为
保证同一个事务中
PROPAGATION_REQUIRED : 支持当前事务, 如果不存在 就新建一个 (默认)
PROPAGATION_SUPPORTS : 支持当前事务, 如果不存在, 就不使用事务
PROPAGATION_MANDATORY : 支持当前事务, 如果不存在, 抛出异常
保证不在同一个事务中
PROPAGATION_REQUIRES_NEW : 如果有事务存在, 挂起当前事务, 创建一个新的事务
PROPAGATION_NOT_SUPPORTED : 以非事务方式运行, 如果有事务存在, 挂起当前事务
PROPAGATION_NEVER : 以非事务方式运行, 如果有事务存在, 抛出异常
PROPAGATION_NESTED : 如果当前事务存在, 则嵌套事务执行
3Spring 事务管理方式
(1) 编码式
将核心事务管理器配置到 Spring 容器
- <!-- 事务核心管理器, 封装了所有事务操作. 依赖于连接池 -->
- <bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
- <property name="dataSource" ref="dataSource" ></property>
- </bean>
配置 TransactionTemplate 模板
- <!-- 事务模板对象 -->
- <bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" >
- <property name="transactionManager" ref="transactionManager" ></property>
- </bean>
将事务模板注入 Service
- <!-- 将 demoDao 和事务模板注入 Service-->
- <bean name="demoService" class="com.spring.service.demoServiceImpl" >
- <property name="dm" ref="demoDao" ></property>
- <property name="tt" ref="transactionTemplate" ></property>
- </bean>
在 Service 中调用模板
(2)xml 配置方式
导入所需要的 jar 包和约束
配置事务通知
- <!-- 配置事务通知 -->
- <tx:advice id="txAdvice" transaction-manager="transactionManager" >
- <tx:attributes>
- <!-- 以方法为单位, 指定方法应用什么事务属性
- isolation: 隔离级别
- propagation: 传播行为
- read-only: 是否只读
- -->
- <tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- <tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- <tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- <tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- <tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- <tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- <tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
- <tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" />
- <tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" />
- </tx:attributes>
- </tx:advice>
将通知织入目标
- <!-- 配置织入 -->
- <aop:config >
- <!-- 配置切点表达式 -->
- <aop:pointcut expression="execution(*com.spring.service.*ServiceImpl.*(..))" id="txPc"/>
- <!-- 配置切面 : 通知 + 切点
- advice-ref: 通知的名称
- pointcut-ref: 切点的名称
- -->
- <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
- </aop:config>
(3) 注解配置方式
导入所需要的 jar 包和约束
开启注解管理事务
- <!-- 开启使用注解管理事务 -->
- <tx:annotation-driven/>
在具体业务中使用注解
来源: https://juejin.im/post/5a9ac83e6fb9a028d936a005