事务的四个特性(ACID):
- 原子性(Atomicity)
事务是数据库的逻辑工作单元,事务中的操作要么都成功要么都失败 - 一致性(Consistency)
事务执行的结果必须是是数据库从一个一致性状态到另一个一致性状态。例如当一个事务执行成功了,那么这可以说现在数据库是处于一致性状态。如果当中发生错误,这些未完成的事务对数据库所做的修改有一部分已经写入了物理数据库,那么当前数据库就处于不一致状态 - 隔离性(Isolation)
一个事务在执行的过程中,不能影响到其他事务的执行。寄一个事务内部的操作,对于其他事务是隔离的,各个并发执行的数据之间不干扰。 - 持续性(Durability)
假如某个事务一旦提交,那么它对数据的修改就是永久性的。就算物理数据库宕机之类的也不会对数据产生影响。
spring事务传播特性
事务传播行为就是在多个事务方法中互相调用时候,这些事务如何在方法之间传播。
- propagation.required:如果当前没有事务,则新建一个事务,如果有的话直接加入,这是开发当中最常见的一个
- propagation.REQUIRES_NEW:无论当前是否有事务,都会开启事务
- propagayion_support:支持当前事务,如果当前没有事务,则以非事务的形式运行
- propagation.NOT_SUPPORT:自身不开启事务,在食物范围内使用则挂起事务,运行完毕后恢复事务
- propagation.MANDATORY:自身不开启事务,必须在事务环境中使用,否则报错
- propagation.NEVER:自身不开启事务,在事务范围内使用的话报错
- propagation.NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
注:在spring中默认的事务传播行为required
@Transactional注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
如源码所示,该注解一共有如下几个参数:
参数 | 含义 |
---|---|
propagation | 事务传播机制,默认为Propagation.REQUIRED |
isolation | 事务隔离级别 |
readOnly | 事务读写性,默认为false |
timeout | 超时时间,以秒为单位 |
rollbackFor | 最好设置为Exception.class,否则只有当有error的时候才会滚 |
isolation事务隔离级别:
- Isolation.DEFAULT:使用各个数据库默认的隔离级别【默认】
- Isolation.READ_UNCOMMITTED:读取未提交数据(会出现脏读, 不可重复读)(基本不使用)
- Isolation.READ_COMMITTED:读取已提交数据(会出现不可重复读和幻读)
- Isolation.REPEATABLE_READ:可重复读(会出现幻读)
- Isolation.SERIALIZABLE:串行化
在这里,简单解释下什么是“脏读”,“不可重复读”,“幻读”:
- 脏读:一个事务读取到另一个事务未提交的数据
- 不可重复读:同一事务中,多次读取到同一数据返回的结果不同。意思就是说,后续读取可以读到另一个事务已提交的数据。相反,在“可重复读”的时候,同一事物多次读取数据是,能够保证所读数据一样,也就是说能够保证数据多次读取结果一样,不会读取到别的事务提交的更新数据。
- 幻读:一个事务读到另一个事务已提交的insert数据
注解失效场景:
4. 用在了非public修饰的方法上
5. 注解属性 propagation 设置错误
6. rollbackFor设置问题
7. 在同一个类方法中调用,导致失效;开发中避免不了会对同一个类里面的方法调用,比如:有一个类Test,它的一个方法A,A再调用本类的方法B(不论方法B是用public还是private修饰),但方法A没有声明注解事务,而B方法有。则外部调用方法A之后,方法B的事务是不会起作用的
8. 异常被 catch 处理了,导致 @Transactional 失效
9. 数据库引擎不支持事务:常用的MySQL数据库默认使用支持事务的Innodb引擎。一旦数据库引擎切换成不支持事务的MyIsam,那事务就从根本上失效了。
思考:事务仅对主线程有效(ThreadLocal),多线程时如何处理?