1. Spring поддерживает программное управление транзакциями TransactionTemplate
и декларативное управление транзакциями @Transactional
двумя способами.
По сравнению с программными транзакциями единственным недостатком декларативных транзакций является то, что наиболее мелкие транзакции могут применяться только на уровне метода и не могут применяться на уровне блока кода, как программные транзакции. Но даже если есть такое требование, есть много обходных путей, например, можно разделить блоки кода, которым нужно управление транзакциями, на методы и т. д. (типа use
AopContext.currentProxy()
).
2. @Transactional
Можно AopContext.currentProxy()
решить, что в том же классе нетранзакционный метод A вызывает транзакционный метод B, и транзакция не выполняется.
Метод B вызывается A, и врезка метода B недействительна, но прокси-класс создается добавлением AopContext.currentProxy(), и врезка выполняется до и после вызова этого метода в прокси сорт. Для метода B proxy.B процесс выполнения заключается в том, чтобы сначала записать журнал, а затем вызвать тело метода, но вызов в методе A proxyA может только улучшить A, а вызов B в A использует объект. B( ) вместо $proxy .B(), поэтому переход к B недействителен.
Примечание. AopContext.currentProxy() использует ThreadLocal для сохранения прокси-объекта, поэтому
AopContext.currentProxy().B() может решить эту проблему.
public class Demo {
public void methodA () {
...
// 获取当前代理类,保证同一个类中非事务方法调用事务方法时事务生效
((Demo) AopContext.currentProxy()).methodA();
...
}
@Transactional(rollbackFor = Exception.class)
public void methodB () {
...
}
}
- Используйте
@Transactional
декларативные транзакции
находятся в одном классе | передача | Действительна ли сделка |
---|---|---|
в разных классах | Транзакционный метод A вызывает нетранзакционный метод B | Транзакция вступает в силу |
в разных классах | Нетранзакционный метод A вызывает транзакционный метод B | Транзакция вступает в силу |
в том же классе | Транзакционный метод A вызывает нетранзакционный метод B | Транзакция распространяется, и транзакция вступает в силу |
в том же классе | Нетранзакционный метод A вызывает транзакционный метод B | сбой транзакции |
Перепечатано: https://www.jianshu.com/p/2ab568e7aaf7
3. Программная транзакция Использование TransactionTemplate
public class Demo {
@Resource
private TransactionTemplate transactionTemplate;
public void methodA () {
...
// 指定事务传播性(可不设置,默认是`PROPAGATION_REQUIRED`)
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 指定事务隔离级别(可不设置,默认是`ISOLATION_DEFAULT`,同数据库隔离级别)
transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_DEFAULT);
transactionTemplate.execute(transactionStatus -> {
methodB();
return Boolean.TRUE;
});
...
}
public void methodB () {
...
}
}
- Поведение распространения транзакции
1. TransactionDefinition.PROPAGATION_REQUIRED:
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
2. TransactionDefinition.PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则把当前事务挂起。
3. TransactionDefinition.PROPAGATION_SUPPORTS:
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
4. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:
以非事务方式运行,如果当前存在事务,则把当前事务挂起。
5. TransactionDefinition.PROPAGATION_NEVER:
以非事务方式运行,如果当前存在事务,则抛出异常。
6. TransactionDefinition.PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
7. TransactionDefinition.PROPAGATION_NESTED:
如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;
如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
- уровень изоляции транзакций
1. @Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读,
不可重复读) 基本不使用
2. @Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
3. @Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
4. @Transactional(isolation = Isolation.SERIALIZABLE):串行化