springboot添加多数据源链接池并配置Mybatis

springboot添加多数据源链接池并配置Mybatishtml

转载请注明出处:http://www.javashuo.com/article/p-vfpnmrep-e.htmljava

    May 12, 2018  星期六,那是个晴天,天湛蓝湛蓝的很是干净,仿佛飘过一粒尘埃也能看得清清楚楚,而后就发生了些事情。。。很伤心很难过,至今也没能抹去,欸,我是怎样一步步把本身变成这个样子呢。mysql

    难过的事情总会在萦绕好久,罢了,这里仍是不回忆了,就这样吧。git

    首先我说说此次配置多数据源的缘由吧:缘由大体有二:github

一是咱们的线上的有两大业务系统云像系统和线上交易系统,这两个系统的分别使用各自的mysql实例,交合业务的状况下目前经过定时脚本作数据更新和同步,遂在开发新的业务模块的时候就想到了将springboot配置两个数据源(mysql和mysql)spring

二是最近在改造数据库日志表的时候发现mysql的优化捉襟见肘,遂就想到了换数据库,换个我我的研究了许久的PostgreSQL,老大一开始不怎么乐意这么干,可是看我又研究了这么久,性能也确实较mysql高许多,再加上公司技术团队并非很大的状况下(主要是业务量上去了数据库性能跟不上,也没有独立的DBA来维护和调优Mysql),就给了我一周的时间研究数据库(下次具体聊),故就涉及到两个数据源(mysql和PostgreSQL)的问题。sql

    嗯,对于以上两个问题,我尝试了差别化的解决方式,对于mysl和mysql数据源我选择的是 阿里Druid+TK.Mybatis的解决方式,对于mysql和PG数据源我选择的是Hikari+TK.Mybatis的解决方式.这两种方式在实际配置中是有些许差别的,这里我略去不讲,只讲第二种,首先罗列下这其中碰到的问题:数据库

      A>DataSource和SessionFactory引用指定注入问题。apache

      B>Hikari数据源配置参数名称差别问题。springboot

      C>Springboot init时配置类前后顺序的问题

      D>多数据源下Mybatis Mapper类重复问题

    我先讲讲我大体的配置过程吧,首先新创建两个配置类,以隔离开(刚在一个包 中不隔离开也能够):

而后在两个包中分别新建两个配置类,一个是MyBatis配置类和数据源、session工厂配置类,我这里是这样子:

这时候,我先展现下数据源配置类:

 1 package **.task.config.mysql;  2 
 3 
 4 import com.github.pagehelper.PageHelper;  5 import com.zaxxer.hikari.HikariConfig;  6 import com.zaxxer.hikari.HikariDataSource;  7 import org.apache.commons.lang3.StringUtils;  8 import org.apache.ibatis.plugin.Interceptor;  9 import org.apache.ibatis.session.SqlSessionFactory; 10 import org.mybatis.spring.SqlSessionFactoryBean; 11 import org.mybatis.spring.SqlSessionTemplate; 12 import org.springframework.beans.factory.annotation.Qualifier; 13 import org.springframework.beans.factory.annotation.Value; 14 import org.springframework.boot.context.properties.ConfigurationProperties; 15 import org.springframework.context.annotation.Bean; 16 import org.springframework.context.annotation.Configuration; 17 import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 18 import org.springframework.core.io.support.ResourcePatternResolver; 19 import org.springframework.jdbc.datasource.DataSourceTransactionManager; 20 import org.springframework.transaction.annotation.EnableTransactionManagement; 21 
