spring boot+mybatis+druid 多資料來源多庫分散式事務
阿新 • • 發佈:2018-12-11
廢話不多說,首先貼配置檔案,需要引入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:
[email protected] 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環境時,會自動啟用分散式事務,給相應的配置,以上配置也是自己摸索出來的,也不敢太深入講解,怕說錯。但親測可用,多庫使用事務也可以回滾。