事务
一系列操作组成的工作单元称为事务。事务必须满足 ACID(原子性、一致性、隔离性、持久性)
事务要素 | 意义 |
---|---|
原子性Atomicity | 事务是不可分割的最小工作单元,事务内的操作要么全做,要么全不做 |
一致性Consistency | 在事务执行前数据库的数据处于正确的状态,而事务执行完成后数据库的数 据依然处于正确的状态,即数据完整性约束没有被破坏,如 A 给 B 转账,不论转账成功与否转账之后 的 A 和 B 的账户总额和转账之前是相同的。 |
隔离性Isolation | 当多个事务处于并发访问同一个数据库资源时,事务之间相互影响程度,不同 的隔离级别决定了各个事务对数据资源访问的不同行为。 |
持久性Durability | 事务一旦执行成功,它对数据库的数据的改变是不可逆的。 |
数据库并发问题:详见事务并发
事务类型
事务类型 | 作用 |
---|---|
本地事务 | 就是普通事务,能保证单台数据库上的操作的 ACID,被限定在一台数据库上 |
分布式事务 | 涉及多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事 务组成的),分布式事务旨在保证这些本地事务的所有操作的 ACID,使事务可以跨越多台数据库; JDBC 事务和 JTA 事务 |
JDBC 事务:数据库事务类型中的本地事务,通过 Connection 对象的控制来管理事务。
JTA(Java Transaction API)事务:Java EE 数据库事务规范,JTA 只提供了事务管理接口,由应用程序服务器厂商提供实现,JTA事务比 JDBC 更强大,支持分布式事务。
按 是否通过编程实现事务 分为声明式事务和编程式事务
- 编程式事务:通过编写代码来管理事务
- 声明式事务:通过注解或 XML 配置来管理事务。
Spring 事务管理
Spring 的事务管理主要包括 3 个接口:
接口名 | 作用 |
---|---|
PlatformTransactionManager | 根据 TransactionDefinition 提供的事务属性配置信息,创建事务。 |
TransactionDefinition | 封装事务的隔离级别和超时时间,是否为只读事务和事务的隔离级别和传播规则等事务属性 |
TransactionStatus | 封装了事务的具体运行状态。是否是新开启的事务,是否已经提交事务,设置当前事务为 rollback-only 等。 |
PlatformTransactionManager
PlatformTransactionManager接口, 统一处理事务相关操作,
- getTransaction(TransactionDefinition) : TransactionStatus 创建或者返回事务
- commit(TransactionStatus) : void 提交事务,如果事务状态被标识为 rollback-only,该方法执行回滚事务操作。
- rollback(TransactionStatus) : void 回滚事务,commit 方法抛出异常时,rollback 会被隐式调用。
常用的事务管理器:
DataSourceTransactionManager - 支持 JDBC,MyBatis
HibernateTransactionManager - 支持 Hibernate
TransactionDefinition
事务的隔离级别、超时时间、是否为只读事务、转播规则等事务属性。
隔离级别:解决并发事务出现的问题
- isolation_default 默认隔离级别,使用数据库默认隔离级别
- isolation_read_uncommitted
- isolation_read_committed
- isolation_repeatable_read 可重复读
- isolation_serializable 序列化
TransactionStatus
事务运行状态,是否是新开启事务,是否已经提交,设置当前事务为 rollback-only 等。
一个事务中调用其他事务方法,Spring 支持7中事务传播行为:
- 遵从当前事务
- required 如果当前存在事务,加入该事务,如果当前没有事务,新建一个事务,默认值
- supports 如果当前存在事务,就加入该事务,如果当前没有事务,就以非事务的方式运行
- mandatory 使用当前事务执行,如果没有当前事务,直接抛异常
- 不遵从当前事务
- requires_new 不管当前是否存在事务,每次都创建新的事务
- not_supported 以非事务方式执行,如果当前存在事务,暂停当前事务,并以非事务方式运行
- never 不支持事务,如果当前存在事务,抛出异常,IllegalTransactionStateException
- 嵌套事务
- nested 如果当前存在事务,在内部事务内执行,如果当前不存在事务,创建一个新的事务并执行。嵌套事务使用数据库中的保存点 savepoint 实现,嵌套事务回滚不影响外部事务,但外部事务回滚将导致嵌套回滚。DataSourceTransactionManager 默认支持,HibernateTransactionManager 默认不支持,需要手动开启。
事务配置
事务增强,好比是一个环绕增强,Spring专门为这一个特殊的环绕增强提供了命名空间,
1 | <!-- what --> |
在 Mybatis-config.xml 中可以知道,要想设置事务,必须有一个连接池,所以 DataSourceTransactionManager 有一个属性 dataSource,需要有一个连接池对象。
1 | <tx:advice id="txAdvice" transaction-manager="txManager"> |
tx:method 可配置属性如下,
事务开启在业务层,不会开在持久层和控制层
属性 | 必须 | default | 描述 |
---|---|---|---|
name | √ | 事务管理的方法,可使用通配符* | |
propagation | × | required | 事务传播规则,比如:supports、requires_new |
isolation | × | default | 事务隔离级别,default:使用数据库默认的事务隔离级别、其他级别是spring 模拟的 |
read-only | × | false | 只读事务针对查询操作 |
timeout | × | -1 | 事务超时时间(秒),-1表示底层事务系统决定 |
rollback-for | × | runtimeException | 需要回滚的异常类型,多个使用,隔开 |
no-rollback-for | × | Exception | 遇到这个类型的异常不回滚 |
CRUD 通用事务配置
1 | <bean> </bean> |
关联 pointcut 和 txAdvice,拦截哪些方法
1 | <!-- where --> |