springBoot 多数据源事务的管理以及回滚

来源:互联网 发布:邮电大学网络教育 编辑:程序博客网 时间:2024/06/06 15:47

            最近开发的项目中使用到了多数据源,也使用到了两个不同事务的回滚事件,保证数据的一致性。部分代码共大家参考:MYSQL作为事例。

配置文件


spring.datasource.prod.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.prod.url=jdbc:mysql://127.0.0.1:3306/test
spring.datasource.prod.username=root
spring.datasource.prod.password=root




spring.datasource.dev.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.dev.url=jdbc:mysql://127.0.0.1:3306/test1
spring.datasource.dev.username=root
spring.datasource.dev.password=root


配置数据源以及事务的管理
package com.lanwon.config;


import java.sql.SQLException;


import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;


/**
 * @author dzb
 * @date 2017年8月23日 
 * 数据源dev
 */
@Configuration#不同的数据源扫描dao时要分层次,否则只能被绑定一次。
@MapperScan(basePackages="com.lanwon.mapper.dev",sqlSessionFactoryRef="devSqlSessionFactory")
public class devDataSourceConfig {


    @Value("${spring.datasource.dev.driver-class-name}")
    private String dbDriver;


    @Value("${spring.datasource.dev.url}")
    private String dbUrl;


    @Value("${spring.datasource.dev.username}")
    private String userName;


    @Value("${spring.datasource.dev.password}")
    private String password;


    @Resource
    private GlobalDbConfig globalDbConfig;


    private static final String MAPPER_PATH = "classpath*:/mapper/dev/*.xml";


    private static final String ENTITY_PACKAGE = "com.lanwon.entity.dev";


    @Bean(name = "devDataSource")
    @Primary
    public DataSource devDataSource() throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(dbDriver);
        dataSource.setUrl(dbUrl);
        dataSource.setUsername(userName);
        dataSource.setPassword(password);
        dataSource.setFilters(globalDbConfig.getDbFilters());
        dataSource.setMaxActive(globalDbConfig.getDbMaxActive());
        dataSource.setMaxWait(globalDbConfig.getDbMaxWait());
        dataSource.setMinIdle(globalDbConfig.getDbMinIdle());
        dataSource.setTimeBetweenEvictionRunsMillis(globalDbConfig
                .getDbTimeBetweenEvictionRunsMillis());
        dataSource.setMinEvictableIdleTimeMillis(globalDbConfig
                .getDbMinEvictableIdleTimeMillis());
        dataSource.setTestWhileIdle(globalDbConfig.isDbtestWhileIdle());
        dataSource.setValidationQuery(globalDbConfig.getDbValidationQuery());
        dataSource.setTestOnBorrow(globalDbConfig.isDbTestOnBorrow());
        dataSource.setTestOnReturn(globalDbConfig.isDbTestOnReturn());
        dataSource.setPoolPreparedStatements(globalDbConfig
                .isDbPoolPreparedStatements());
        dataSource.setMaxOpenPreparedStatements(globalDbConfig
                .getDbMaxOpenPreparedStatements());
        dataSource.init();
        return dataSource;
    }



    @Bean(name = "devTransactionManager")
    @Primary
    public DataSourceTransactionManager devTransactionManager()
            throws SQLException {
        return new DataSourceTransactionManager(devDataSource());
    }
    
    
    @Bean(name = "devSqlSessionFactory")
    @Primary //默认
    public SqlSessionFactory devSqlSessionFactory(
            @Qualifier("devDataSource") DataSource ddataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(ddataSource);
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactory.setMapperLocations(resolver.getResources(MAPPER_PATH));
        sessionFactory.setTypeAliasesPackage(ENTITY_PACKAGE);
        return sessionFactory.getObject();
    }


}




import java.sql.SQLException;
import javax.annotation.Resource;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;


/**
 * @author dzb
 * @date 2017年8月23日 
 * 数据源prod
 */
@Configuration
@MapperScan(basePackages="com.lanwon.mapper.prod",sqlSessionFactoryRef="prodSqlSessionFactory")
public class prodDataSourcesConfig {


    @Value("${spring.datasource.prod.driver-class-name}")
    private String dbDriver;


    @Value("${spring.datasource.prod.url}")
    private String dbUrl;


    @Value("${spring.datasource.prod.username}")
    private String userName;