22 import javax.sql.DataSource; 23 import java.sql.SQLException; 24 import java.util.Properties; 25 
26 /**
27  * mybatis 配置数据源类 28  * 29  * @author
30  * @date 2016年12月15日 31  * @since 1.7 32  */
33 @Configuration("mysqlCfg") 34 @EnableTransactionManagement 35 @ConfigurationProperties(prefix = "spring.db_mysql") //引用配置文件参数前缀 36 public class MybatisConfiguration extends HikariConfig { 37     @Value("${mybatis.mysql.xmlLocation}") 38     private String xmlLocation; 39 
40     private String typeAliasesPackage; 41   //配置数据源
42     @Bean("mysqlDataSource") 43     public DataSource dataSource(){ 44         /*
45  HikariDataSource ds=HikariDataSource(); 46  ds.setJdbcUrl(); 47  ds.setConnectionTimeout(); 48         */
49         return new HikariDataSource(this); 50  } 51   //配置Session工厂
52     @Bean(name = "mysqlSqlSessionFactory") 53     public SqlSessionFactory sqlSessionFactoryBean(@Qualifier("mysqlDataSource")DataSource dataSource) { 54         SqlSessionFactoryBean bean = new SqlSessionFactoryBean(); 55  bean.setDataSource(dataSource); 56         if(StringUtils.isNotBlank(typeAliasesPackage)){ 57  bean.setTypeAliasesPackage(typeAliasesPackage); 58  } 59         //分页插件
60         PageHelper pageHelper = new PageHelper(); 61         Properties properties = new Properties(); 62         properties.setProperty("reasonable", "true"); 63         properties.setProperty("supportMethodsArguments", "true"); 64         properties.setProperty("returnPageInfo", "check"); 65         properties.setProperty("params", "count=countSql"); 66  pageHelper.setProperties(properties); 67         //添加XML目录
68         ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); 69         Interceptor[] plugins =  new Interceptor[]{pageHelper}; 70  bean.setPlugins(plugins); 71         try { 72 
73  bean.setMapperLocations(resolver.getResources(xmlLocation)); 74             return bean.getObject(); 75         } catch (Exception e) { 76  e.printStackTrace(); 77             throw new RuntimeException(e); 78  } 79  } 80   //mybatis会用到的SqlSession模板
81  @Bean 82     public SqlSessionTemplate sqlSessionTemplate(@Qualifier("mysqlSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { 83         return new SqlSessionTemplate(sqlSessionFactory); 84  } 85   //数据源事物配置
86  @Bean 87     public DataSourceTransactionManager transactionManager(@Qualifier("mysqlDataSource") DataSource dataSource) { 88         return new DataSourceTransactionManager(dataSource); 89  } 90 
91 }

在这里须要说明的是我经过继承HikariConfig来配置数据源以及Session工厂,配置DataSource和Session工厂的时候须要使用指定注解名称,在这里是“mysqlDataSource“和”mysqlSqlSessionFactory“,若是项目只有一个数据源的话大可没必要写这个的,另外须要特别注意的是在配置session工厂必定要在形式参数前使用@Qualifier注解引用指定的数据源,同时SqlSession模板和事物也须要经过@Qualifier注解指定session工厂和数据源,这里这样作的缘由是为了解决多数据源配置引用不明的问题。

  OK,数据源配置完成了,如今将配置第二个配置类Mybatis配置类,如下是具体配置内容:

 1 package **.task.config.mysql;
 2 
 3 import org.springframework.boot.autoconfigure.AutoConfigureAfter;
 4 import org.springframework.boot.bind.RelaxedPropertyResolver;
 5 import org.springframework.context.EnvironmentAware;
 6 import org.springframework.context.annotation.Bean;
 7 import org.springframework.context.annotation.Configuration;
 8 import org.springframework.core.env.Environment;
 9 import tk.mybatis.spring.mapper.MapperScannerConfigurer;
10 
11 /**
12  * mybatis mapper 扫描配置类
13  *
14  * @author
15  * @date 2018年05月15日
16  */
17 @Configuration("mysqlMapper")
18 @AutoConfigureAfter(MybatisConfiguration.class)//init时指定前后顺序,这里是数据源在mybatis以前配置
19 public class MapperConfiguration implements EnvironmentAware {
20 
21     private RelaxedPropertyResolver propertyResolver;
22 
23     private String basePackage;
24     //这里为mybatis配置指定session工厂和Dao类基础包路径
25     @Bean("mysqlMapperScannerConfigurer")
26     public MapperScannerConfigurer mapperScannerConfigurer(Environment environment){
27 
28         MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
29         mapperScannerConfigurer.setSqlSessionFactoryBeanName("mysqlSqlSessionFactory");
30         mapperScannerConfigurer.setBasePackage(basePackage);
31         return mapperScannerConfigurer;
32     }
33 
34    //设置环境变量(引用配置文件中的)
35     @Override
36     public void setEnvironment(Environment environment) {
37         this.propertyResolver = new RelaxedPropertyResolver(environment, null);
38         this.basePackage = propertyResolver.getProperty("mybatis.mysql.basepackage");
39     }
40 }

配置Mybaits的时候须要将数据源配置置于以后配置,这里经过注解@AutoConfigureAfter来指定数据源配置类,在配置Mybatis引用的Session工厂时也要指定为数据源配置类中的sqlSession工厂,同时也须要指定生成的Mapper的包名,这个包的路径这里我写在application.yml的配置文件中。

  配置类已经写完,如今最后一步了,在配置文件中指定配置类所引用的配置参数,大体是这样子:

spring:
    application:
        name: **-task
    jackson:
        date-format: yyyy-MM-dd HH:mm:ss
        time-zone: GMT+8
        default-property-inclusion: non_null
    db_mysql:
        name: DEV_MYSQL

        #LOCAL
        jdbc-url: jdbc:mysql://${MYSQL_HOST:192.168.10.141}:${MYSQL_PORT:3306}/p2p?useUnicode=true&characterEncoding=UTF8
        driver-class-name: com.mysql.jdbc.Driver
        username: p2p
        password: p2p

        # Hikari connection pool
        type: com.zaxxer.hikari.HikariDataSource
        minimum-idle: 5
        maximum-pool-size:  15
        auto-commit:  true
        idle-timeout: 30000
        pool-name:  DatebookHikariCP
        max-lifetime: 1800000
        connection-timeout: 30000
        connection-test-query:  SELECT 1
        validation-timeout: 10000
    db_pg:
        name: DEV_PG

        # JDBC config
        jdbc-url:  jdbc:postgresql://192.168.10.141:5432/log
        driver-class-name:  org.postgresql.Driver
        username: log
        password: log

        # Hikari connection pool
        type: com.zaxxer.hikari.HikariDataSource
        minimum-idle: 5
        maximum-pool-size:  15
        auto-commit:  true
        idle-timeout: 30000
        pool-name:  DatebookHikariCP
        max-lifetime: 1800000
        connection-timeout: 30000
        connection-test-query:  SELECT 1
        validation-timeout: 10000

以上配置文件中主要展现了数据源的一些配置(注意db_mysqldb_pg这两项),这里须要特别注意的是在Hikari数据源的配置参数中没有url和driverClass,只有jdbc-urldriver-class-name这两个,其它的配置配置参数名称与c3p0和Druid的无异,具体的链接池大小须要根据实际的项目和数据库服务器的硬件参数来配置,这里我只给出常见配置。

  哦,对了,还须要在配置文件中追加Mybatis的配置参数,具体是这样:

1 mybatis:
2     mysql:
3         basepackage: **.task.mapper.mysql
4         xmlLocation: classpath:mapper/mysql/*.xml
5     pg:
6         basepackage: **.task.mapper.pg
7         xmlLocation: classpath:mapper/pg/*.xml

  Mybatis的配置完成了,对于PostgreSQL的配置只须要注意响应的配置别名便可(好比数据源、session工厂、SqlSession工厂等等)

  本节所讲的配置貌似已经完成,可是这里我顺带讲一下我在性能测试的时候所碰见的两个TK.mybatis这个插件的问题(原生mybatis也可能存在):

    A>对于两个库中存在同名的Mapper名字,在@Autowired使用时会产生冲突

    B>持久化须要返回主键时对于mysql和PG两中数据库的处理方式存在差别

  对于以上第一个问题(多数据源Mapper冲突),我给出的解决方式是在生成的Mapper类中指定冲突的那个Mapper的Service别名,这样:

1 package **.task.mapper.pg;
2 
3 import com.github.carvechris.security.task.entity.pg.TestEmp;
4 import org.springframework.stereotype.Service;
5 import tk.mybatis.mapper.common.Mapper;
6 
7 @Service("pgTestEmpMapper")//这里指定别名
8 public interface TestEmpMapper extends Mapper<TestEmp> {
9 }

这个Dao在使用的时候须要使用@Resource注解来指定的Dao类:

1  @Autowired 2     @Resource(name = "pgTestEmpMapper") 3     private **.task.mapper.pg.TestEmpMapper pgEmpMapper;

  

  对于以上第二个问题(持久化返回主键问题),mysql和pg的处理方式不一样,具体为:

对于mysql须要在实体类中指定主键的生成方式,便可在调用insert方法时返回生成的主键:

    /**
     * 表ID
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//设置为主键自增以回写主键
    private Integer id;

以上的主键策略能够是主键表,也能够是UUID的方式,根据项目实际需求而定。

对于PG:首先须要在实体类的主键中这样声明

    /**
     * 表ID
     */
    @Id
    @Column(insertable=false)//指定主键为数据库生成(同时须要在DB中将ID声明为serial类型)
    private Long id;

在Dao(生成的Mapper类中)声明一个独立的查入方法

 1 package **.task.mapper.pg;
 2 
 3 import **.task.entity.pg.ZwPlBalancequery;
 4 import org.apache.ibatis.annotations.InsertProvider;
 5 import org.a2018-06-16pache.ibatis.annotations.Options;
 6 import org.apache.ibatis.annotations.Select;
 7 import tk.mybatis.mapper.common.Mapper;
 8 import tk.mybatis.mapper.provider.base.BaseInsertProvider;
 9 
10 public interface ZwPlBalancequeryMapper extends Mapper<ZwPlBalancequery> {
11     //须要须要独立声明插入方法以返回插入记录的ID      
12     @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
13     @InsertProvider(type = BaseInsertProvider.class, method = "dynamicSQL")
14     int insertWBack(ZwPlBalancequery record);
15 }

以上插入方法(insertWBack)中的注解是将id的生成方式改成数据库生成,至此,完美解决持久化返回记录ID问题。

如今是  2018-06-16 17:40:42 ,后天就是端午节了,预祝各位节日快乐!

相关文章
相关标签/搜索