case mybatis 不同表_SpringBoot2 整合 Mybatis 多数据源流程

本文介绍了在SpringBoot2项目中整合Mybatis并接入多数据源的详细流程,包括测试数据准备、pom依赖、yml配置、数据源配置、mapper和服务与控制器的编写。同时分享了在配置过程中遇到的坑,如Mybatis配置不生效和YML中数据源配置的注意事项。提供了完整的解决方案和参考文章。
摘要由CSDN通过智能技术生成

最近在搭建项目的框架,使用的是 SpringBoot 跟 Mybatis,并接入了多数据源。这里总结一下整合的流程以及踩过的坑。你亦可到 github 上查看我的工程代码:springboot-mybatis-multidatabase。

SpringBoot2 整合 Mybatis,接入多数据源流程

01 测试数据

在本地测试,我使用了 MySQL,创建 test_db1 / test_db2 两个数据库,分别新建一张测试表来模拟多数据源的接入。数据如下:

我的工程代码链接:springboot-mybatis-multidatabase,你也可以从中获取我使用的数据脚本。

a0c3ddb633e53b5f727ed789f6876b6c.png

3e8a964d9cbcc28033e7317fc6aad827.png

02 pom 依赖

我们新建 SpringBoot 项目(你可在 https://start.spring.io 自动创建,或使用 IDEA 等 IDE 来辅助创建,不在此详述),先来看看 pom 文件的依赖。我是基于 SpringBoot2 来操作的,具体使用到的版本为 2.1.8.RELEASE。

此外使用到 MySQL 数据库,lombok 插件,swagger 调用测试接口来校验结果:

实际使用中,下面介绍的方法也测试过 MySQL 与 PostgreSQL 混用,同样正常运行。若接入其他数据库,需在 pom 中接入相应的依赖。
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
    <relativePath /> <!-- lookup parent from repository -->
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>1.3.2</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <version>2.9.2</version>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger-ui</artifactId>
        <version>2.9.2</version>
    </dependency>
</dependencies>

03 yml 配置

我使用了 yml 配置文件格式,在这里,有三部分的配置

  1. database 数据源信息;
  2. Mybatis 配置。这里每个数据源单独配置了一份 Mybatis 的配置信息,后续会说明这样做的原因;
  3. 服务暴露的端口
mybatis:
  configuration:
    db1:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      map-underscore-to-camel-case: true
    db2:
      log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      map-underscore-to-camel-case: true

spring:
  datasource:
    db1:
      jdbc-url: jdbc:mysql://localhost:3306/test_db1
      username: your username
      password: your password
      driver-class-name: com.mysql.jdbc.Driver
    db2:
      jdbc-url: jdbc:mysql://localhost:3306/test_db2
      username: your username
      password: your password
      driver-class-name: com.mysql.jdbc.Driver

server:
  port: 8090

04 数据源配置

当在 SpringBoot 配置文件中创建多个数据源的配置时,若使用 Mybatis,mapper 是不能自动识别哪个 mapper 该基于哪个数据源连接的。这里我们的关键是需要为 mapper 指定使用的数据源

根据我的调研,有几种指定的思路,例如使用 AOP,或者本文介绍的,显式指定不同 mapper 使用不同的数据源

新建 Db1MybatisConfig.java,使用 @Configuration 指定为 Spring 的配置文件。接着,我们使用 @MapperScan 来指定,该份配置文件需要扫描哪些包(basePackages 参数),以及所扫描的包,使用哪份模板文件来与数据库操作(sqlSessionTemplateRef 参数)。

@Configuration
@MapperScan(basePackages = "com.example.demo.mapper.db1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class Db1MybatisConfig {
    ...
}

当指定了这两个参数,我们只要进一步的,让当前使用的模板文件与特定的数据库连接,便可实现特定包下的 mapper 与特定数据源连接

1. 特定数据源 —> 2. 特定 sqlSessionTemplate —> 3. 特定包目录 —> 4. 特定 mapper

@MapperScan 实现了 3 -> 4 步骤的过程,剩下的 1 ->2 步骤需要在上述配置类中实现,详见下方代码:

@Bean(name = "db1DataSource")
@ConfigurationProperties(prefix = "spring.datasource.db1") // 读取yml数据源配置,自动注入到DataSource
@Primary // 注意若配置了多数据源,需要使用@Parimary显式指定一个主数据源,其余数据源不需再配置该注解
public DataSource db1DataSource() {
    return DataSourceBuilder.create().build();
}

@Bean(name = "db1Config")
@ConfigurationProperties(prefix = "mybatis.configuration.db1") // 读取yml Mybatis配置,自动注入到Configuration
@Primary
public org.apache.ibatis.session.Configuration db1MybatisConfig() {
    return new org.apache.ibatis.session.Configuration();
}

@Bean(name = "db1SqlSessionFactory")
@Primary
public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource,
                                              @Qualifier("db1Config") org.apache.ibatis.session.Configuration config)
        throws Exception {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    bean.setConfiguration(config); // 多数据源需要在各自的SessionFactory中设置配置Mybatis属性
    bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/db1/*.xml"));
    return bean.getObject();
}

@Bean(name = "db1TransactionManager")
@Primary
public DataSourceTransactionManager db1TransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

@Bean(name = "db1SqlSessionTemplate")
@Primary
public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
    return new SqlSessionTemplate(sqlSessionFactory);
}
  1. 首先使用 @ConfigurationProperties 获取 yml 文件中,我们配置的数据源信息,自动注入到 DataSource 对象;
  2. 与 1 类似,使用 @ConfigurationProperties 获取 yml 中特定数据源的 Mybatis 配置信息,自动注入到 Configuration 对象;
  3. 准备好上述数据后,进一步手动封装 SqlSessionFactory,再由其生成对应的 SqlSessionTemplate,并使用该数据源来进行事务管理 DataSourceTransactionManager。

至此我们便绑定了特定数据源到特定的 SqlSessionTemplate,进而实现了特定包目录下的 mapper 文件,通过对应绑定的 SqlSessionTemplate 来操作特定的数据源。

05 编写代码测试

mapper

由于在数据源配置文件中绑定了特定的包目录,因此,我们有

  1. 若想操作 db1 数据源,mapper 接口只可置于配置文件中绑定的 com.example.demo.mapper.db1 目录;
  2. 若想操作 db2 数据源,mapper 接口只可置于配置文件中绑定的 com.example.demo.mapper.db2 目录。

我们在 db1 目录中新建 StudentMapper.java 来进行测试:

因为已在配置文件中指定了目录,因此 mapper 接口不需再使用 @Mapper。
public interface StudentMapper {

    List<Student> listStudent();

    Student findStudentById(@Param("id") Integer id);
}

接下来使用 XML 文件编写具体的 SQL,XML 文件的位置没有具体要求,看自己如何方便管理,例如我便类似的新建了 resource/mapper/db1 目录放置 db1 的 mapper 接口 XML 文件。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.db1.StudentMapper">
    <sql id="column_list">id, name, age, create_time, update_time</sql>

    <select id="listStudent" resultType="com.example.demo.model.Student">
        select <include refid="column_list"/> from student
    </select>

    <select id="findStudentById" resultType="com.example.demo.model.Student">
        select <include refid="column_list"/> from student where id = #{id}
    </select>
</mapper>

service 与 controller

编写完 mapper,剩下的 service 与 controller 便没有特别:

@Service
public class StudentService {
    @Resource
    private StudentMapper studentMapper;

    public List<Student> listStudent() {
        return studentMapper.listStudent();
    }
    public Student getStudentById(Integer id) {
        return studentMapper.findStudentById(id);
    }
}
service 我直接编写实现类,而不是编写接口,针对接口编程。
@RestController
@RequestMapping("/api/test/")
public class TestController {

    @Autowired
    private StudentService studentService;

    @ApiOperation("根据id查询学生信息")
    @GetMapping("/student/{id}")
    public String getStudent(@PathVariable("id") Integer id) {
        Student student = studentService.getStudentById(id);
        return student == null ? "no data." : student.toString();
    }

    @ApiOperation("查询学生列表")
    @GetMapping("/student/list")
    public String students() {
        List<Student> students = studentService.listStudent();
        return CollectionUtils.isEmpty(students) ? "no data." : students.toString();
    }
}
@ApiOperation 是 swagger 的注解,启动项目后 swagger 可自动将接口生成文档,同时也可模拟接口调用。这里我将使用 swagger 来测试接口。

06 结果

到这里代码编写完毕。启动项目,打开 http://localhost:8090/swagger-ui.html,可看到 swagger 自动生成的接口文档,我们进行测试调用 /api/test/student/1,获取数据与数据库一致。

a29b9232e071e2700268234db178be72.png

同样,根据该思路我们编写另一数据源 db2 的相应代码,最后测试调用 /api/test/category/1,亦正常获取到数据

c7bc443597afcf5f07beda998ab3450c.png

踩过的坑

01 使用数据源配置文件后,Mybatis 配置不生效

配置了多数据源后,一开始 Mybatis 的 yml 配置(mybatis.configuration)是不生效的,例如我们上面配置的下划线转驼峰。

这是因为数据源的 Mybatis 配置信息在 SqlSessionFactory 中生成,而我们是自定义了该工厂的生成,此时,Spring 没有将 yml 中的 Mybatis 配置信息放入到 SqlSessionFactory 中,因此在上面的配置类代码中,我们需要显式使用 @ConfigurationProperties(prefix = "mybatis.configuration.db1") 加载特定数据源的 Mybatis 配置。

02 yml 中 Mybatis 数据源配置要分别配置

不同数据源需要分别配置,这是因为一个配置只能加载到一个 bean 中,上面两个数据源需要分别编写配置类,因此单一 bean 是满足不了的。

另外,我们很可能会遇到不同数据源,Mybatis 配置不同的情况,这也需要我们将不同数据源的 Mybatis 配置分别设置。

而对于不同环境,我们编写多份 yml 配置文件,不同文件里的 Mybatis 配置也可不相同,满足不同的具体需求。

参考文章

Spring Boot(七):Mybatis 多数据源最简解决方案
SpringBoot中mybatis配置自动转换驼峰标识没有生效 - 剑握在手 - 博客园
mybatis - MyBatis 3

END

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值