spring boot+mybatis+druid 多数据源多库分布式事务

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ypp91zr/article/details/83988919

废话不多说,首先贴配置文件,需要引入pomxml

        <dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>druid-spring-boot-starter</artifactId>
			<version>1.1.10</version>
		</dependency>
		<!-- JTA atomikos事务 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jta-atomikos</artifactId>
		</dependency>

JTA/atomikos自行了解

配置文件:

spring: 
    datasource:
        druid: 
          type: com.alibaba.druid.pool.xa.DruidXADataSource
          driver-class-name: com.mysql.jdbc.Driver
          platform: mysql
          default: 
            # 资源标识
            uniqueResourceName: default
            # 数据源类名
            xaDataSourceClassName: com.alibaba.druid.pool.xa.DruidXADataSource
#            xaDataSourceClassName: org.apache.tomcat.jdbc.pool.DataSource
#            xaDataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
            xaProperties: 
              # 数据源配置
              driverClassName: com.mysql.jdbc.Driver
              url: jdbc:mysql://211.149.199.68:3306/mypinyu?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&pinGlobalTxToPhysicalConnection=true
              username: root
              password: Goodlan@123
              initialSize: 10
              minIdle: 10
              maxActive: 200
              maxWait: 60000
              timeBetweenEvictionRunsMillis: 60000
              minEvictableIdleTimeMillis: 300000
              validationQuery: SELECT 1 FROM DUAL
              testWhileIdle: true
              testOnBorrow: false
              testOnReturn: false
              # 打开PSCache,并且指定每个连接上PSCache的大小
              poolPreparedStatements: true
              maxPoolPreparedStatementPerConnectionSize: 20
              # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
              connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
              #超过时间限制是否回收 
              removeAbandoned: true
              #超时时间;单位为秒。180秒=3分钟
              removeAbandonedTimeout: 180
              #关闭abanded连接时输出错误日志
#              logAbandoned: true
          second: 
            # 资源标识
            uniqueResourceName: second
            # 数据源类名
            xaDataSourceClassName: com.alibaba.druid.pool.xa.DruidXADataSource
#            xaDataSourceClassName: com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
#            xaDataSourceClassName: org.apache.tomcat.jdbc.pool.DataSource
            xaProperties: 
              driverClassName: com.mysql.jdbc.Driver
              url: jdbc:mysql://localhost:3306/mypinyu?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false&pinGlobalTxToPhysicalConnection=true
              username: root
              password: admin
              initialSize: 10
              minIdle: 10
              maxActive: 200
              maxWait: 60000
              timeBetweenEvictionRunsMillis: 60000
              minEvictableIdleTimeMillis: 300000
              #验证连接是否可用,使用的SQL语句
              validationQuery: SELECT 1 FROM DUAL #DruidXADataSource pool.DataSource 范围 
#              testQuery: select 1#MysqlXADataSource范围使用
              #指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
              testWhileIdle: true
              #借出连接时不要测试,否则很影响性能
              testOnBorrow: false
              testOnReturn: false
              # 打开PSCache,并且指定每个连接上PSCache的大小
              poolPreparedStatements: true
              maxPoolPreparedStatementPerConnectionSize: 20
              # 通过connectProperties属性来打开mergeSql功能;慢SQL记录
              connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
              #设置连接参数,否则durid在mysql断开连接后连接不上数据库了,配置数据库断开后自动连接
              #超过时间限制是否回收 
              removeAbandoned: true
              #超时时间;单位为秒。180秒=3分钟
              removeAbandonedTimeout: 180
              #关闭abanded连接时输出错误日志
#              logAbandoned: true
#jta相关参数配置
jta:
  log-dir: classpath:tx-logs
  transaction-manager-id: transactionManager
        
logging.config:
  classpath: log4j2.xml
  
#返回视图的前缀   目录对应src/main/webapp下
spring.mvc.view.prefix: /WEB-INF/jsp/
#返回的后缀
spring.mvc.view.suffix: .jsp

配置:

package com.pinyu.system.global.config.datasource;

import java.util.Properties;

