编程式事务 是基于底层的API,如 PlatformTransactionManager
、TransactionDefinition
和 TransactionStatus
等核心接口,开发者完全可以通过编程的方式来进行事务管理。
编程式事务 需要开发者在代码中手动的管理事务的开启、提交、回滚等操作
目前提供两种实现编程式事务的方式:
- 使用
PlatformTransactionManager
(事务管理器) - 使用
TransactionTemplate
1. 通过 PlatformTransactionManager 实现的编程式事务
在传统的 Spring 项目,我们需要通过配置XML文件来使用事务,但 SpringBoot 项目,已经自动集成了,我们直接使用即可
。
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1/demo?useUnicode=true&characterEncoding=utf-8"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
</bean>
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="txManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
业务逻辑模拟
@Service
public class DemoService {
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
PlatformTransactionManager txManager;
public void update() {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionStatus status = txManager.getTransaction(definition);
try {
jdbcTemplate.update("update account_tbl set money=money+100 where name='a'");
// 为了事务回滚,抛运行时异常
int i = 1 / 0;
jdbcTemplate.update("update account_tbl set money=money-100 where name='b'");
// 事务提交
txManager.commit(status);
} catch (DataAccessException e) {
e.printStackTrace();
// 事务回滚
txManager.rollback(status);
}
}
}
如果我们需要配置事务的隔离性、传播性等,可以在 DefaultTransactionDefinition 对象中进行配置。TransactionDefinition
用来描述事务的具体规则,也称作事务的属性。
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
// 设置事务隔离级别
/**
ISOLATION_SERIALIZABLE:
最高的隔离级别,完全服从ACID的隔离级别,确保阻止脏读、不可重复读以及幻读,也是最慢的事务隔离级别
*/
definition.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);
// 设置传播行为属性
/**
PROPAGATION_REQUIRED:
表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,启动一个新的事务
*/
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
2. 通过 TransactionTemplate 来实现编程式事务
TransactionTemplate 定义:
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean {
// 定义事务控制器
private PlatformTransactionManager transactionManager;
...
}
修改XML配置: 在上面XML配置文件的基础上,再添加以下 TransactionTemplate
的配置
<bean class="org.springframework.transaction.support.TransactionTemplate" id="tranTemplate">
<property name="transactionManager" ref="txManager"/>
</bean>
直接使用 TransactionTemplate,在 execute
方法的回调匿名类中编写业务逻辑即可,当抛出异常时,将当前事务标注为只能回滚即可
@Service
public class DemoService {
@Autowired
JdbcTemplate jdbcTemplate;
@Autowired
TransactionTemplate tranTemplate;
public void update() {
tranTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
jdbcTemplate.update("update account_tbl set money=money+100 where name='a'");
// 为了事务回滚,抛运行时异常
int i = 1 / 0;
jdbcTemplate.update("update account_tbl set money=money-100 where name='b'");
} catch (DataAccessException e) {
status.setRollbackOnly(); // 当前事务标注为只能回滚
e.printStackTrace();
}
}
});
}
}
注:在 TransactionTemplate 的
execute
方法,如果不需要获取事务执行的结果,则直接使用TransactionCallbackWithoutResult
类即可,如果要获取事务执行结果,则使用TransactionCallback
。
3. 总结
编程式事务由于代码入侵太严重,因此在实际开发中使用比较少,我们在项目中更多的是使用声明式事务。
熟练使用编程式事务,对我们深入了解 Spring的事务管理是非常有帮助的。