目录

  • 背景
  • springboot 配置文件
  • mybatis 配置文件
  • 编写jdbc配置类
  • 注意点
  • ServiceImpl
  • 总结


背景

公司项目需要用到多个数据源,因为数据来源于不同的系统,所以这里简单描述下 springboot多数据源如何配置与使用, 以及涉及到 多事务管理器如何配置与使用

springboot 配置文件

spring:
  datasource:
    bigdata:
      driver-class-name: com.mysql.jdbc.Driver
      url: yoururl
      username: username
      password: root
    jx:
      driver-class-name: com.mysql.jdbc.Driver
      url: yoururl
      username: username
      password: root

在yml配置文件中 填写好自己的两个数据源连接信息

mybatis 配置文件

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 全局参数 -->
    <settings>
        <!-- 打印SQL语句到控制台 -->
        <setting name="logImpl" value="STDOUT_LOGGING" />
        <!--<setting displayText="logImpl" value="NO_LOGGING" />-->

        <!-- 使全局的映射器启用或禁用缓存。 -->
        <setting name="cacheEnabled" value="true"/>

        <!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载。 -->
        <setting name="lazyLoadingEnabled" value="true"/>

        <!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载。 -->
        <setting name="aggressiveLazyLoading" value="true"/>

        <!-- 是否允许单条sql 返回多个数据集  (取决于驱动的兼容性) default:true -->
        <setting name="multipleResultSetsEnabled" value="true"/>

        <!-- 是否可以使用列的别名 (取决于驱动的兼容性) default:true -->
        <setting name="useColumnLabel" value="true"/>

        <!-- 允许JDBC 生成主键。需要驱动器支持。如果设为了true,这个设置将强制使用被生成的主键,有一些驱动器不兼容不过仍然可以执行。  default:false  -->
        <setting name="useGeneratedKeys" value="false"/>

        <!-- 指定 MyBatis 如何自动映射 数据基表的列 NONE:不隐射 PARTIAL:部分  FULL:全部  -->
        <setting name="autoMappingBehavior" value="PARTIAL"/>

        <!-- 这是默认的执行类型  (SIMPLE: 简单; REUSE: 执行器可能重复使用prepared statements语句;BATCH: 执行器可以重复执行语句和批量更新)  -->
        <setting name="defaultExecutorType" value="SIMPLE"/>

        <!-- 使用驼峰命名法转换字段。 -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>

        <!-- 设置本地缓存范围 session:就会有数据的共享  statement:语句范围 (这样就不会有数据的共享 ) defalut:session -->
        <setting name="localCacheScope" value="STATEMENT"/>

        <!-- 设置但JDBC类型为空时,某些驱动程序 要指定值,default:OTHER,插入空值时不需要指定类型 -->
        <setting name="jdbcTypeForNull" value="NULL"/>


    </settings>

    <plugins>
        <plugin interceptor="com.github.pagehelper.PageHelper">
            <property name="dialect" value="mysql"/>
            <property name="supportMethodsArguments" value="true"/>
            <property name="params" value="pageNum=pageNumKey;pageSize=pageSizeKey;"/>
        </plugin>
    </plugins>
    
</configuration>
  • settings 里面包含了一些简单的设置 ,这些设置基本写了注释,可以详细看下,可以选择性加一些
  • plugins 里面加入了 分页插件,用的是 github开源的插件, 挺好用的,也可以自己写。 自己的写的话可以增加一些特性啥的,具体可以百度,不再赘诉。

编写jdbc配置类

这里为了便于识别,将两个数据源的配置放在了两个configure中

@Configuration
@MapperScan(basePackages = BigdataDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "bigdataSqlSessionFactory")
public class BigdataDataSourceConfig {

    static final String PACKAGE = "xxxxxxxx";
    static final String MAPPER_LOCATION = "xxxxxxxx";

    @Value("${spring.datasource.bigdata.url}")
    private String url;

    @Value("${spring.datasource.bigdata.username}")
    private String user;

    @Value("${spring.datasource.bigdata.password}")
    private String password;

    @Value("${spring.datasource.bigdata.driver-class-name}")
    private String driverClass;

    @Value("${mybatis.config-location}")
    private String configLocation;

    @Value("${mybatis.mapper-locations}")
    private String mapperLocations;

    @Value("${mybatis.type-aliases-package}")
    private String typeAliasesPackage;

    @Bean(name = "bigdataDataSource")
    @Primary
    public DataSource bigdataDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(url);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        return dataSource;
    }

    @Bean(name = "bigdataTransactionManager")
    @Primary
    public DataSourceTransactionManager bigdataTransactionManager() {
        return new DataSourceTransactionManager(bigdataDataSource());
    }

    @Bean(name = "bigdataSqlSessionFactory")
    @Primary
    public SqlSessionFactory bigdataSqlSessionFactory(@Qualifier("bigdataDataSource") DataSource bigdataDataSource)
            throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();

        sessionFactory.setDataSource(bigdataDataSource);
        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources(BigdataDataSourceConfig.MAPPER_LOCATION));

        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        //设置 mybatis配置, 不然mybatis配置文件里面配置的东西无法生效
        sessionFactory.setConfigLocation(resolver.getResource(configLocation));
        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);

        return sessionFactory.getObject();
    }
}
注意点
  1. PACKAGE : *mapper.java 类所在的包路径
  2. MAPPER_LOCATION : *mapper.xml 所在的包路径 我这里是 classpath:mapper/bigdata/*.xml
  3. sessionFactory.setConfigLocation(resolver.getResource(configLocation)); 加载 自己编写的mybatis 配置类,不然设置的那些参数,以及分页插件不会生效。 (比如 *mapper.xml 查询结果不会自动将下划线转驼峰并映射到 java entity类的字段上, 一般出现这种情况,要么就是 mybatis-config.xml 里面settings没有设置该项, 要么就是没有加载到 mybatis配置文件)
  4. @Bean(name = "bigdataTransactionManager") 这里是设置这个数据源的 事务管理器, 所有通过该数据源的数据库动作都归于这个名字叫“bigdataTransactionManager”的事务管理器

另一个数据源配置类就不贴出来了,基本配置一样 ,但是需要将数据源名称修改一下,然后上述四个注意点也需要按实际情况进行修改。

ServiceImpl

在ServiceImpl文件 中,我们需要使用 @Transcational() 注解来使用 事务管理器。
但是我们实际上注册了两个, 如果不指定事务管理器的, springboot是不知道该使用那个的。
不过我们在注册的时候,在 @Bean(name = "bigdataTransactionManager"), 这一行下面使用了 @Primary 注解。
所以我们的spring会默认使用 bigdataTransactionManager 这个事务管理器。
如果当你需要用到 另一个事务管理器的时候,你需要在你的 @Transcational 注解中指定事务管理器名称
ps: 可以使用在方法上,也可以加在 serviceImpl文件最上方

@Transactional(readOnly = true, transactionManager = "primaryTxxxxxxxxxxx")
@Transactional(readOnly = true, transactionManager = "anotherTxxxxxxxxxx")

总结

Springboot帮我们做了很多事情, 但是其实明白里面的设计还是比较重要的, 至少你从0搭建一个代码框架的时候不会有太多问题。
记录一下自己的问题,也希望能够帮助到正在学习的各位