import javax.sql.DataSource;
import javax.transaction.UserTransaction;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.transaction.jta.JtaTransactionManager;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;

/** 
* @author ypp
* 创建时间:2018年11月9日 上午9:36:21 
* @Description: TODO(用一句话描述该文件做什么) 
*/
@Configuration
public class DruidConfig {

	@Bean(DataSourceNames.DEFAULT)
    @Primary
    @Autowired
    public DataSource systemDataSource(Environment env) {
        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        Properties prop = build(env, "spring.datasource.druid."+DataSourceNames.DEFAULT+".");
        ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
        ds.setUniqueResourceName(DataSourceNames.DEFAULT);
        ds.setPoolSize(5);
        ds.setXaProperties(prop);
        return ds;

    }

    @Autowired
    @Bean(name = DataSourceNames.SECOND)
    public AtomikosDataSourceBean businessDataSource(Environment env) {

        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        Properties prop = build(env, "spring.datasource.druid."+DataSourceNames.SECOND+".");
        ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
        ds.setUniqueResourceName(DataSourceNames.SECOND);
        ds.setPoolSize(5);
        ds.setXaProperties(prop);

        return ds;
    }


    /**
     * 注入事物管理器
     * @return
     */
    @Bean("transactionManager")
    public JtaTransactionManager regTransactionManager () {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        UserTransaction userTransaction = new UserTransactionImp();
        return new JtaTransactionManager(userTransaction, userTransactionManager);
    }


    private Properties build(Environment env, String prefix) {
    	long minEvictableIdleTimeMillis = Long.parseLong(env.getProperty(prefix + "minEvictableIdleTimeMillis"));
    	long timeBetweenEvictionRunsMillis = Long.parseLong(env.getProperty(prefix + "timeBetweenEvictionRunsMillis"));
        Properties prop = new Properties();
        prop.put("url", env.getProperty(prefix + "url"));
        prop.put("username", env.getProperty(prefix + "username"));
        prop.put("password", env.getProperty(prefix + "password"));
        prop.put("driverClassName", env.getProperty(prefix + "driverClassName"));
        prop.put("initialSize", Integer.valueOf(env.getProperty(prefix + "initialSize")));
        prop.put("minIdle", Integer.valueOf(env.getProperty(prefix + "minIdle")));
        prop.put("maxActive", Integer.valueOf(env.getProperty(prefix + "maxActive")));
        prop.put("maxWait", Integer.valueOf(env.getProperty(prefix + "maxWait")));
//        prop.put("timeBetweenEvictionRunsMillis", timeBetweenEvictionRunsMillis);
//        prop.put("minEvictableIdleTimeMillis", minEvictableIdleTimeMillis);
        prop.put("validationQuery", env.getProperty(prefix + "validationQuery"));
        prop.put("testWhileIdle", Boolean.valueOf(env.getProperty(prefix + "testWhileIdle")));
        prop.put("testOnBorrow", Boolean.valueOf(env.getProperty(prefix + "testOnBorrow")));
        prop.put("testOnReturn", Boolean.valueOf(env.getProperty(prefix + "testOnReturn")));
        return prop;
    }

    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        //控制台管理用户,加入下面2行 进入druid后台就需要登录
        //servletRegistrationBean.addInitParameter("loginUsername", "admin");
        //servletRegistrationBean.addInitParameter("loginPassword", "admin");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        return filterRegistrationBean;
    }

    @Bean
    public StatFilter statFilter(){
        StatFilter statFilter = new StatFilter();
        statFilter.setLogSlowSql(true); //slowSqlMillis用来配置SQL慢的标准,执行时间超过slowSqlMillis的就是慢。
        statFilter.setMergeSql(true); //SQL合并配置
        statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000,也就是3秒。
        return statFilter;
    }

    @Bean
    public WallFilter wallFilter(){
        WallFilter wallFilter = new WallFilter();
        //允许执行多条SQL
        WallConfig config = new WallConfig();
        config.setMultiStatementAllow(true);
        wallFilter.setConfig(config);
        return wallFilter;
    }
}
package com.pinyu.system.global.config.datasource;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

