SpringBoot整合MYBATIS,多数据源,事务,支持JAVA -JAR 启动.
Posted 高因咖啡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot整合MYBATIS,多数据源,事务,支持JAVA -JAR 启动.相关的知识,希望对你有一定的参考价值。
用了一段时间SpringBoot,之前配置MYBATIS ,在打包WAR 放到tomcat下正常,但是WAR已经过时了,现在流行直接打包JAR 丢到DOCKER 里,无奈JAR 启动的时候MAPPER 扫描有问题,只能说之前整合MYBATIS 的方式不对.
这次的整合应该是不存在加载顺序引起的问题,使用了一段时间,妥妥的,记录下来
pom.xml
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency>
application.yml,支持多个数据源,有多少就写多少个,但这是静态的多数据源方式,也可以动态往Spring的数据源路由里面丢
spring: datasource: # readSize: 1 # name: writeDataSource type: com.alibaba.druid.pool.DruidDataSource write: driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://localhost:3306/cloud?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&useSSL=true username: root password: 123 initialSize: 10 maxActive: 100 maxWait: 60000 minIdle: 5 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: SELECT ‘x‘ testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxPoolPreparedStatementPerConnectionSize: 20
DataSourceConfig.java
/** * Created by ZhenWeiLai on 2016/11/20. */ @Configuration @EnableTransactionManagement @MapperScan("com.lzw.**.dao")//mybatis扫描 public class DataSourceConfig implements TransactionManagementConfigurer { @Value("${spring.datasource.type}") private Class<? extends DataSource> dataSourceType; @Primary @Bean(name = "writeDataSource") @ConfigurationProperties(prefix = "spring.datasource.write") public DataSource writeDataSource() { return DataSourceBuilder.create().type(dataSourceType).build(); } /** * 有多少个从库就要配置多少个 * @return */ // @Bean(name = "readDataSource") // @ConfigurationProperties(prefix = "spring.datasource.read") // public DataSource readDataSourceOne() { // return DataSourceBuilder.create().type(dataSourceType).build(); // } /** * AbstractRoutingDataSource 这破玩意 继承了AbstractDataSource ,AbstractDataSource又实现了DataSource * 所以可以直接丢去构建 SqlSessionFactory * @return */ @Bean("routingDataSource") // @Bean(name="routingDataSource",initMethod = "init",destroyMethod = "close") public MyRoutingDataSource dataSourceProxy(){ // int size = Integer.parseInt(dataSourceSize); MyRoutingDataSource proxy = new MyRoutingDataSource(); Map<Object,Object> dataSourceMap = new HashMap<>(); DataSource writeSource = writeDataSource(); // DataSource readSource = getReadDataSource(); dataSourceMap.put(TargetDataSource.WRITE.getCode(),writeSource); // dataSourceMap.put(TargetDataSource.READ.getCode(),readSource); proxy.setDefaultTargetDataSource(dataSourceMap.get(TargetDataSource.WRITE.getCode())); proxy.setTargetDataSources(dataSourceMap); return proxy; } @Bean public SqlSessionFactory sqlSessionFactory() { SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); bean.setDataSource(dataSourceProxy()); bean.setTypeAliasesPackage("com.lzw"); bean.setVfs(SpringBootVFS.class); //添加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); } } /** * 事务配置,考虑多数据源情况下 * @return */ @Bean public PlatformTransactionManager txManager() { return new DataSourceTransactionManager(dataSourceProxy()); } @Override public PlatformTransactionManager annotationDrivenTransactionManager() { return txManager(); } }
MyRoutingDataSource.java
/** * Created by ZhenWeiLai on 2016/11/22. */ public class MyRoutingDataSource extends AbstractRoutingDataSource { /** * 这里可以做简单负载均衡,暂时用不上 */ // private int dataSourceOrder; // private AtomicInteger count = new AtomicInteger(0); public MyRoutingDataSource() { } // public MyRoutingDataSource(int _dataSourceOrder){ // this.dataSourceOrder = _dataSourceOrder; // } /** * 这个方法会根据返回的key去配置文件查找数据源 * * @return */ @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getTargetDataSource(); } }
TargetDataSource.java
/** * Created by ZhenWeiLai on 2016/11/22. * 配置读写分离或者多数据源 */ public enum TargetDataSource { WRITE("write","主库"), READ("read","从库"), CREATE("create","建库"); final private String code; final private String name; TargetDataSource(String _code,String _name) { this.code = _code; this.name = _name; } public String getCode() { return code; } public String getName(){ return name; } public static String getNameByCode(String _code){ for(TargetDataSource item : TargetDataSource.values()){ if(item.getCode().equals(_code)){ return item.getName(); } } return ""; } }
喜欢的话,可以使用AOP 注解切换数据源,但是要注意滥用AOP,加上全局统一AOP异常拦截,以及Spring AOP事务,顺序问题,处理不好可能会引起事务失效,或者异常拦截失效,也可能是数据源切换失效.
AOP事务如果先开启了,那么AOP切换数据源将无效
/** * Created by ZhenWeiLai on 2016/11/22. * 切换数据源的注解 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DataSourceSwitch { String targetDataSource() default ""; }
DataSourceContextHolder.java
/** * Created by ZhenWeiLai on 2016/11/22. * 多数据源/读写分离 */ public class DataSourceContextHolder { private static final ThreadLocal<String> dataSourceLocal = new ThreadLocal<>(); public static ThreadLocal<String> getDataSourceLocal() { return dataSourceLocal; } /** * 从库 可以有多个 */ public static void read() { dataSourceLocal.set(TargetDataSource.READ.getCode()); } /** * 主库 只有一个 */ public static void write() { dataSourceLocal.set(TargetDataSource.WRITE.getCode()); } public static String getTargetDataSource() { return dataSourceLocal.get(); } }
以上是关于SpringBoot整合MYBATIS,多数据源,事务,支持JAVA -JAR 启动.的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot-技术专区-Mybatis plus 实现多数据源整合
SpringBoot:4.SpringBoot整合Mybatis实现数据库访问