一、簡介
MybatisPlus中引用多數據庫時,傳統的配置就失效了,需要單獨寫配置來實現,下面就說一下具體應該如何操作
二、引入MybatisPlus多數據源配置
還是先看一下我的項目結構,Model是單獨的模塊,請自行創建
1、創建一個Maven項目,修改pom.xml文件增加對spring boot、mybatis plus、druid、mysql connector的引用
<dependencyManagement> <dependencies> <dependency> <!-- Import dependency management from Spring Boot --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>2.0.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--import druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <!--import mysql connector--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> <!--import mybatis plus 它會自動引入mybatis及mybatis spring切勿重復引用以免沖突--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>2.3</version> </dependency> </dependencies>
2、創建resources文件夾,並創建application.yml文件增加以下配置,此處不需要寫mybatis plus的配置了,因為多數據源時這里的mybatis plus會失效,具體原因還沒找到
#設置提供的服務名 spring: application: name: javademo-tyh-service-hotel #配置數據庫 datasource: type: com.alibaba.druid.pool.DruidDataSource db1: url: jdbc:mysql://10.11.12.237:3306/db_test?useUnicode=true&characterEncoding=utf8 username: root password: root driver-class-name: com.mysql.jdbc.Driver db2: url: jdbc:mysql://10.11.12.237:3306/tyh_test?useUnicode=true&characterEncoding=utf8 username: root password: root driver-class-name: com.mysql.jdbc.Driver #設置自己啟動的端口 server: port: 12000
3、在resources文件夾下創建mapper文件夾,在其內部創建兩個數據庫的兩張表的mapper.xml文件,分別編寫一個自定義方法
BaseInfoMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 指明當前xml對應的Mapper --> <mapper namespace="javademo.tyh.service.hotel.mapper.BaseInfoMapper"> <select id="listCount" resultType="Integer"> select count(*) from base_info; </select> </mapper>
UserInfoMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org/DTD Mapper 3.0" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 指明當前xml對應的Mapper --> <mapper namespace="javademo.tyh.service.hotel.mapper.UserInfoMapper"> <select id="listCount" resultType="Integer"> select count(*) from user_info; </select> </mapper>
4、打開main方法所在的類並修改為如下代碼
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("javademo.tyh.service.hotel.mapper")//標記掃描的mapper位置 public class AppServiceHotel { public static void main( String[] args ) { SpringApplication.run(AppServiceHotel.class, args); } }
5、創建config文件夾,存放mybatis plus的相關配置,此內部的類很多都摘自官網,是按照他的方式進行實現的
創建枚舉DBTypeEnum
/** * 多數據源枚舉 */ public enum DBTypeEnum { db1("db1"), db2("db2"); private String value; DBTypeEnum(String value) { this.value = value; } public String getValue() { return value; } }
創建數據源操作類DbContextHolder
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(); } }
創建spring的DataSource抽象類 DynamicDataSource
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /* * 擴展Spring的AbstractRoutingDataSource抽象類,實現動態數據源。 * AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是實現數據源的route的核心, * 這里對該方法進行Override。 【上下文DbContextHolder為一線程安全的ThreadLocal】 */ public class DynamicDataSource extends AbstractRoutingDataSource { /** * 取得當前使用哪個數據源 * @return */ @Override protected Object determineCurrentLookupKey(){ return DbContextHolder.getDbType(); } }
創建MybatisPlusConfig配置類
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; import com.baomidou.mybatisplus.MybatisConfiguration; import com.baomidou.mybatisplus.entity.GlobalConfiguration; import com.baomidou.mybatisplus.mapper.LogicSqlInjector; 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.core.io.support.PathMatchingResourcePatternResolver; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; /** * MybatisPlus配置 */ @Configuration public class MybatisPlusConfig { // 分頁攔截器 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); } //定義db1 @Bean(name = "db1") @ConfigurationProperties(prefix = "spring.datasource.db1")//與配置文件中的層次結構相同 public DataSource db1() { return DruidDataSourceBuilder.create().build(); } //定義db2 @Bean(name = "db2") @ConfigurationProperties(prefix = "spring.datasource.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(db1); return dynamicDataSource; } @Bean("sqlSessionFactory") public SqlSessionFactory sqlSessionFactory() throws Exception { //***導入MybatisSqlSession配置*** MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean(); //指明數據源 sqlSessionFactory.setDataSource(multipleDataSource(db1(), db2())); //指明mapper.xml位置(配置文件中指明的xml位置會失效用此方式代替,具體原因未知) sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/mapper/**Mapper.xml")); //指明實體掃描(多個package用逗號或者分號分隔) sqlSessionFactory.setTypeAliasesPackage("javademo.tyh.model.base;javademo.tyh.model.hotel"); //***導入Mybatis配置*** MybatisConfiguration configuration = new MybatisConfiguration(); configuration.setJdbcTypeForNull(JdbcType.NULL); configuration.setMapUnderscoreToCamelCase(true); configuration.setCacheEnabled(false); sqlSessionFactory.setConfiguration(configuration); sqlSessionFactory.setPlugins(new Interceptor[]{paginationInterceptor()}); //***導入全局配置*** sqlSessionFactory.setGlobalConfig(globalConfiguration()); return sqlSessionFactory.getObject(); } /** * 在代碼中配置MybatisPlus替換掉application.yml中的配置 * @return */ @Bean public GlobalConfiguration globalConfiguration() { GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector()); //主鍵類型 0:數據庫ID自增, 1:用戶輸入ID,2:全局唯一ID (數字類型唯一ID), 3:全局唯一ID UUID conf.setIdType(0); //字段策略(拼接sql時用於判斷屬性值是否拼接) 0:忽略判斷,1:非NULL判斷,2:非空判斷 conf.setFieldStrategy(2); //駝峰下划線轉換含查詢column及返回column(column下划線命名create_time,返回java實體是駝峰命名createTime,開啟后自動轉換否則保留原樣) conf.setDbColumnUnderline(true); //是否動態刷新mapper conf.setRefresh(true); return conf; } }
6、創建mapper文件夾用於存放於xml對應的mapper接口
BaseInfoMapper
import com.baomidou.mybatisplus.mapper.BaseMapper; import javademo.tyh.model.hotel.BaseInfoModel; import org.springframework.stereotype.Component; @Component public interface BaseInfoMapper extends BaseMapper<BaseInfoModel> { //自定義方法 int listCount(); }
UserInfoMapper
import com.baomidou.mybatisplus.mapper.BaseMapper; import javademo.tyh.model.hotel.UserInfoModel; import org.springframework.stereotype.Component; @Component public interface UserInfoMapper extends BaseMapper<UserInfoModel> { //自定義方法 int listCount(); }
7、創建service文件夾用於存放業務邏輯類
import javademo.tyh.model.hotel.BaseInfoModel; import javademo.tyh.model.hotel.UserInfoModel; import javademo.tyh.service.hotel.config.DBTypeEnum; import javademo.tyh.service.hotel.config.DbContextHolder; import javademo.tyh.service.hotel.mapper.BaseInfoMapper; import javademo.tyh.service.hotel.mapper.UserInfoMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class HotelService { @Autowired BaseInfoMapper baseMapper; @Autowired UserInfoMapper userMapper; public void testDynamicDb() { //使用db1 DbContextHolder.setDbType(DBTypeEnum.db1); BaseInfoModel baseModel = baseMapper.selectById(1); int baseCount = baseMapper.listCount(); System.out.println("db1=" + baseModel.getNickname()); //使用db2 DbContextHolder.setDbType(DBTypeEnum.db2); UserInfoModel userModel = userMapper.selectById(1); int userCount = userMapper.listCount(); System.out.println("db2=" + userModel.getUsername()); } }
8、創建controller文件夾編寫一個controller和action用於測試
import javademo.tyh.service.hotel.service.HotelService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping("/hotel") public class HotelController { @Autowired HotelService service; @ResponseBody @RequestMapping("/test") public void test() { service.testDynamicDb(); } }
9、創建自己的實體Model,get/set方法自己生成吧
BaseInfoModel
import com.baomidou.mybatisplus.annotations.TableName; import java.time.LocalDateTime; @TableName("base_info") public class BaseInfoModel { private int id; private String nickname; private LocalDateTime updateTime; }
UserInfoModel
import com.baomidou.mybatisplus.annotations.TableName; import java.time.LocalDateTime; @TableName("user_info") public class UserInfoModel { private int id; private String username; private String password; private int sex; private int age; private LocalDateTime createTime; }
OK,至此Mybatis Plus多數據源配置Demo就完成了,可以運行http://localhost:12000/hotel/test看一下console控制台會得到以下輸出,db1和db2就切換成功了