10、SpringBoot-mybatis-plus-druid多源数据
系列导航
6、SpringBoot-mybatis分页实现pagehelper
9、SpringBoot-mybatis-druid多源数据多源数据
10、SpringBoot-mybatis-plus-druid多源数据
11、SpringBoot-mybatis-plus-druid多源数据事务
12、SpringBoot-mybatis-plus-ehcache
14、SpringBoot-easyexcel导出excle
完结
本文介绍如何在mybatis-plus上使用多源数据,本来以为mybatis-plus上多源数据和mybatis差不多实际操作后发现真还是不太一样。mybatis-plus的配置多源数据的大致思路就是,利用了切面的思想,访问那个mapper就把当前数据连接切换到对应的数据源上。
1数据库中创建表
zy数据库:
CREATE TABLE TEST_BLOCK_T ( BLOCK_ID VARCHAR2(10 BYTE) PRIMARY KEY, --编码 BLOCK_NAME VARCHAR2(200 BYTE) --资源名称 ); Insert into TEST_BLOCK_T (BLOCK_ID, BLOCK_NAME) Values ('1', 'java'); COMMIT;
yc数据库:
CREATE TABLE TEST_USER_T ( USER_ID VARCHAR2(10 BYTE) PRIMARY KEY, NAME VARCHAR2(200 BYTE) ); Insert into TEST_USER_T (USER_ID, NAME) Values ('1', '张三'); COMMIT;
2、pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>demo</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <spring-boot.version>2.1.17.RELEASE</spring-boot.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- oracle驱动 --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency> <!-- 集成druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!--集成mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>2.1.9</version> </dependency> <!-- aop切面 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!-- 省略get/set等方法 日志打印 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> </project>
3、 application.properties配置
# 应用名称
spring.application.name=demo
# 应用服务 WEB 访问端口
server.port=8080
spring.aop.proxy-target-class=true
spring.aop.auto=true
spring.datasource.druid.db1.url=jdbc:oracle:thin:@192.168.1.100:1521:orcl
spring.datasource.druid.db1.username=zy
spring.datasource.druid.db1.password=123
spring.datasource.druid.db1.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.druid.db1.initialSize=5
spring.datasource.druid.db1.minIdle=5
spring.datasource.druid.db1.maxActive=20
spring.datasource.druid.db2.url=jdbc:oracle:thin:@192.168.1.100:1521:orcl
spring.datasource.druid.db2.username=yc
spring.datasource.druid.db2.password=123
spring.datasource.druid.db2.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.druid.db2.initialSize=5
spring.datasource.druid.db2.minIdle=5
spring.datasource.druid.db2.maxActive=20
#开启sql打印
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
4、文件目录
主要源码:
MybatisPlusConfig.java
DataSourceSwitchAspect.java
5、源码
package com.example.demo.config; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Component @Order(value = -100) @Slf4j @Aspect public class DataSourceSwitchAspect { @Pointcut("execution(* com.example.demo.mapper.db1..*.*(..))") private void db1Aspect() { } @Pointcut("execution(* com.example.demo.mapper.db2..*.*(..))") private void db2Aspect() { } @Before("db1Aspect()") public void db1() { log.info("切换到db1 数据源..."); DbContextHolder.setDbType(DBTypeEnum.db1); } @Before("db2Aspect()") public void db2() { log.info("切换到db2 数据源..."); DbContextHolder.setDbType(DBTypeEnum.db2); } }
package com.example.demo.config; public class DbContextHolder { private static final ThreadLocal contextHolder = new ThreadLocal<>(); /** * 设置数据源 * @param dbTypeEnum */ public static void setDbType(DBTypeEnum dbTypeEnum) { contextHolder.set(dbTypeEnum.getValue()); } /** * 取得当前数据源 * @return */ public static String getDbType() { return (String) contextHolder.get(); } /** * 清除上下文数据 */ public static void clearDbType() { contextHolder.remove(); } }
package com.example.demo.config; public enum DBTypeEnum { db1("db1"), db2("db2") ; private String value; DBTypeEnum(String value) { this.value = value; } public String getValue() { return value; } }
package com.example.demo.config; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DbContextHolder.getDbType(); } }
package com.example.demo.config; import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.baomidou.mybatisplus.MybatisConfiguration; import com.baomidou.mybatisplus.plugins.PaginationInterceptor; import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean; import org.apache.ibatis.plugin.Interceptor; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.type.JdbcType; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import org.springframework.transaction.annotation.EnableTransactionManagement; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @EnableTransactionManagement @Configuration public class MybatisPlusConfig { @Bean public PaginationInterceptor paginationInterceptor() { PaginationInterceptor paginationInterceptor = new PaginationInterceptor(); paginationInterceptor.setLocalPage(true); return paginationInterceptor; } @Bean(name = "db1") @ConfigurationProperties(prefix = "spring.datasource.druid.db1") public DataSource db1() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "db2") @ConfigurationProperties(prefix = "spring.datasource.druid.db2") public DataSource db2() { return DruidDataSourceBuilder.create().build(); } /** * 动态数据源配置 * * @return */ @Bean @Primary public DataSource multipleDataSource(@Qualifier("db1") DataSource db1, @Qualifier("db2") DataSource db2) { DynamicDataSource dynamicDataSource = new DynamicDataSource(); Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put(DBTypeEnum.db1.getValue(), db1); targetDataSources.put(DBTypeEnum.db2.getValue(), db2); dynamicDataSource.setTargetDataSources(targetDataSources); dynamicDataSource.setDefaultTargetDataSource(db2); return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2())); MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); //添加分页功能 sqlSessionFactory.setPlugins(new Interceptor[]{ paginationInterceptor() }); return sqlSessionFactory.getObject(); } }
package com.example.demo.controller; import com.example.demo.service.ManySourceService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/hello") public class ManySourceController { @Autowired ManySourceService manySourceService; @GetMapping("/getZyBlock") @ResponseBody public String test1() { return manySourceService.getZyBlock(); } @GetMapping("/getYcUser") @ResponseBody public String test2() { return manySourceService.getYcUser(); } @PostMapping("/insertZyBlock") @ResponseBody public String test3() { return manySourceService.insertZyBlock(); } @PostMapping("/insertYcUser") @ResponseBody public String test4() { return manySourceService.insertYcUser(); } @PostMapping("/insertMany") @ResponseBody public String test5() { return manySourceService.insertMany(); } }
package com.example.demo.domain.db1; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; @TableName(value = "TEST_BLOCK_T") public class Block { private static final long serialVersionUID = 1L; @TableId private String blockId; /** * $field.comment。 */ private String blockName; public String getBlockId() { return blockId; } public void setBlockId(String blockId) { this.blockId = blockId; } public String getBlockName() { return blockName; } public void setBlockName(String blockName) { this.blockName = blockName; } @Override public String toString() { return "TEST_BLOCK_T{" + "blockId='" + blockId + '\'' + ", blockName='" + blockName + '\'' + '}'; } }
package com.example.demo.domain.db2; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; @TableName(value = "TEST_USER_T") public class User { private static final long serialVersionUID = 1L; @TableId private String userId; /** * $field.comment。 */ private String name; public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "userId='" + userId + '\'' + ", name='" + name + '\'' + '}'; } }
package com.example.demo.mapper.db1; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.example.demo.domain.db1.Block; public interface BlockMapper extends BaseMapper<Block> { }
package com.example.demo.mapper.db2; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.example.demo.domain.db2.User; public interface UserMapper extends BaseMapper<User> { }
package com.example.demo.service; import com.example.demo.domain.db1.Block; import com.example.demo.domain.db2.User; import com.example.demo.mapper.db1.BlockMapper; import com.example.demo.mapper.db2.UserMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class ManySourceService { @Autowired BlockMapper blockMapper; @Autowired UserMapper userMapper; //获取zy库中的block中的数据 public String getZyBlock() { return blockMapper.selectById("99999").toString(); } //获取yc库中的user中的数据 public String getYcUser() { return userMapper.selectById("2").toString() ; } public String insertZyBlock() { Block block = new Block(); block.setBlockId("99999"); block.setBlockName("PHP"); return blockMapper.insert(block)+""; } public String insertYcUser() { User user = new User(); user.setUserId("2"); user.setName("李四"); return userMapper.insert(user)+""; } //@Transactional 加了事务会报错 public String insertMany() { Block block = new Block(); block.setBlockId("99999"); block.setBlockName("PHP"); blockMapper.insert(block) ; User user = new User(); user.setUserId("2"); user.setName("李四"); userMapper.insert(user) ; return "1"; } }
package com.example.demo; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.example.demo.mapper.db*") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
6、启动项目访问项目
清空yc库里的表TEST_USER_T 和 zy库里的表TEST_BLOCK_T
(1)访问http://localhost:8080/hello/insertZyBlock 成功插入数据到TEST_BLOCK_T
(2)访问http://localhost:8080/hello/insertYcUser成功插入数据到TEST_USER_T
说明分别向不同数据源的数据库的插入没有问题。
(3)访问http://localhost:8080/hello/getZyBlock
(4)访问http://localhost:8080/hello/getYcUser
说明分别从不同数据源的数据库的查询没有问题。
再次清空yc库里的表TEST_USER_T 和 zy库里的表TEST_BLOCK_T
(5)访问http://localhost:8080/hello/insertMany
一个方法中向TEST_USER_T 和TEST_BLOCK_T插入数据插入成功数据库里的数据生成了。
日志中看到同一个方法中向不同的数据库中插入数据程序会自动的切换数据源。
注:下面就不能加事务Transactional了,这里估计是我没有用对,如果有能解决的道友可以反馈一下。
//@Transactional 加了事务会报错
public String insertMany()