1. 配置application.properties
#primary db
spring.datasource.primary.url=jdbc:mysql://127.0.0.1:3306/master?characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.primary.username=root
spring.datasource.primary.password=root
spring.datasource.primary.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.primary.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.primary.filters=stat
spring.datasource.primary.maxActive=20
spring.datasource.primary.initialSize=1
spring.datasource.primary.maxWait=60000
spring.datasource.primary.minIdle=1
spring.datasource.primary.timeBetweenEvictionRunsMillis=60000
spring.datasource.primary.minEvictableIdleTimeMillis=300000
spring.datasource.primary.validationQuery=select 'x'
spring.datasource.primary.testWhileIdle=true
spring.datasource.primary.testOnBorrow=false
spring.datasource.primary.testOnReturn=false
spring.datasource.primary.poolPreparedStatements=true
spring.datasource.primary.maxOpenPreparedStatements=20
#slave db1
spring.datasource.secondary.url=jdbc:mysql://127.0.0.1:3306/slave?characterEncoding=utf-8&allowMultiQueries=true
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root
spring.datasource.secondary.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.secondary.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.secondary.filters=stat
spring.datasource.secondary.maxActive=20
spring.datasource.secondary.initialSize=1
spring.datasource.secondary.maxWait=60000
spring.datasource.secondary.minIdle=1
spring.datasource.secondary.timeBetweenEvictionRunsMillis=60000
spring.datasource.secondary.minEvictableIdleTimeMillis=300000
spring.datasource.secondary.validationQuery=select 'x'
spring.datasource.secondary.testWhileIdle=true
spring.datasource.secondary.testOnBorrow=false
spring.datasource.secondary.testOnReturn=false
spring.datasource.secondary.poolPreparedStatements=true
spring.datasource.secondary.maxOpenPreparedStatements=20
△这里注意的是一定要指定主数据源(主数据源用primary标识)
2. 配置主数据源PrimaryDataSourceConfig
@Configuration
@MapperScan(basePackages ="xx.xxx.xx.mapper.primary",sqlSessionTemplateRef = "primarySqlSessionTemplate")
public class PrimaryDataSourceConfig{
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    @Primary
    public DataSource primaryDataSource() { 
        return new DruidDataSource();
    }
    @Bean(name = "primaryTransactionManager")
    @Primary
    public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
         return new DataSourceTransactionManager(dataSource);
    }
    @Bean(name = "primarySqlSessionFactory")
    @Primary
    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource)
     throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("xx.xx.xx.model");
        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        //添加插件
        bean.setPlugins(new Interceptor[]{pageHelper});
        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    @Bean(name = "primarySqlSessionTemplate")
    @Primary
    public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory")
        SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    @Bean
    @Primary
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("primarySqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("xx.xx.xx.mapper.primary");
        Properties properties = new Properties();
        properties.setProperty("mappers", "xx.xx.xx.util.MyMapper");
        properties.setProperty("notEmpty", "false");
        properties.setProperty("IDENTITY", "MYSQL");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }
}
△多个数据源要标识哪一个为主数据源所以这里PrimaryDataSourceConfig设置为主数据源需要用@primary来标识是主数据源(默认使用主数据源)
3.配置次数据源SlaveOneDataSourceConfig
@Configuration
@MapperScan(basePackages ="xx.xx.xx.mapper.slave1",sqlSessionTemplateRef = "slaveOneSqlSessionTemplate")
public class SlaveOneDataSourceConfig{
    @Bean(name = "slaveOneDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource slaveOneDataSource() {
        return new DruidDataSource();
    }
    @Bean(name = "slaveOneTransactionManager")
    public PlatformTransactionManager slaveOneTransactionManager(@Qualifier("slaveOneDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    @Bean(name = "slaveOneSqlSessionFactory")
    public SqlSessionFactory slaveOneSqlSessionFactory(@Qualifier("slaveOneDataSource") DataSource dataSource) 
    throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        bean.setTypeAliasesPackage("xx.xx.xx.model");
        //分页插件
        PageHelper pageHelper = new PageHelper();
        Properties properties = new Properties();
        properties.setProperty("reasonable", "true");
        properties.setProperty("supportMethodsArguments", "true");
        properties.setProperty("returnPageInfo", "check");
        properties.setProperty("params", "count=countSql");
        pageHelper.setProperties(properties);
        //添加插件
        bean.setPlugins(new Interceptor[]{pageHelper});
        //添加XML目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        try {
            bean.setMapperLocations(resolver.getResources("classpath:mapper/*.xml"));
            return bean.getObject();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    @Bean(name = "slaveOneSqlSessionTemplate")
    public SqlSessionTemplate slaveOneSqlSessionTemplate(@Qualifier("slaveOneSqlSessionFactory")
    SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("slaveOneSqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("cn.ctx.admin.mapper.slave1");
        Properties properties = new Properties();
        properties.setProperty("mappers", "xx.xx.xx.util.MyMapper");
        properties.setProperty("notEmpty", "false");
        properties.setProperty("IDENTITY", "MYSQL");
        mapperScannerConfigurer.setProperties(properties);
        return mapperScannerConfigurer;
    }
}
@MapperScan(basePackages =”cn.ctx.admin.mapper”,sqlSessionTemplateRef = “sqlSessionTemplate”)
basePackages 对应的dao mybatis会根据不同的dao切换数据源
4. 多数据源使用事物
- 程序入口需要加入 @EnableTransactionManagement注解开启注解,等同于xml配置方式的<tx:annotation-driven />
 △注意,发现事务不回滚//△多数据源 value 指定需要回滚的数据源一定要写 @Transactional(value="slaveOneTransactionManager") @Override public Map<String, Object> addSlaveData() { Map<String,Object> map=new HashMap<String,Object>(); try { int i=userInfoMapper.addSlaveData(); if(i>0) { map.put("result","写入成功"); }else { map.put("result","写入失败"); } }catch (Exception e) { map.put("result","写入失败"); //异常手动回滚,好处上层就无需去处理异常 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return map; }
 原因:
- 默认spring事务只在发生未被捕获的 RuntimeException 时才回滚。
- spring aop  异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理,这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获 RuntimeException 的异常,但可以通过配置来捕获特定的异常并回滚
 换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获而回滚
- 解决方案: - 方案1.例如service层处理事务,那么service中的方法中不做异常捕获,或者在catch语句中最后增加throw new RuntimeException()语句,以便让aop捕获异常再去回滚,并且在service上层(webservice客户端,view层action)要继续捕获这个异常并处理
- 方案2.在service层方法的catch语句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();语句,手动回滚,这样上层就无需去处理异常
 
          赏
          
            
              
              使用支付宝打赏
            
            
              
              使用微信打赏
            
          
        
        若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏
扫描二维码,分享此文章
