简介
上篇讲解了 JPA 多数据源实现;这篇讲解一下 Mybatis 多数据源实现 。主要采用将不同数据库的 Mapper 接口分别存放到不同的 package,Spring 去扫描不同的包,注入不同的数据源来实现多数据源。原理跟 JPA 多数据源实现基本一致。
创建 mybatis-multip-datasource 项目
数据库脚本参考:
pom.xml文件引入如下依赖
| <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
| <modelVersion>4.0.0modelVersion> |
| |
| <groupId>com.olivegroupId> |
| <artifactId>mybatis-multip-datasourceartifactId> |
| <version>0.0.1-SNAPSHOTversion> |
| <packaging>jarpackaging> |
| |
| <name>jpa-multip-datasourcename> |
| <url>http://maven.apache.orgurl> |
| |
| <parent> |
| <groupId>org.springframework.bootgroupId> |
| <artifactId>spring-boot-starter-parentartifactId> |
| <version>2.5.14version> |
| <relativePath /> |
| parent> |
| |
| <properties> |
| <project.build.sourceEncoding>UTF-8project.build.sourceEncoding> |
| <maven.compiler.source>8maven.compiler.source> |
| <maven.compiler.target>8maven.compiler.target> |
| properties> |
| |
| <dependencies> |
| <dependency> |
| <groupId>org.springframework.bootgroupId> |
| <artifactId>spring-boot-starter-testartifactId> |
| <scope>testscope> |
| dependency> |
| <dependency> |
| <groupId>org.mybatis.spring.bootgroupId> |
| <artifactId>mybatis-spring-boot-starterartifactId> |
| <version>2.1.3version> |
| dependency> |
| |
| <dependency> |
| <groupId>mysqlgroupId> |
| <artifactId>mysql-connector-javaartifactId> |
| dependency> |
| |
| <dependency> |
| <groupId>org.projectlombokgroupId> |
| <artifactId>lombokartifactId> |
| dependency> |
| |
| <dependency> |
| <groupId>org.springframework.bootgroupId> |
| <artifactId>spring-boot-starter-webartifactId> |
| dependency> |
| |
| dependencies> |
| project> |
配置两个数据源
分别为第一个主数据源(primary),第二数据源(second),具体配置如下:
| |
| server: |
| port: 8080 |
| |
| |
| spring: |
| datasource: |
| primary: |
| driver-class-name: com.mysql.jdbc.Driver |
| jdbc-url: jdbc:mysql://127.0.0.1:3306/db01?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true |
| username: root |
| password: root |
| second: |
| driver-class-name: com.mysql.cj.jdbc.Driver |
| jdbc-url: jdbc:mysql://127.0.0.1:3306/crm72?characterEncoding=utf-8&allowMultiQueries=true&autoReconnect=true |
| username: root |
| password: root |
| |
| jackson: |
| serialization: |
| indent-output: true |
配置数据源
DataSourceConfig配置
| package com.olive.config; |
| |
| import org.springframework.beans.factory.annotation.Qualifier; |
| import org.springframework.boot.context.properties.ConfigurationProperties; |
| import org.springframework.boot.jdbc.DataSourceBuilder; |
| import org.springframework.context.annotation.Bean; |
| import org.springframework.context.annotation.Configuration; |
| import org.springframework.context.annotation.Primary; |
| |
| import javax.sql.DataSource; |
| |
| |
| |
| |
| @Configuration |
| public class DataSourceConfig { |
| |
| @Bean(name = "primaryDataSource") |
| @Qualifier("primaryDataSource") |
| @ConfigurationProperties(prefix = "spring.datasource.primary") |
| @Primary |
| public DataSource primaryDataSource() { |
| return DataSourceBuilder.create().build(); |
| } |
| |
| @Bean(name = "secondDataSource") |
| @Qualifier("secondDataSource") |
| @ConfigurationProperties(prefix = "spring.datasource.second") |
| public DataSource secondDataSource() { |
| return DataSourceBuilder.create().build(); |
| } |
| } |
PrimaryConfig数据源
| |
| |
| |
| @Configuration |
| @MapperScan(basePackages = "com.olive.mapper.primary", |
| sqlSessionTemplateRef = "primarySqlSessionTemplate") |
| public class PrimaryConfig { |
| |
| @Autowired |
| @Qualifier("primaryDataSource") |
| private DataSource primaryDataSource; |
| |
| @Bean(name = "primarySqlSessionFactory") |
| @Primary |
| public SqlSessionFactory primarySqlSessionFacotory() throws Exception { |
| SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); |
| sqlSessionFactoryBean.setDataSource(primaryDataSource); |
| sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() |
| .getResources("classpath:mapper/primary/*.xml")); |
| return sqlSessionFactoryBean.getObject(); |
| } |
| |
| @Bean(name = "primaryTransactionManager") |
| @Primary |
| public DataSourceTransactionManager primaryTransactionManager() { |
| return new DataSourceTransactionManager(primaryDataSource); |
| } |
| |
| @Bean(name = "primarySqlSessionTemplate") |
| @Primary |
| public SqlSessionTemplate primarySqlSessionTemplate(@Qualifier("primarySqlSessionFactory") SqlSessionFactory sqlSessionFactory) { |
| return new SqlSessionTemplate(sqlSessionFactory); |
| } |
| |
| } |
SecondConfig数据源
| |
| |
| |
| @Configuration |
| @MapperScan(basePackages = "com.olive.mapper.second", |
| sqlSessionTemplateRef = "secondSqlSessionTemplate") |
| public class SecondConfig { |
| |
| @Autowired |
| @Qualifier("secondDataSource") |
| private DataSource secondDataSource; |
| |
| @Bean(name = "secondSqlSessionFactory") |
| public SqlSessionFactory secondSqlSessionFacotory() throws Exception { |
| SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); |
| sqlSessionFactoryBean.setDataSource(secondDataSource); |
| sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver() |
| .getResources("classpath:mapper/second/*.xml")); |
| return sqlSessionFactoryBean.getObject(); |
| } |
| |
| @Bean(name = "secondTransactionManager") |
| public DataSourceTransactionManager secondTransactionManager() { |
| return new DataSourceTransactionManager(secondDataSource); |
| } |
| |
| @Bean(name = "secondSqlSessionTemplate") |
| public SqlSessionTemplate secondSqlSessionTemplate(@Qualifier("secondSqlSessionFactory") SqlSessionFactory sqlSessionFactory) { |
| return new SqlSessionTemplate(sqlSessionFactory); |
| } |
| } |
创建学生与老师实体类
Student实体类
| package com.olive.entity.primary; |
| |
| import java.io.Serializable; |
| import lombok.Data; |
| |
| @Data |
| public class StudentDO implements Serializable{ |
| |
| private Long id; |
| |
| private String name; |
| |
| private int sex; |
| |
| private String grade; |
| } |
Teacher实体类
| package com.olive.entity.second; |
| |
| import java.io.Serializable; |
| import lombok.Data; |
| |
| @Data |
| public class TeacherDO implements Serializable { |
| |
| private Long id; |
| |
| private String name; |
| |
| private int sex; |
| |
| private String office; |
| } |
数据库持久类
StudentMapper类
| package com.olive.mapper.primary; |
| |
| import com.olive.entity.primary.StudentDO; |
| import org.apache.ibatis.annotations.Param; |
| |
| |
| public interface StudentMapper { |
| |
| int save(@Param("studentDO") StudentDO studentDO); |
| } |
TeacherMapper类
| package com.olive.mapper.second; |
| |
| import com.olive.entity.second.TeacherDO; |
| import org.apache.ibatis.annotations.Param; |
| |
| public interface TeacherMapper { |
| |
| int save(@Param("teacherDO") TeacherDO teacherDO); |
| } |
Mybatis xml映射
StudentMapper.xml
| |
| mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| <mapper namespace="com.olive.mapper.primary.StudentMapper"> |
| <resultMap id="BaseResultMap" type="com.olive.entity.primary.StudentDO"> |
| <id column="id" jdbcType="BIGINT" property="id" /> |
| <result column="name" jdbcType="VARCHAR" property="name" /> |
| <result column="sex" jdbcType="INTEGER" property="sex" /> |
| <result column="grade" jdbcType="VARCHAR" property="grade" /> |
| resultMap> |
| |
| <insert id="save"> |
| INSERT INTO t_student (user_name, sex, grade) VALUES (#{studentDO.name}, #{studentDO.sex}, #{studentDO.grade}); |
| insert> |
| mapper> |
TeacherMapper.xml
| |
| mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> |
| <mapper namespace="com.olive.mapper.second.TeacherMapper"> |
| <resultMap id="BaseResultMap" type="com.olive.entity.second.TeacherDO"> |
| <id column="id" jdbcType="BIGINT" property="id" /> |
| <result column="name" jdbcType="VARCHAR" property="name" /> |
| <result column="sex" jdbcType="INTEGER" property="sex" /> |
| <result column="office" jdbcType="VARCHAR" property="office" /> |
| resultMap> |
| |
| <insert id="save"> |
| INSERT INTO t_teacher ( user_name, sex, office) VALUES (#{teacherDO.name}, #{teacherDO.sex}, #{teacherDO.office}); |
| insert> |
| mapper> |
主要注意这两个xml文件需要放到不同的目录,如下图
创建springboot引导类
| package com.olive; |
| |
| import org.springframework.boot.SpringApplication; |
| import org.springframework.boot.autoconfigure.SpringBootApplication; |
| |
| @SpringBootApplication |
| public class Application { |
| |
| public static void main(String[] args) { |
| SpringApplication.run(Application.class); |
| } |
| |
| } |
测试
| package com.olive; |
| |
| import org.junit.jupiter.api.Test; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.boot.test.context.SpringBootTest; |
| |
| import com.olive.entity.primary.StudentDO; |
| import com.olive.entity.second.TeacherDO; |
| import com.olive.mapper.primary.StudentMapper; |
| import com.olive.mapper.second.TeacherMapper; |
| |
| @SpringBootTest |
| public class MybatisTest { |
| |
| @Autowired |
| StudentMapper studentMapper; |
| |
| @Autowired |
| TeacherMapper teacherMapper; |
| |
| @Test |
| public void userSave() { |
| StudentDO studentDO = new StudentDO(); |
| studentDO.setName("BUG弄潮儿"); |
| studentDO.setSex(1); |
| studentDO.setGrade("一年级"); |
| studentMapper.save(studentDO); |
| |
| TeacherDO teacherDO = new TeacherDO(); |
| teacherDO.setName("Java乐园"); |
| teacherDO.setSex(2); |
| teacherDO.setOffice("语文"); |
| teacherMapper.save(teacherDO); |
| } |
| } |