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

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

使用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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值