/** 
* @author ypp
* 创建时间:2018年11月9日 上午10:09:56 
* @Description: TODO(用一句话描述该文件做什么) 
*/
@Configuration
@MapperScan(basePackages = "com.pinyu.system.mapper",sqlSessionFactoryRef = "defaultSqlSessionFactory")
public class MybatisDataSourceDefaultConfig {


    @Bean
    public SqlSessionFactory defaultSqlSessionFactory(@Qualifier(DataSourceNames.DEFAULT)DataSource ds) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(ds);
        //指定mapper xml目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(resolver.getResources("classpath:mapper/**/*Mapper.xml"));
        return factoryBean.getObject();

    }

    @Bean
    public SqlSessionTemplate defaultSqlSessionTemplate(@Qualifier("defaultSqlSessionFactory")SqlSessionFactory sf) throws Exception {
        SqlSessionTemplate template = new SqlSessionTemplate(sf); // 使用上面配置的Factory
        return template;
    }

    //关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager
    // 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
    //在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
    /*@Bean(name = "transactionManager2")
    @Primary
    public DataSourceTransactionManager masterTransactionManager() {
        //MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源
        // 与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。
        return new DataSourceTransactionManager(ds);
    }*/

}
package com.pinyu.system.global.config.datasource;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

/** 
* @author ypp
* 创建时间:2018年11月9日 上午10:18:03 
* @Description: TODO(用一句话描述该文件做什么) 
*/
@Configuration
@MapperScan(basePackages = "com.pinyu.system.mapper2",sqlSessionFactoryRef = "secondSqlSessionFactory")
public class MybatisDataSourceSecondConfig {

	@Bean
    public SqlSessionFactory secondSqlSessionFactory(@Qualifier(DataSourceNames.SECOND)DataSource ds) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(ds);
        //指定mapper xml目录
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(resolver.getResources("classpath:mapper2/**/*Mapper.xml"));
        return factoryBean.getObject();

    }

    @Bean
    public SqlSessionTemplate secondSqlSessionTemplate(@Qualifier("secondSqlSessionFactory")SqlSessionFactory sf) throws Exception {
        SqlSessionTemplate template = new SqlSessionTemplate(sf); // 使用上面配置的Factory
        return template;
    }

    //关于事务管理器,不管是JPA还是JDBC等都实现自接口 PlatformTransactionManager
    // 如果你添加的是 spring-boot-starter-jdbc 依赖,框架会默认注入 DataSourceTransactionManager 实例。
    //在Spring容器中,我们手工注解@Bean 将被优先加载,框架不会重新实例化其他的 PlatformTransactionManager 实现类。
    /*@Bean(name = "transactionManager2")
    @Primary
    public DataSourceTransactionManager masterTransactionManager() {
        //MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的数据源
        // 与DataSourceTransactionManager引用的数据源一致即可,否则事务管理会不起作用。
        return new DataSourceTransactionManager(ds);
    }*/
}
package com.pinyu.system.global.config.datasource;

/**
 * @author ypp 创建时间:2018年11月6日 上午11:39:03
 * @Description: TODO(数据源常量池)
 */
public interface DataSourceNames {

	public static final String DEFAULT = "default";

	public static final String SECOND = "second";

}

启动类:

package com.pinyu.system;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.pinyu.system.global.config.datasource.DruidConfig;

@ComponentScan(basePackages = "com.pinyu.system")
@EnableTransactionManagement(proxyTargetClass = true)
//@SpringBootApplication(exclude={  
//		DataSourceAutoConfiguration.class,  
////		HibernateJpaAutoConfiguration.class, //(如果使用Hibernate时,需要加)  
//		DataSourceTransactionManagerAutoConfiguration.class  
//		})
@SpringBootApplication
@Import(DruidConfig.class)
public class Application extends SpringBootServletInitializer {

}

springboot 检测到jta atomikos环境时,会自动启用分布式事务,给相应的配置,以上配置也是自己摸索出来的,也不敢太深入讲解,怕说错。但亲测可用,多库使用事务也可以回滚。

猜你喜欢

转载自blog.csdn.net/ypp91zr/article/details/83988919
今日推荐