一、编程式事务和声明式事务的区别
1. 编程式事务
-
定义 : 通过手动编码控制事务的开启、提交和回滚,通常使用
TransactionTemplate
或PlatformTransactionManager
。 -
特点: 灵活性高,但代码侵入性强。
-
代码实践 :
javaimport org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; @Service public class ProgrammaticTransactionService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private TransactionTemplate transactionTemplate; public void updateDataWithTransaction() { transactionTemplate.execute(new TransactionCallback<Void>() { @Override public Void doInTransaction(TransactionStatus status) { try { // 业务逻辑1: 插入数据 jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Alice", 25); // 模拟异常 if (true) { throw new RuntimeException("Simulated error"); } // 业务逻辑2: 更新数据 jdbcTemplate.update("UPDATE user SET age = ? WHERE name = ?", 26, "Alice"); return null; } catch (Exception e) { status.setRollbackOnly(); // 手动标记回滚 throw e; } } }); } }
- 说明 : 如果发生异常,
status.setRollbackOnly()
标记事务回滚,插入操作会被撤销。
- 说明 : 如果发生异常,
2. 声明式事务
-
定义 : 使用
@Transactional
注解,通过 Spring AOP 自动管理事务。 -
特点: 代码简洁,但受限于 AOP 机制。
-
代码实践 :
javaimport org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class DeclarativeTransactionService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void updateDataWithTransaction() { // 业务逻辑1: 插入数据 jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Bob", 30); // 模拟异常 if (true) { throw new RuntimeException("Simulated error"); } // 业务逻辑2: 更新数据 jdbcTemplate.update("UPDATE user SET age = ? WHERE name = ?", 31, "Bob"); } }
- 说明 : 默认情况下,抛出
RuntimeException
会自动触发回滚,插入操作被撤销。
- 说明 : 默认情况下,抛出
区别总结
特性 | 编程式事务 | 声明式事务 |
---|---|---|
实现方式 | TransactionTemplate 或手动调用 |
@Transactional 注解 |
代码示例 | 显式控制事务边界 | 注解驱动,自动管理 |
灵活性 | 高,可动态调整逻辑 | 较低,依赖配置 |
侵入性 | 高,事务代码嵌入业务逻辑 | 低,与业务逻辑分离 |
二、@Transactional
的默认行为和局限性
1. 默认行为
-
异常捕获 : 只对
RuntimeException
和Error
触发回滚。 -
代码实践 :
java@Service public class DefaultBehaviorService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void defaultRollback() throws Exception { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Charlie", 35); // 抛出非 RuntimeException,不会回滚 throw new Exception("Not a RuntimeException"); } @Transactional(rollbackFor = Exception.class) public void explicitRollback() throws Exception { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "David", 40); // 显式指定 rollbackFor,回滚生效 throw new Exception("Explicit rollback"); } }
- 结果 :
defaultRollback
: 事务不回滚,数据插入成功。explicitRollback
: 事务回滚,数据插入被撤销。
- 结果 :
2. 局限性及代码实践
-
方法可见性 : 仅对
public
方法生效。java@Service public class VisibilityService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional private void privateMethod() { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Eve", 45); throw new RuntimeException("Test rollback"); } public void callPrivateMethod() { privateMethod(); // 直接调用,事务不生效 } }
- 结果 :
privateMethod
的@Transactional
被忽略,数据插入成功。
- 结果 :
-
自调用: 同一个类内方法调用,事务失效。
java@Service public class SelfInvocationService { @Autowired private JdbcTemplate jdbcTemplate; public void methodA() { methodB(); // 自调用,事务不生效 } @Transactional public void methodB() { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Frank", 50); throw new RuntimeException("Test rollback"); } }
- 结果 :
methodB
的@Transactional
不生效,数据插入成功。 - 解决办法: 使用自注入。
java@Service public class SelfInvocationFixService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private SelfInvocationFixService self; public void methodA() { self.methodB(); // 通过代理调用,事务生效 } @Transactional public void methodB() { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Grace", 55); throw new RuntimeException("Test rollback"); } }
- 结果: 事务回滚,数据插入被撤销。
- 结果 :
-
代理对象: 非代理对象调用,事务失效。
javapublic class ProxyIssueExample { public static void main(String[] args) { DeclarativeTransactionService service = new DeclarativeTransactionService(); service.updateDataWithTransaction(); // 直接 new,事务不生效 } }
- 结果: 事务不生效,需通过 Spring 容器获取代理对象。
三、TransactionManager
和 TransactionAspectSupport
结合触发回滚
1. TransactionManager
-
代码实践 (编程式事务直接使用
TransactionManager
):javaimport org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; @Service public class TransactionManagerService { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private PlatformTransactionManager transactionManager; public void manualTransaction() { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(def); try { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Helen", 60); throw new RuntimeException("Test rollback"); } catch (Exception e) { transactionManager.rollback(status); // 手动回滚 throw e; } // 如果没有异常,手动提交 // transactionManager.commit(status); } }
- 结果: 事务回滚,数据插入被撤销。
2. TransactionAspectSupport
-
代码实践 (结合
@Transactional
):javaimport org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.interceptor.TransactionAspectSupport; @Service public class TransactionAspectService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void forceRollback() { jdbcTemplate.update("INSERT INTO user (name, age) VALUES (?, ?)", "Ivy", 65); // 手动触发回滚 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
- 结果: 事务回滚,数据插入被撤销。
- 说明 :
@Transactional
通过TransactionInterceptor
(继承自TransactionAspectSupport
)调用TransactionManager
管理事务,异常或手动标记回滚时触发rollback()
。
3. Spring Boot 配置
-
自动配置示例 :
javaimport org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; @Configuration public class TransactionConfig { @Bean public DataSourceTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
- Spring Boot 默认自动配置
TransactionManager
,无需手动定义,除非需要自定义。
- Spring Boot 默认自动配置