Springboot+mybatisPlusのマルチデータソースのトランザクション
14010 ワード
Springbootは箱を開けてすぐに使うのは多くありませんが、mybatisplusの強力な持続層プラグインは、キーでコードを生成します.両者の結合は開発効率を大幅に向上させることができる.しかし、最初に学んだマルチデータ・ソースとマルチデータ・ソースのトランザクションの処理には、頭が痛くなる可能性があります.本稿ではmybatis-plusのマルチデータソースのトランザクション問題に焦点を当てて、いくつかのリファレンスソリューションを提供します.
datasource.ymlファイル構成
application.yml構成
DataSourceConfiguration.java
DataSourceContextHolder.java
DataSourceType.java
MyAbstractRoutingDataSource.java
MybatisPlusConfig.java
DataSourceAop.java
記事の参考:http://www.cnblogs.com/sweetchildomine/p/6977987.html http://www.cnblogs.com/softidea/p/7127874.html
datasource.ymlファイル構成
spring:
user_center:
url: jdbc:mysql://192.168.1.2:3306/a?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
center_user:
url: jdbc:mysql://192.168.1.2:3306/b?rewriteBatchedStatements=true&useUnicode=true&characterEncoding=UTF-8
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
application.yml構成
spring:
application:
name: auth-service
profiles.active: dev
aop:
proxy-target-class: true
auto: true
server:
port: 18601
mybatis:
type-aliases-package: com.br.auth.entity.*
mapper-locations: classpath:mapper/*/*.xml
#logging
logging:
level: warn
DataSourceConfiguration.java
package com.br.auth.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
/**
* Created by jack-cooper on 2017/1/18.
*/
@Configuration
@EnableTransactionManagement
public class DataSourceConfiguration implements TransactionManagementConfigurer {
private static final Logger log = LoggerFactory.getLogger(DataSourceConfiguration.class);
@Value("${spring.center_user.type}")
private Class extends DataSource> dataSourceType;
@Bean(name = "centerUserDataSource", destroyMethod = "close", initMethod = "init")
@Primary
@ConfigurationProperties(prefix = "spring.center_user")
public DataSource centerUserDataSourceOne() {
log.info("-------------------- - init ---------------------");
return DataSourceBuilder.create().type(dataSourceType).build();
}
@Bean(name = "userCenterDataSource", destroyMethod = "close", initMethod="init")
@ConfigurationProperties(prefix = "spring.user_center")
public DataSource userCenterDataSourceOne() {
log.info("-------------------- init ---------------------");
return DataSourceBuilder.create().type(dataSourceType).build();
}
@Bean("dataSources")
public Map dataSources(){
Map dataSources = new HashMap<>();
dataSources.put(DataSourceType.center_user.getType(), centerUserDataSourceOne());
dataSources.put(DataSourceType.user_center.getType(),userCenterDataSourceOne());
return dataSources;
}
/**
* bean
*
* @return
*/
@Bean(name = "routingDataSource")
public MyAbstractRoutingDataSource roundRobinDataSouceProxy() {
int size = Integer.parseInt("1");
MyAbstractRoutingDataSource proxy = new MyAbstractRoutingDataSource(size);
Map
DataSourceContextHolder.java
package com.br.auth.config;
/**
* Created by jack-cooper on 2017/1/18.
*/
public class DataSourceContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal();
/**
* setDataSourceType
* @param dataSourceType
*/
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return contextHolder.get();
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
DataSourceType.java
package com.br.auth.config;
/**
* Created by jack-cooper on 2017/1/18.
*/
public enum DataSourceType {
user("user", " "),
order("order", " - ");
private String type;
private String name;
DataSourceType(String type, String name) {
this.type = type;
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
MyAbstractRoutingDataSource.java
package com.br.auth.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by jack-cooper on 2017/1/18.
*/
public class MyAbstractRoutingDataSource extends AbstractRoutingDataSource {
private final int dataSourceNumber;
private AtomicInteger count = new AtomicInteger(0);
public MyAbstractRoutingDataSource(int dataSourceNumber) {
this.dataSourceNumber = dataSourceNumber;
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
MybatisPlusConfig.java
package com.br.auth.config;
import com.baomidou.mybatisplus.MybatisConfiguration;
import com.baomidou.mybatisplus.MybatisXMLLanguageDriver;
import com.baomidou.mybatisplus.entity.GlobalConfiguration;
import com.baomidou.mybatisplus.enums.DBType;
import com.baomidou.mybatisplus.enums.FieldStrategy;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import com.br.auth.util.PropertiesUtil;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.plugin.Interceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import javax.sql.DataSource;
/**
* @author 10400
* @create 2017-07-03 11:28
*/
@Configuration
@Import({DataSourceConfiguration.class})
@MapperScan("com.br.auth.mapper.*")
@EnableTransactionManagement
public class MybatisPlusConfig {
@Autowired(required = false)
private Interceptor[] interceptors;
@Autowired
private ResourceLoader resourceLoader = new DefaultResourceLoader();
@Value("${spring.user.type}")
private Class extends DataSource> dataSourceType;
@Autowired(required = false)
private MybatisProperties properties;
@Autowired(required = false)
private DatabaseIdProvider databaseIdProvider;
@Autowired(required = false)
private PropertiesBean propertiesBean;
@Resource(name = "routingDataSource")
private AbstractRoutingDataSource routingDataSource;
/**
* mybatis-plus
* :http://mp.baomidou.com
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* mybatis-autoconfigure 。
* mybatis-boot
*
* @return
*/
@Bean
public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean() throws Exception {
PropertiesUtil.setProperties(propertiesBean.getPropertiesBean());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
MybatisSqlSessionFactoryBean mybatisPlus = new MybatisSqlSessionFactoryBean();
mybatisPlus.setDataSource(routingDataSource);
mybatisPlus.setVfs(SpringBootVFS.class);
if (StringUtils.hasText(this.properties.getConfigLocation())) {
mybatisPlus.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
}
mybatisPlus.setConfiguration(properties.getConfiguration());
if (!ObjectUtils.isEmpty(this.interceptors)) {
mybatisPlus.setPlugins(this.interceptors);
}
// MP ,
GlobalConfiguration globalConfig = new GlobalConfiguration();
globalConfig.setDbType(DBType.MYSQL.name());
// ID AUTO->`0`(" ID ") INPUT->`1`( ID") ID_WORKER->`2`(" ID") UUID->`3`(" ID")
globalConfig.setIdType(0);
globalConfig.setFieldStrategy(FieldStrategy.NOT_EMPTY.getKey());
mybatisPlus.setGlobalConfig(globalConfig);
MybatisConfiguration mc = new MybatisConfiguration();
mc.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);
//mapUnderscoreToCamelCase: ( first_name => firstName)
mc.setMapUnderscoreToCamelCase(false);
mybatisPlus.setConfiguration(mc);
if (this.databaseIdProvider != null) {
mybatisPlus.setDatabaseIdProvider(this.databaseIdProvider);
}
if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
mybatisPlus.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
}
if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
mybatisPlus.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
}
if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
mybatisPlus.setMapperLocations(this.properties.resolveMapperLocations());
}
return mybatisPlus;
}
}
DataSourceAop.java
package com.br.auth.config;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* desc:
* Created by jack-cooper on 2017/1/18.
*/
@Aspect
@Order(-1)
@Component
public class DataSourceAop {
Logger log = LoggerFactory.getLogger(this.getClass());
@Before("execution(* com.br.auth.service.centerUser..*.*(..))")
public void setCenterUserDataSourceType() throws Exception {
DataSourceContextHolder.setDataSourceType(DataSourceType.center_user.getType());
log.info("dataSource == >: centerUser");
}
@Before("execution(* com.br.auth.service.userCenter..*.*(..))")
public void setUserCenterDataSourceType() throws Throwable{
DataSourceContextHolder.setDataSourceType(DataSourceType.user_center.getType());
log.info("dataSource == >:userCenter");
}
@After("execution(* com.br.auth.service.*..*.*(..)) ")
public void afterReturning() throws Throwable {
DataSourceContextHolder.clearDataSourceType();
log.info("=====> clear dataSource aop ");
}
}
記事の参考:http://www.cnblogs.com/sweetchildomine/p/6977987.html http://www.cnblogs.com/softidea/p/7127874.html