Beginning Spring学习笔记——第6章(三)使用Spring进行编程式事务管理

xiaoxiao2021-02-28  132

这样的方式对于一个庞大的方法可以将其中一部分事务化,定义事务开始和结束的位置。

使用Transaction Template进行编程式事务管理


这是Spring推荐使用的方法。 首先向AccountServiceImpl类中添加一个TransactionTemplate属性及其setter方法,然后在tansfertMoney方法中调用TransactionTemplate.execute方法,以TransactionCallbackWithoutResult类创建的匿名类为输入参数。

public class AccountServiceImpl implements AccountService { private AccountDao accountDao; private TransactionTemplate transactionTemplate; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void setTransactionTemplate(TransactionTemplate transactionTemplate) { this.transactionTemplate = transactionTemplate; } @Override public void transferMoney(final long sourceAccountId, final long targetAccountId, final double amount) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { Account sourceAccount = accountDao.find(sourceAccountId); Account targetAccount = accountDao.find(targetAccountId); sourceAccount.setBalance(sourceAccount.getBalance() - amount); targetAccount.setBalance(targetAccount.getBalance() + amount); accountDao.update(sourceAccount); accountDao.update(targetAccount); } }); } }

然后在Configuration类中通过将transactionManager注入其构造函数来定义transactionTemplate Bean。tansactionManager和dataSource Bean定义不变。并将tansactionTemplate Bean注入accountService Bean中。

@Configuration @Import(Ch4Configuration.class) public class Ch6Configuration { @Bean public TransactionTemplate transactionTemplate() { TransactionTemplate transactionTemplate = new TransactionTemplate(); transactionTemplate.setTransactionManager(transactionManager()); return transactionTemplate; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:tcp://localhost/~/test"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; } @Bean public PlatformTransactionManager transactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource()); return transactionManager; } @Bean @Autowired public AccountService accountService(AccountDao accountDao) { AccountServiceImpl bean = new AccountServiceImpl(); bean.setAccountDao(accountDao); bean.setTransactionTemplate(transactionTemplate()); return bean; } }

然后就可以在Main类中测试新的实现了。

public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext( Ch6Configuration.class); AccountService accountService = applicationContext.getBean(AccountService.class); accountService.transferMoney(100L, 101L, 5.0d); } }

执行前ACCOUNT表的内容: 执行后: 转账成功!

使用PlatformTransactionManager API进行编程式事务管理


这是一种低级的方法,与JDBC API管理事务边界类似。 首先向AccountServiceImpl类中添加一个PlatformTransactionManagerAPI属性及其setter方法。用该PlatformTransactionManager创建新的TransactionDefinition对象以便获取TransactionStatus。用AccountDao方法完成数据访问操作,顺利则通过transactionManager.commit(status)提交事务,否则使用transactionManager.rollback(status)确定是否回滚。

public class AccountServiceImpl implements AccountService { private AccountDao accountDao; private PlatformTransactionManager transactionManager; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } @Override public void transferMoney(long sourceAccountId, long targetAccountId, double amount) { TransactionDefinition definition = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(definition); try { Account sourceAccount = accountDao.find(sourceAccountId); Account targetAccount = accountDao.find(targetAccountId); sourceAccount.setBalance(sourceAccount.getBalance() - amount); targetAccount.setBalance(targetAccount.getBalance() + amount); accountDao.update(sourceAccount); accountDao.update(targetAccount); transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); throw new RuntimeException(e); } } }

在配置类中将transactionManager注入accountService Bean中。

@Configuration @Import(Ch4Configuration.class) public class Ch6Configuration { @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName("org.h2.Driver"); dataSource.setUrl("jdbc:h2:tcp://localhost/~/test"); dataSource.setUsername("sa"); dataSource.setPassword(""); return dataSource; } @Bean public PlatformTransactionManager transactionManager() { DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource()); return transactionManager; } @Bean @Autowired public AccountService accountService(AccountDao accountDao) { AccountServiceImpl bean = new AccountServiceImpl(); bean.setAccountDao(accountDao); bean.setTransactionManager(transactionManager()); return bean; } }

然后就可以运行Main函数测试新的实现了。

public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext( Ch6Configuration.class); AccountService accountService = applicationContext.getBean(AccountService.class); accountService.transferMoney(101L, 100L, 5.0d); } }

运行前ACCOUNT表如上图,运行后: 转账成功!

在事务执行前后执行自定义逻辑


通知事务性操作

将事务功能作为一个AOP通知,使用Spring AOP功能进行处理。 可使用MethodInceptor拦截方法调用,在调用前后执行一些额外操作。并在XML文件中的aop:config元素中使用aop:advisor定义在哪些方法上触发该逻辑。

使用TransactionSynchronization执行事务后逻辑

使用回调机制指定当前事务结束时需要执行的自定义代码块。TransactionSynchronization接口定义为:

public interface TransactionSynchronization extends Flushable{ int STATUS_COMMITED = 0; int STATUS_ROLLED_BACK = 1; int STATUS_UNKNOWN = 2; void beforeCommit(boolean readOnly); void afterCommit(); void afterCompletion(int status); }

提交事务前调用befroeCommit方法,但不确定调用方法后会提交当前事务。该方法中抛出的任何异常都会传递给调用这。

转载请注明原文地址: https://www.6miu.com/read-19464.html

最新回复(0)