使用事务
数据库的事务是常见的,相关知识有:事务的特性与隔离级别。网上很多介绍的,本文不展开。
实际开发中为了减少使用try{}catch{} 捕获异常,专注于业务,更加常见的做法是使用spring的注解。对于声明式事务,是使 用@Transactional 进行标注的,就是告诉spring什么地方启用数据库事务功能。底层想关的参数与传播级别、超时时间、只读等比较好理解,单独整理下复杂一点的事务传播级别。
如果都没有发生异常, Spring数据库拦截器就会帮助我们提交事务,如果发生异常,就要判断 一 次事务定义器内的配置 ,如 果事务定义器己经约定了该类型的异常不回 段事务就提交事务 , 如果没有任何配置或者不是配置不回滚事务的异常,则会回滚事务,并且将异 常抛出 , 这步也是由事务拦截器完成的,这些不需要我们干预。
那么遇到问题:比如serviceA 方法调用了 serviceB 方法,但两个方法都有事务,这个时候如果 serviceB 方法异常,是让 serviceB 方法提交,还是两个一起回滚,或者serviceB 已经正常执行完,但 serviceA 异常,是否需要回滚 serviceB 的数据。
传播级别
在 Spring事务机制中对数据库存在 7种传播行为,它是通过枚举类 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,
* PROPAGATION_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
*/
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 it 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 it 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 PROPAGATION_REQUIRED else. 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 when working on a JDBC 3.0 driver.
* Some JTA providers might support nested transactions as well.
* @see org.springframework.jdbc.datasource.DataSourceTransactionManager
*/
NESTED(TransactionDefinition.PROPAGATION_NESTED);
private final int value;
Propagation(int value) { this.value = value; }
public int value() { return this.value; }
}
常用的有3种:
PROPAGATION_REQUIRED (默认)
- 支持当前事务,如果当前没有事务,则新建事务
- 如果当前存在事务,则加入当前事务,合并成一个事务
这种情况下B异常,就会导致整体回滚。
REQUIRES_NEW
- 新建事务,如果当前存在事务,则把当前事务挂起
- 这个方法会独立提交事务,不受调用者的事务影响,父级异常,它也是正常提交
NESTED
- 如果当前存在事务,它将会成为父级事务的一个子事务,方法结束后并没有提交,只有等父事务结束才提交
- 如果当前没有事务,则新建事务
- 如果它异常,父级可以捕获它的异常而不进行回滚,正常提交
- 但如果父级异常,它必然回滚,这就是和
REQUIRES_NEW
的区别