Transactional注解
隔离级别
定义一个事务受其他并发事务影响程度。事务并发引发的问题。
- 脏读:一个事务读取到另一个事务修改但还未提交的数据
- 不可重复读:一个事务读取数据之后,该数据被其他事务修改,此时第一个事务读取到的事务就是错误的(强调修改)
- 幻读:一个事务读取了某些数据,没提交再读取时数据多了或者少了,类似幻觉(强调增删)
- 丢失修改:两个事务都读取了数据,其中一个事务修改之后,另一个事务也做了修改,前者的修改丢失。、
我们这里先看看@Transaction注解
//可以放在 类上 或者 方法上。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
/**
* 区别于 transactionManager属性
* 查看 transactionManager
*/
@AliasFor("transactionManager")
String value() default "";
/**
* 选定特定的 事务管理器 SpringBoot中默认不用配置 可以是beanName或者特定的值
*/
@AliasFor("value")
String transactionManager() default "";
/**
* 设置传播级别
*/
Propagation propagation() default Propagation.REQUIRED;
/**
* 设置事务隔离级别
*/
Isolation isolation() default Isolation.DEFAULT;
/**
* 事务超时
*/
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
/**
* 事务只读 默认是可以修改的 如果设置为true只能执行查询相关
*/
boolean readOnly() default false;
/**
* 指定错误回滚 当未抛出该类型的错误或者其子类的错误时 不会回滚 默认是任何错误(异常)都会回滚
*/
Class<? extends Throwable>[] rollbackFor() default {};
/**
* 略
*/
String[] rollbackForClassName() default {};
/**
* 如果配置这个 如果抛出此异常将不会回滚
*/
Class<? extends Throwable>[] noRollbackFor() default {};
/**
* 略
*/
String[] noRollbackForClassName() default {};
}
可以看到这上面我们主要关注 isolation
(事务隔离级别)和propagation
(事务传播级别)
五种隔离级别(RU、RC、RR、Serializable)
这里的隔离级别也映射了Mysql或Oracle的隔离级别。
我们先查看一下Isolation
枚举类的源码
public enum Isolation {
/**
* 使用默认的隔离级别
* 所有其他级别对应于JDBC隔离级别
* 具体隔离级别 查看 java.sql.Connection
* Mysql 默认 RR(REPEATABLE_READ)
* Oracle 默认 RC(READ_COMMITTED)
*/
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
/**
* 未提交读 什么问题都不解决
* @see java.sql.Connection#TRANSACTION_READ_UNCOMMITTED
*/
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
/**
* 提交读 解决脏读
* @see java.sql.Connection#TRANSACTION_READ_COMMITTED
*/
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
/**
* 可重复读 解决脏读和不可重复读 不解决幻读
*/
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
/**
* 串行读 解决所有的事务隔离问题
*/
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);
private final int value;
Isolation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ_UNCOMMITTED | × | × | × |
READ_COMMITTED | √ | × | × |
REPEATABLE_READ | √ | √ | × |
SERIALIZABLE | √ | √ | √ |
事务传播行为
用来描述 一个被事务传播行为修饰的方法 被 嵌套进另一个方法 时,事务如何传播。
在Spring的@Transaction中,有个重要的属性:Propagation,指的是事务方法之间发生嵌套调用时,事务的传播行为(当前调用的这个方法的事务,和当前的其他事务之间的关系)。
我们查看一下Propagation
枚举类的源码
public enum Propagation {
/**
* Support a current transaction, create a new one if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>This is the default setting of a transaction annotation.
* 外围有事务则加入形成同一个事务,外围无事务则新开启,内部事务之间相互独立
*/
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
/**
* Support a current transaction, execute non-transactionally if none exists.
* Analogous to EJB transaction attribute of the same name.
* <p>Note: For transaction managers with transaction synchronization,
* {@code SUPPORTS} is slightly different from no transaction at all,
* as it defines a transaction scope that synchronization will apply for.
* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
* will be shared for the entire specified scope. Note that this depends on
* the actual synchronization configuration of the transaction manager.
* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization
* 若外围没有事务则非事务执行,有事务则同 REQUIRED
*/
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
/**
* Support a current transaction, throw an exception if none exists.
* Analogous to EJB transaction attribute of the same name.
* 使用外围事务,若外围无事务则抛出异常
*/
MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
/**
* Create a new transaction, and suspend the current transaction if one exists.
* Analogous to the EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
* 外围有无事务都开启新事务,相互独立,且与外围事务相互独立开 如果当前有事务,就把当前的事务挂起
*/
REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
/**
* Execute non-transactionally, suspend the current transaction if one exists.
* Analogous to EJB transaction attribute of the same name.
* <p><b>NOTE:</b> Actual transaction suspension will not work out-of-the-box
* on all transaction managers. This in particular applies to
* {@link org.springframework.transaction.jta.JtaTransactionManager},
* which requires the {@code javax.transaction.TransactionManager} to be
* made available to it (which is server-specific in standard Java EE).
* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager
* 非事务执行,若外围存在事务则挂起该事务
*/
NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
/**
* Execute non-transactionally, throw an exception if a transaction exists.
* Analogous to EJB transaction attribute of the same name.
* 非事务执行,当外围有事务则抛出异常
*/
NEVER(TransactionDefinition.PROPAGATION_NEVER),
/**
* Execute within a nested transaction if a current transaction exists,
* behave like {@code REQUIRED} otherwise. There is no analogous feature in EJB.
* <p>Note: Actual creation of a nested transaction will only work on specific
* transaction managers. Out of the box, this only applies to the JDBC
* DataSourceTransactionManager. Some JTA providers might support nested
* transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
* 外围无事务,则同 REQUIRED 内部开启新事务相互独立。外围有事务,则内部事务是其子事务,主事务回滚则子事务全部回滚,子事务回滚不影响其他子事务和主事务
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) {
this.value = value;
}
public int value() {
return this.value;
}
}
总结
在我们的日常开发过程中,设计到数据安全相关的问题的时候切记要选择正确的事务隔离和事务传播,多测试,以免造成没必要的经济损失。