事物
1 定义
事务(Transaction)是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都执行,
要么都不执行,它是一个不可分割的工作单位。
1.1 特性
事务是必须满足4个条件(ACID)。
原子性(Consistency):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
一致性(Consistency):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
隔离性(Isolation):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
持久性(Durability):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
1.2 脏读、重复读、幻读
脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
不可重复读 :是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的,因此称为是不可重复读。
幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样。
1.3 隔离级别
TransactionDefinition.ISOLATION_DEFAULT:这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
TransactionDefinition.ISOLATION_READ_UNCOMMITTED:该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别。
TransactionDefinition.ISOLATION_READ_COMMITTED:该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值。(锁定正在读取的行)
TransactionDefinition.ISOLATION_REPEATABLE_READ:该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读。(锁定读取的所有行)
TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。(锁表)
2 Spring事物
spring支持编程式事务管理和声明式事务管理两种方式。编程式事务管理使用TransactionTemplate或者直接使用底层的PlatformTransactionManager。
2.1 声明式注解
@Transactional 注解的属性信息
参数 | 说明 |
---|---|
name | 名称 |
propagation | 事务的传播行为,默认值为 REQUIRED |
isolation | 事务的传播行为,默认值为 REQUIRED |
timeout | 事务的传播行为,默认值为 REQUIRED |
read-only | 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。 |
rollback-for | 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。 |
no-rollback- for | 抛出 no-rollback-for 指定的异常类型,不回滚事务。 |
2.1.1 声明式注解原理
在应用系统调用声明@Transactional 的目标方法时,Spring Framework 默认使用 AOP 代理,
在代码运行时生成一个代理对象,根据@Transactional 的属性配置信息,这个代理对象决定该声明@Transactional
的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,
会在在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑, 最后根据执行情况是否出现异常,
利用抽象事务管理器AbstractPlatformTransactionManager 操作数据源 DataSource 提交或回滚事务。
事务管理的框架是由抽象事务管理器 AbstractPlatformTransactionManager 来提供的,而具体的底层事务处理实现,
由 PlatformTransactionManager 的具体实现类来实现,如事务管理器 DataSourceTransactionManager。
不同的事务管理器管理不同的数据资源 DataSource,比如 DataSourceTransactionManager 管理 JDBC 的 Connection。
2.2编程式事物
@Autowired
private PlatformTransactionManager transactionManager;
DefaultTransactionDefinition defaultTransaction = new DefaultTransactionAttribute();
defaultTransaction.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
defaultTransaction.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
TransactionStatus transactionStatus = transactionManager.getTransaction(defaultTransaction);
try {
//dao 操作
transactionManager.commit(transactionStatus);
} catch (Exception ex) {
transactionManager.rollback(transactionStatus);
log.warn("[事物执行失败], ex:{}", ex);
return false;
}