多数据源事物管理浅谈

这里我用到的是spring 4.09  hibernate 4.1.0.Final------PS:网上好多人说多数据源必须配置多个事务管理器基本都是用的spring 3

多数据源的实现可以参看之前的文章:多数据源

举例说明:

有两个数据源:dataSourceOne、dataSourceTwo

有两个service类,oneService、twoService

@Service("oneService")
public class oneServiceImpl implements oneService {    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private twoService twoService;

    @Transactional
    public void txLog(){
        DataSourceContextHandle.setDataSourceType(DataSourceType.dataSourceOne);
        String sql4 = "INSERT INTO jxfp_tyjr_logs(logcontent,loglevel,operatetime,user_id) value('测试','4',now(),'777')";
        jdbcTemplate.execute(sql4);
        DataSourceContextHandle.setDataSourceType(DataSourceType.dataSourceTwo);
        String sql2 = "INSERT INTO jxfp_tyjr_logs(logcontent,loglevel,operatetime,user_id) value('测试','3',now(),'777')";
        jdbcTemplate.execute(sql2);
        try{
            twoService.txSaveLog();
        }catch(Exception e){
            e.printStackTrace();
        }    
    }
}
@Service("twoService")
public class twoServiceImpl implements twoService {
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    @Autowired
    private JdbcTemplate jdbcTemplate;

@Transactional(propagation=Propagation.NOT_SUPPORTED) public void txSaveLog() { DataSourceContextHandle.setDataSourceType(DataSourceType.dataSourceTwo); String sql1 = "INSERT INTO jxfp_tyjr_logs(logcontent,loglevel,operatetime,user_id) value('测试','2',now(),'777')"; jdbcTemplate.batchUpdate(new String[]{sql1}); } }

我们在测试类中调用oneService的txLog()方法

public class test {
    public static void main(String[] args) throws InterruptedException {
        ApplicationContext context = new ClassPathXmlApplicationContext("winclpt/transaction/spring-mvc-hibernate.xml");
        oneService os = (oneService) context.getBean("oneService");
    
DataSourceContextHandle.setDataSourceType(DataSourceType.dataSourceOne);//在调用oneService的txLog()方法前我们将数据源切换为dataSourceOne
     os.txLog();
  }
}

以上都看了后,我们分析以下情况:

              当oneService.txLog()和twoService.txSaveLog()都开启了@Transactional,那么txLog()方法在事物切入的时候(也就是方法执行前)就确定了使用数据源dataSourceOne,之后将不再执行determineTargetDataSource()方法确定用哪个数据源。

              当twoService.txSaveLog()设置Propagation.REQUIRED,那么txSaveLog()将加入到txLog()的事物中执行,没有启用新事物,那么他们将使用同一个数据源dataSourceOne

              当twoService.txSaveLog()设置Propagation.REQUIRED_NEW,那么txSaveLog()执行的时候会从新启动一个事物,并将txLog()的事物挂起,在启动事物的同时会先执行determineTargetDataSource()方法确定当前要使用哪个数据源,由于在执行txSaveLog()发方法前已经将数据源切换到了dataSourceTwo,那么txSaveLog()执行过程将会使用数据源dataSourceTwo,txLog()会使用它的数据源dataSourceOne

              当当twoService.txSaveLog()设置Propagation.NOT_SUPPORTED,那么txSaveLog()会把txLog()的事物挂起在非事物环境执行,由于是在非事物环境执行,所以在txSaveLog()执行前不会调用determineTargetDataSource()方法,而是在执行入库操作前执行此方法确定使用哪个数据源,由于在执行txSaveLog()发方法前已经将数据源切换到了dataSourceTwo,那么txSaveLog()执行过程将会使用数据源dataSourceTwo,txLog()会使用它的数据源dataSourceOne

 

总结

一、在没有启动事物的方法里面,执行数据库操作前都会执行determineTargetDataSource()方法来确定当前要使用哪个数据源

二、在启动事物的方法里,事物是通过AOP动态代理的方法在目标方法前插进去的,determineTargetDataSource()方法也会在这个时候执行,之后将不再执行,也就是说每个方法在事物一开始就必须确定使用哪个数据源,之后即使碰到数据库操作也不会执行determineTargetDataSource()方法

三、同一个事物将实用同一个数据源

posted @ 2017-07-14 16:13  暗夜心慌方  阅读(1037)  评论(0编辑  收藏  举报