https://blog.csdn.net/liuxiao723846/article/details/80461071java
版權聲明:本文爲博主原創文章,未經博主容許不得轉載。 https://blog.csdn.net/liuxiao723846/article/details/80461071
上一篇文章介紹了 spring-boot整合mybatis和druid鏈接池如何配置和使用,本篇文章是上篇的擴展,若是業務中出現了須要從多個數據源中獲取數據,到底該如何實現?本文主要介紹在一種最爲簡單的實現方案:多數據源 - 多實例。 mysql
在上篇文章中不難看出Spring Boot中,經過爲該數據源DataSource初始化一個與之對應的SessionFactory,從而實現鏈接。所以在面對多數據源的時候,能夠分別爲每一個數據源寫一個mybatis的config類,使其每一個DataSource都擁有一個只屬於本身的SessionFactory,這樣就能夠根據各自的mapper(dao)映射目錄找到對應的mybaits實例。git
注:這種實現方法要求不一樣的mybatis實例的mapper映射目錄(dao)不能相同。github
一、pom.xmlweb
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.edu.nuc</groupId>
<artifactId>Test1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Test1</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
<mybatis-spring-boot>1.2.0</mybatis-spring-boot>
<mysql-connector>5.1.39</mysql-connector>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- spring boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Boot log4j依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
<version>1.3.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- jsp -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<!-- Spring Boot Mybatis 依賴 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis-spring-boot}</version>
</dependency>
<!-- Druid 數據鏈接池依賴 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.13</version>
</dependency>
<!-- MySQL 鏈接驅動依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<finalName>Test</finalName>
<plugins>
<!-- <plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
</project>
二、application.properties和數據源配置:spring
1)application.properties配置:sql
#---------------------ds1數據源(使用durid鏈接池)
ds1.datasource.url=jdbc:mysql://ds1.w.abc.db:1883/ttengine?useUnicode=true&characterEncoding=utf8
ds1.datasource.username=ds1
ds1.datasource.password=ds1
ds1.datasource.driverClassName=com.mysql.jdbc.Driver
ds1.datasource.initialSize=20
ds1.datasource.minIdle=20
ds1.datasource.maxActive=200
ds1.datasource.maxWait=60000
ds1.datasource.timeBetweenEvictionRunsMillis=60000
ds1.datasource.minEvictableIdleTimeMillis=300000
ds1.datasource.testWhileIdle=true
ds1.datasource.testOnBorrow=false
ds1.datasource.testOnReturn=false
ds1.datasource.poolPreparedStatements=true
ds1.datasource.maxPoolPreparedStatementPerConnectionSize=20
ds2.datasource.url=jdbc:mysql://ds2.w.abc.db:8907/toutiao?useUnicode=true&characterEncoding=utf8
ds2.datasource.username=ds2
ds2.datasource.password=^ds2
ds2.datasource.driverClassName=com.mysql.jdbc.Driver
#---------------------ds2數據源
ds2.datasource.initialSize=20
ds2.datasource.minIdle=20
ds2.datasource.maxActive=200
ds2.datasource.maxWait=60000
ds2.datasource.timeBetweenEvictionRunsMillis=60000
ds2.datasource.minEvictableIdleTimeMillis=300000
ds2.datasource.testWhileIdle=true
ds2.datasource.testOnBorrow=false
ds2.datasource.testOnReturn=false
ds2.datasource.poolPreparedStatements=true
ds2.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 頁面默認前綴目錄
spring.mvc.view.prefix=/WEB-INF/page/
spring.mvc.view.suffix=.jsp
因爲咱們使用druid鏈接池,因此咱們須要定製DataSourceConfig(每一個數據源都要定製一份)apache
2)Datasource1Config:tomcat
package nc.edu.nuc.Test.dao.mysql;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
//掃描 Mapper 接口並容器管理
@MapperScan(basePackages = Datasource1Config.PACKAGE, sqlSessionFactoryRef = "ds1SqlSessionFactory")
public class Datasource1Config {
// 精確到 master 目錄,以便跟其餘數據源隔離
static final String PACKAGE = "nc.edu.nuc.Test.dao.mysql.ds1";
static final String MAPPER_LOCATION = "classpath:mapper/ds1/*.xml";
@Value("${ds1.datasource.url}")
private String url;
@Value("${ds1.datasource.username}")
private String user;
@Value("${ds1.datasource.password}")
private String password;
@Value("${ds1.datasource.driverClassName}")
private String driverClass;
@Value("${ds1.datasource.maxActive}")
private Integer maxActive;
@Value("${ds1.datasource.minIdle}")
private Integer minIdle;
@Value("${ds1.datasource.initialSize}")
private Integer initialSize;
@Value("${ds1.datasource.maxWait}")
private Long maxWait;
@Value("${ds1.datasource.timeBetweenEvictionRunsMillis}")
private Long timeBetweenEvictionRunsMillis;
@Value("${ds1.datasource.minEvictableIdleTimeMillis}")
private Long minEvictableIdleTimeMillis;
@Value("${ds1.datasource.testWhileIdle}")
private Boolean testWhileIdle;
@Value("${ds1.datasource.testWhileIdle}")
private Boolean testOnBorrow;
@Value("${ds1.datasource.testOnBorrow}")
private Boolean testOnReturn;
@Bean(name = "ds1DataSource")
@Primary
public DataSource ds1DataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
//鏈接池配置
dataSource.setMaxActive(maxActive);
dataSource.setMinIdle(minIdle);
dataSource.setInitialSize(initialSize);
dataSource.setMaxWait(maxWait);
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
dataSource.setTestWhileIdle(testWhileIdle);
dataSource.setTestOnBorrow(testOnBorrow);
dataSource.setTestOnReturn(testOnReturn);
dataSource.setValidationQuery("SELECT 'x'");
dataSource.setPoolPreparedStatements(true);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
return dataSource;
}
@Bean(name = "ds1TransactionManager")
@Primary
public DataSourceTransactionManager ds1TransactionManager() {
return new DataSourceTransactionManager(ds1DataSource());
}
@Bean(name = "ds1SqlSessionFactory")
@Primary
public SqlSessionFactory ds1SqlSessionFactory(@Qualifier("ds1DataSource") DataSource ds1DataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(ds1DataSource);
sessionFactory.setTypeAliasesPackage("nc.edu.nuc.Test.entity");
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(Datasource1Config.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
3)Datasource2Config:
package nc.edu.nuc.Test.dao.mysql;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import com.alibaba.druid.pool.DruidDataSource;
@Configuration
//掃描 Mapper 接口並容器管理
@MapperScan(basePackages = Datasource2Config.PACKAGE, sqlSessionFactoryRef = "ds2SqlSessionFactory")
public class Datasource2Config {
// 精確到 master 目錄,以便跟其餘數據源隔離
static final String PACKAGE = "nc.edu.nuc.Test.dao.mysql.ds2";
static final String MAPPER_LOCATION = "classpath:mapper/ds2/*.xml";
@Value("${ds2.datasource.url}")
private String url;
@Value("${ds2.datasource.username}")
private String user;
@Value("${ds2.datasource.password}")
private String password;
@Value("${ds2.datasource.driverClassName}")
private String driverClass;
@Value("${ds2.datasource.maxActive}")
private Integer maxActive;
@Value("${ds2.datasource.minIdle}")
private Integer minIdle;
@Value("${ds2.datasource.initialSize}")
private Integer initialSize;
@Value("${ds2.datasource.maxWait}")
private Long maxWait;
@Value("${ds2.datasource.timeBetweenEvictionRunsMillis}")
private Long timeBetweenEvictionRunsMillis;
@Value("${ds2.datasource.minEvictableIdleTimeMillis}")
private Long minEvictableIdleTimeMillis;
@Value("${ds2.datasource.testWhileIdle}")
private Boolean testWhileIdle;
@Value("${ds2.datasource.testWhileIdle}")
private Boolean testOnBorrow;
@Value("${ds2.datasource.testOnBorrow}")
private Boolean testOnReturn;
@Bean(name = "ds2DataSource")
public DataSource ds2DataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
//鏈接池配置
dataSource.setMaxActive(maxActive);
dataSource.setMinIdle(minIdle);
dataSource.setInitialSize(initialSize);
dataSource.setMaxWait(maxWait);
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
dataSource.setTestWhileIdle(testWhileIdle);
dataSource.setTestOnBorrow(testOnBorrow);
dataSource.setTestOnReturn(testOnReturn);
dataSource.setValidationQuery("SELECT 'x'");
dataSource.setPoolPreparedStatements(true);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
return dataSource;
}
@Bean(name = "ds2TransactionManager")
public DataSourceTransactionManager ds2TransactionManager() {
return new DataSourceTransactionManager(ds2DataSource());
}
@Bean(name = "ds2SqlSessionFactory")
public SqlSessionFactory ds2SqlSessionFactory(@Qualifier("ds2DataSource") DataSource ds2DataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(ds2DataSource);
sessionFactory.setTypeAliasesPackage("nc.edu.nuc.Test.entity");
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(Datasource2Config.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
多數據源配置的時候注意,必需要有一個主數據源。springboot
@Primary 標誌這個 Bean 若是在多個同類 Bean 候選時,該 Bean 優先被考慮。「多數據源配置的時候注意,必需要有一個主數據源,用 @Primary 標誌該 Bean」
@MapperScan 掃描 Mapper 接口並容器管理,包路徑精確到 master,爲了和下面 cluster 數據源作到精確區分
@Value 獲取全局配置文件 application.properties 的 kv 配置,並自動裝配sqlSessionFactoryRef 表示定義了 key ,表示一個惟一 SqlSessionFactory 實例.
4)說明:
上面數據配置分別掃描nc.edu.nuc.Test.dao.mysql.ds1 和 nc.edu.nuc.Test.dao.mysql.ds2中定義的Mapper接口TestDao和DemoDao(能夠在接口上配置@Mapper註解,也能夠在springboot主類上統一加@MapperScan("..."))
ds1對應 xml classpath:mapper/ds1下的sql文件,ds2對應 xml classpath:mapper/ds2下的sql文件,Mybatis 內部會使用反射機制運行去解析相應 SQL。
三、其餘:
多數據源配置好後,接下來就和正常spring-boot的用法同樣了。整個結構:
1)crontroller:
package nc.edu.nuc.Test.controller;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import nc.edu.nuc.Test.entity.Test;
import nc.edu.nuc.Test.service.TestService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
private static final Logger logger = LoggerFactory.getLogger(TestController.class);
@Autowired
private TestService testService;
@RequestMapping("/test")
@ResponseBody
public String test(HttpServletRequest request) {
String name = request.getParameter("name");
Test test = null;
try {
test = testService.findByName(name);
} catch (Exception e) {
test = new Test();
logger.error("test error.",e);
}
logger.info("test....{}",name);
return test.toString();
}
}
2)service:
package nc.edu.nuc.Test.service;
import java.util.List;
import nc.edu.nuc.Test.dao.mysql.ds1.TestDao;
import nc.edu.nuc.Test.dao.mysql.ds2.DemoDao;
import nc.edu.nuc.Test.entity.Demo;
import nc.edu.nuc.Test.entity.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestService{
private static final Logger logger = LoggerFactory.getLogger(TestService.class);
@Autowired
private TestDao testDao;
@Autowired
private DemoDao demoDao;
public Test findByName(String name) throws Exception{
List<Demo> demoList = demoDao.getDemoList();
logger.info(demoList.toString());
return testDao.findByName(name);
}
}
3)entity:
package nc.edu.nuc.Test.entity;
public class Demo {
private Long id;
private String title;
private String descs;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescs() {
return descs;
}
public void setDescs(String descs) {
this.descs = descs;
}
@Override
public String toString() {
return "Demo [id=" + id + ", title=" + title + ", descs=" + descs + "]";
}
}
package nc.edu.nuc.Test.entity;
public class Test {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Test [id=" + id + ", name=" + name + "]";
}
}
4)dao:
package nc.edu.nuc.Test.dao.mysql.ds1;
import nc.edu.nuc.Test.entity.Test;
import org.apache.ibatis.annotations.Param;
public interface TestDao {
Test findByName(@Param("name") String n);
}
package nc.edu.nuc.Test.dao.mysql.ds2;
import java.util.List;
import nc.edu.nuc.Test.entity.Demo;
public interface DemoDao {
List<Demo> getDemoList() throws Exception;
}
5)mapper sql文件:
<?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="nc.edu.nuc.Test.dao.mysql.ds1.TestDao">
<resultMap id="BaseResultMap" type="nc.edu.nuc.Test.entity.Test">
<result column="id" property="id" />
<result column="name" property="name" />
</resultMap>
<parameterMap id="Test" type="nc.edu.nuc.Test.entity.Test"/>
<sql id="Base_Column_List">
id,name
</sql>
<select id="findByName" resultMap="BaseResultMap" parameterType="java.lang.String">
select
<include refid="Base_Column_List" />
from test
where name = #{name}
</select>
</mapper>
<?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="nc.edu.nuc.Test.dao.mysql.ds2.DemoDao">
<resultMap id="BaseResultMap" type="nc.edu.nuc.Test.entity.Demo">
<result column="id" property="id" />
<result column="title" property="title" />
<result column="descs" property="descs" />
</resultMap>
<parameterMap id="Demo" type="nc.edu.nuc.Test.entity.Demo"/>
<sql id="Base_Column_List">
id,title,descs
</sql>
<select id="getDemoList" resultType="Demo">
select
<include refid="Base_Column_List" />
from demo
</select>
</mapper>
6)app啓動類:
package nc.edu.nuc.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* Hello world!
* 能夠統一用@MapperScan指定掃描的dao,也能夠在每一個dao上添加@Mapper
*/
@SpringBootApplication
//mapper 接口類掃描包配置
@MapperScan("nc.edu.nuc.Test.dao.mysql")
public class App {
public static void main( String[] args ) {
SpringApplication.run(App.class, args);
}
}
參考:https://github.com/YHYR/Mybatis
https://github.com/JeffLi1993/springboot-learning-example/blob/master/springboot-mybatis-mutil-datasource/src/main/java/org/spring/springboot/service/impl/UserServiceImpl.java
https://www.bysocket.com/?p=1712