    @Value("${spring.datasource.prod.password}")
    private String password;


    @Resource
    private GlobalDbConfig globalDbConfig;


    private static final String MAPPER_PATH = "classpath*:/mapper/prod/*.xml";


    private static final String ENTITY_PACKAGE = "com.lanwon.entity.prod";


    @Bean(name = "prodDataSource")
    public DataSource prodDataSource() throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(dbDriver);
        dataSource.setUrl(dbUrl);
        dataSource.setUsername(userName);
        dataSource.setPassword(password);
        dataSource.setFilters(globalDbConfig.getDbFilters());
        dataSource.setMaxActive(globalDbConfig.getDbMaxActive());
        dataSource.setMaxWait(globalDbConfig.getDbMaxWait());
        dataSource.setMinIdle(globalDbConfig.getDbMinIdle());
        dataSource.setTimeBetweenEvictionRunsMillis(globalDbConfig
                .getDbTimeBetweenEvictionRunsMillis());
        dataSource.setMinEvictableIdleTimeMillis(globalDbConfig
                .getDbMinEvictableIdleTimeMillis());
        dataSource.setTestWhileIdle(globalDbConfig.isDbtestWhileIdle());
        dataSource.setValidationQuery(globalDbConfig.getDbValidationQuery());
        dataSource.setTestOnBorrow(globalDbConfig.isDbTestOnBorrow());
        dataSource.setTestOnReturn(globalDbConfig.isDbTestOnReturn());
        dataSource.setPoolPreparedStatements(globalDbConfig
                .isDbPoolPreparedStatements());
        dataSource.setMaxOpenPreparedStatements(globalDbConfig
                .getDbMaxOpenPreparedStatements());
        dataSource.init();
        return dataSource;
    }


    @Bean(name = "prodTransactionManager")
    public DataSourceTransactionManager prodTransactionManager()
            throws SQLException {
        return new DataSourceTransactionManager(prodDataSource());
    }


    @Bean(name = "prodSqlSessionFactory")
    public SqlSessionFactory prodSqlSessionFactory(
            @Qualifier("prodDataSource") DataSource pdataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(pdataSource);
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactory.setMapperLocations(resolver.getResources(MAPPER_PATH));
        sessionFactory.setTypeAliasesPackage(ENTITY_PACKAGE);
        return sessionFactory.getObject();
    }


}


使用事务管理器

使用时只需在需要事务的方法添加注解@Transactional,并指定其value值即可。同样的,value值与相应的事务管理方法名相匹配即可。


/**
 * @author dzb
 * @since 2016/7/5 - 22:21
 */
@Service
public class UserDetailServiceImpl implements UserDetailService {


    @Autowired
    private UserDetailMapper userDetailMapper;


    public List<UserDetail> selectUserDetail() {
        return userDetailMapper.selectAll();
    }




@Transactional(value="devTransactionManager")
@Override
public int update(UserDetail userDetail){
int b=userDetailMapper.update(userDetail);
return b;
}
}



@Service
public class UserInfoServiceImpl implements UserInfoService {




    @Autowired
    private UserInfoMapper userInfoMapper;
    
    @Autowired
    private  UserDetailServiceImpl detailServiceImpl ;
    
    public List<UserInfo> selectUserInfo() {
        return userInfoMapper.selectAll();
    }


//@Transactional(value="prodTransactionManager")
@Override
public int update(UserInfo userInfo) {
int a =userInfoMapper.update(userInfo);
return a;
}


    @Transactional(value="prodTransactionManager")
@Override
public int update(String name1,String name2) {
    int c=0;
UserInfo info = new UserInfo();
info.setId("1");
info.setUsername(name1);
int b=userInfoMapper.update(info);
if(b>0){
UserDetail detail = new UserDetail();
detail.setId(1L);
detail.setName(name2);
c=detailServiceImpl.update(detail);
}
   
return c;
}
}



事务传播行为种类

Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,

它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:

表1事务传播行为类型

事务传播行为类型

说明

PROPAGATION_REQUIRED

如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。

PROPAGATION_SUPPORTS

支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY

使用当前的事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW

新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED

以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER

以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED

如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。




注:这篇文章是本人自己所遇到写的,如果有不太对的地方,请多多指教。
        项目源码github:https://github.com/sdmxdzb/transcations

原创粉丝点击