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

来源:互联网 发布:js实现中奖后彩带特效 编辑:程序博客网 时间:2024/06/05 14:21

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

使用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方法,但不确定调用方法后会提交当前事务。该方法中抛出的任何异常都会传递给调用这。

阅读全文
0 0
原创粉丝点击