赞
踩
SpringBoot 默认支持如下数据源;
- 自动配置都在
org.springframework.boot.autoconfigure.jdbc包下。org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration 数据源配置类作用是根据逻辑判断之后,添加数据源
- com.zaxxer.hikari.HikariDataSource (Spring Boot 2.0 以上,默认使用此数据源)
- org.apache.tomcat.jdbc.pool.DataSource (Spring Boot 2.0.x 以下,默认使用此数据源)
- org.apache.commons.dbcp2.BasicDataSource
HikariDataSource 号称 Java WEB 当前速度最快的数据源,相比于传统的 C3P0 、DBCP、Tomcat jdbc 等连接池更加优秀
全局配置文件application.yml中 spring.datasource.* 下只配置账号、密码、数据库地址、连接驱动,默认使用的是 com.zaxxer.hikari.HikariDataSource 数据源spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.58.129:3307/horse?characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
spring.datasource.type指定spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.58.129:3307/horse?characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
Spring Boot 2.+的默认连接池HikariCP详解
即使不使用第三方第数据库操作框架,如 MyBatis、Hibernate 、spring-data-jpa 等,Spring 本身也对 原生的 JDBC 做了轻量级的封装,即org.springframework.jdbc.core.JdbcTemplate。
JdbcTemplate 是 core 包的核心类,用于简化 JDBC 操作,还能避免一些常见的错误,如忘记关闭数据库连接。
Spring Boot 不仅提供了默认的数据源HikariDataSource,同时默认为JdbcTemplate注入数据源并初始化到Spring容器中,使用时只需自己注入即可使用
JdbcTemplate 的自动配置原理是依赖 org.springframework.boot.autoconfigure.jdbc 包下的 org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration 类
配置多个数据源
spring:
datasource:
master:
# 基本属性 url、user、password
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 123456
slave:
# 基本属性 url、user、password
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/slave_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 123456
数据源连接配置2.x和1.x的配置项是有区别的:
如果你在配置的时候发生了这个报错java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName.,那么就是这个配置项的问题。
@Configuration
public class DataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
@Primary
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
public JdbcTemplate masterJdbcTemplate(@Qualifier("masterDataSource") DataSource primaryDataSource) {
return new JdbcTemplate(primaryDataSource);
}
@Bean
public JdbcTemplate slaveJdbcTemplate(@Qualifier("slaveDataSource") DataSource secondaryDataSource) {
return new JdbcTemplate(secondaryDataSource);
}
}
数据源的创建,通过**@ConfigurationProperties** 可以知道这两个数据源分别加载了spring.datasource.master.*和spring.datasource.slave.*的配置然后初始化数据源。@Primary注解指定了主数据源,就是当我们不特别指定哪个数据源的时候,就会使用这个BeanJdbcTemplate。可以看到这两个JdbcTemplate创建的时候,分别注入了masterDataSource数据源和slaveDataSource数据源JdbcTemplate 的CRUD伪代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter37ApplicationTests {
@Autowired
protected JdbcTemplate masterJdbcTemplate;
@Autowired
protected JdbcTemplate slaveJdbcTemplate;
@Before
public void setUp() {
primaryJdbcTemplate.update("DELETE FROM USER ");
secondaryJdbcTemplate.update("DELETE FROM USER ");
}
@Test
public void test() throws Exception {
// 往第一个数据源中插入 2 条数据
masterJdbcTemplate.update("insert into user(name,age) values(?, ?)", "aaa", 20);
masterJdbcTemplate.update("insert into user(name,age) values(?, ?)", "bbb", 30);
// 往第二个数据源中插入 1 条数据,若插入的是第一个数据源,则会主键冲突报错
slaveJdbcTemplate.update("insert into user(name,age) values(?, ?)", "ccc", 20);
// 查一下第一个数据源中是否有 2 条数据,验证插入是否成功
Assert.assertEquals("2", masterJdbcTemplate.queryForObject("select count(1) from user", String.class));
// 查一下第一个数据源中是否有 1 条数据,验证插入是否成功
Assert.assertEquals("1", masterJdbcTemplate.queryForObject("select count(1) from user", String.class));
}
/**查询*/
@Test
public void userList() {
/**
* List 中的1个 Map 对应数据库的 1行数据
* Map 中的 key 对应数据库的字段名,value 对应数据库的字段值
*/
List<Map<String, Object>> mapList = masterJdbcTemplate.queryForList("SELECT * FROM phone");
}
//--------update 方法可以做查询以外的 增加、修改、删除操作---------------
/**新增*/
@Test
public void savePhone() {
String sql = "INSERT INTO phone(number,region) VALUES (?,?)";
Object[] objects = new Object[2];
objects[0] = "18673886425";
objects[1] = "湖南";
masterJdbcTemplate.update(sql, objects);
}
/**修改*/
@Test
public void updatePhone() {
String sql = "UPDATE phone SET number=? WHERE pid=?";
Object[] objects = new Object[2];
objects[0] = "18666668888";
objects[1] = "1";
masterJdbcTemplate.update(sql, objects);
}
/**删除*/
@Test
public void deletePhone() {
String sql = "DELETE FROM phone WHERE number=?";
Object[] objects = new Object[1];
objects[0] = "18673886425";
masterJdbcTemplate.update(sql, objects);
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</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>
配置多个数据源
spring:
datasource:
master:
# 基本属性 url、user、password
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 123456
slave:
# 基本属性 url、user、password
driver-class-name: com.mysql.jdbc.Driver
jdbc-url: jdbc:mysql://127.0.0.1:3306/slave_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 123456
有几个数据源就写几个配置类
master数据源的JPA配置:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactoryMaster",
transactionManagerRef="transactionManagerMaster",
basePackages= { "com.oyjp.master.repository" }) //设置Repository所在位置
public class MasterConfig {
@Autowired
@Qualifier("masterDataSource")
private DataSource masterDataSource;
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
private Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
@Primary
@Bean(name = "entityManagerMaster")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryMaster(builder).getObject().createEntityManager();
}
@Primary
@Bean(name = "entityManagerFactoryMaster")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryMaster(EntityManagerFactoryBuilder builder) {
return builder
.dataSource(masterDataSource)
.packages("com.oyjp.master.entity") //设置实体类所在位置
.persistenceUnit("masterPersistenceUnit")
.properties(getVendorProperties())
.build();
}
@Primary
@Bean(name = "transactionManagerMaster")
public PlatformTransactionManager transactionManagerMaster(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactoryMaster(builder).getObject());
}
}
slave数据源的JPA配置:
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
entityManagerFactoryRef="entityManagerFactorySlave",
transactionManagerRef="transactionManagerSlave",
basePackages= { "com.oyjp.slave.repository" }) //设置Repository所在位置
public class SecondaryConfig {
@Autowired
@Qualifier("slaveDataSource")
private DataSource slaveDataSource;
@Autowired
private JpaProperties jpaProperties;
@Autowired
private HibernateProperties hibernateProperties;
private Map<String, Object> getVendorProperties() {
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
}
@Bean(name = "entityManagerSlave")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactorySlave(builder).getObject().createEntityManager();
}
@Bean(name = "entityManagerFactorySlave")
public LocalContainerEntityManagerFactoryBean entityManagerFactorySlave (EntityManagerFactoryBuilder builder) {
return builder
.dataSource(slaveDataSource)
.packages("com.oyjp.slave.entity") //设置实体类所在位置
.persistenceUnit("secondaryPersistenceUnit")
.properties(getVendorProperties())
.build();
}
@Bean(name = "transactionManagerSlave")
PlatformTransactionManager transactionManagerSlave(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactorySlave(builder).getObject());
}
}
说明与注意:
@EnableJpaRepositories中指定Repository的所在位置指定Entity所在的位置主要注意在互相注入时候,不同数据源不同配置的命名,基本就没有什么大问题了
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter38ApplicationTests {
@Autowired
private UserRepository userRepository;
@Autowired
private MessageRepository messageRepository;
@Test
public void test() throws Exception {
userRepository.save(new User("aaa", 10));
userRepository.save(new User("bbb", 20));
userRepository.save(new User("ccc", 30));
userRepository.save(new User("ddd", 40));
userRepository.save(new User("eee", 50));
Assert.assertEquals(5, userRepository.findAll().size());
messageRepository.save(new Message("o1", "aaaaaaaaaa"));
messageRepository.save(new Message("o2", "bbbbbbbbbb"));
messageRepository.save(new Message("o3", "cccccccccc"));
Assert.assertEquals(3, messageRepository.findAll().size());
}
}
在 pom.xml 文件中添加上 Druid 数据源依赖
<?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>www.test.com</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>horse</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 引入Spring封装的jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 引入web项目启动模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入mysql数据库连接驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Spring Boot Mybatis 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!-- 引入 Druid 数据源依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<!-- 引入Spring Boot 测试模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins> </plugins>
<resources>
<!--src/main/resources下面所有文件打包-->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<!--src/main/java下面存在xml文件也打包进去,解决 mapper与xml映射文件处于同级目录下却无法找到文件-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
配置多个数据源
spring:
datasource:
druid:
master:
# 基本属性 url、user、password
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/master_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 123456
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 配置监控统计拦截的filters
filters: stat,wall,log4j2
# 配置初始化大小、最小、最大
initial-size: 5
max-active: 20
max-pool-prepared-statement-per-connection-size: 20
# 配置获取连接等待超时的时间
max-wait: 60000
min-idle: 5
pool-prepared-statements: true
test-on-borrow: false
test-on-return: false
test-while-idle: true
type: com.alibaba.druid.pool.DruidDataSource
validation-query: SELECT 1 FROM DUAL
validation-query-timeout: 30000
slave:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/slave_db?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 123456
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
filters: stat,wall,log4j2
initial-size: 5
max-active: 20
max-pool-prepared-statement-per-connection-size: 20
max-wait: 60000
min-idle: 5
pool-prepared-statements: true
test-on-borrow: false
test-on-return: false
test-while-idle: true
type: com.alibaba.druid.pool.DruidDataSource
validation-query: SELECT 1 FROM DUAL
validation-query-timeout: 30000
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DruidConfig {
/**
* 配置Druid监控
* 后台管理Servlet
* @return
*/
@Bean
public ServletRegistrationBean statViewServlet(){
//注册服务
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();
//这是配置的druid监控的登录密码
initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
// 白名单(为空表示,所有的都可以访问,多个IP的时候用逗号隔开)默认就是允许所有访问
initParams.put("allow", "127.0.0.1");
// IP黑名单 (存在共同时,deny优先于allow) (黑白名单就是如果是黑名单,那么该ip无法登陆该可视化界面)
initParams.put("deny", "127.0.0.2");
// 是否能够重置数据.
initParams.put("resetEnable", "false");
bean.setInitParameters(initParams);
return bean;
}
/**
* 配置web监控的filter
* @return
*/
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());
// 添加过滤规则
bean.setUrlPatterns(Arrays.asList("/*"));
// 添加过滤规则
Map<String,String> initParams = new HashMap<>();
// 添加不需要忽略的格式信息
initParams.put("exclusions","/static/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");//过滤掉需要监控的文件
initParams.put("profileEnable", "true");
initParams.put("principalCookieName", "USER_COOKIE");
initParams.put("principalSessionName", "USER_SESSION");
initParams.put("DruidWebStatFilter", "/*");
bean.setInitParameters(initParams);
return bean;
}
}
如果访问Druid监控平台的Spring监控没有数据

import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* spring监控配置
* @author
*/
@Configuration
public class SpringDaoMethodAspect {
@Bean
public DruidStatInterceptor druidStatInterceptor() {
DruidStatInterceptor dsInterceptor = new DruidStatInterceptor();
return dsInterceptor;
}
@Bean
@Scope("prototype")
public JdkRegexpMethodPointcut druidStatPointcut() {
JdkRegexpMethodPointcut pointcut = new JdkRegexpMethodPointcut();
pointcut.setPattern("com.yadu.example.demo.mapper.*");
return pointcut;
}
@Bean
public DefaultPointcutAdvisor druidStatAdvisor(DruidStatInterceptor druidStatInterceptor, JdkRegexpMethodPointcut druidStatPointcut) {
DefaultPointcutAdvisor defaultPointAdvisor = new DefaultPointcutAdvisor();
defaultPointAdvisor.setPointcut(druidStatPointcut);
defaultPointAdvisor.setAdvice(druidStatInterceptor);
return defaultPointAdvisor;
}
}
(有几个数据源就写几个配置类)
注意:数据源是在在第一次连接数据库的时候进行初始化的主数据源
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(
basePackages = "com.yadu.example.demo.mapper.master",
sqlSessionTemplateRef= "masterSqlSessionTemplate",
sqlSessionFactoryRef="masterSqlSessionFactory")
public class MasterDataSourceConfiguration {
/**创建数据源*/
@Bean(name = "masterDataSource")
@Primary //表示这个数据源是默认数据源, 这个注解必须要加,因为不加的话spring将分不清楚那个为主数据源(默认数据源)
//将spring.datasource.druid.master开头的配置映射成对象DruidDataSource
//也可以使用 @Value("${spring.datasource.druid.master.username:#{null}}") 指定属性映射
@ConfigurationProperties(prefix = "spring.datasource.druid.master")
public DataSource dataSource() {
return new DruidDataSource();
}
/**创建SessionFactory*/
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
// mapper的xml形式文件位置必须要配置,不然将报错:no statement (这种错误也可能是mapper的xml中,namespace与项目的路径不一致导致)
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapping/*.xml"));
return bean.getObject();
}
/**创建事务管理器*/
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager transactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/**创建SqlSessionTemplate*/
@Bean(name = "masterSqlSessionTemplate")
@Primary
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("masterSqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
@MapperScan注解来指定当前数据源下定义的Entity和Mapper的包路径另外需要指定sqlSessionFactory和sqlSessionTemplate,这两个具体实现在该配置类中类中初始化。主数据源,用 @Primary 标志该 Bean」application.properties 的 属性配置,并自动装配从数据源
import com.alibaba.druid.pool.DruidDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
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 org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;
@Configuration
@MapperScan(
basePackages = "com.yadu.example.demo.mapper.slave",
sqlSessionFactoryRef= "slaveSqlSessionTemplate",
sqlSessionFactoryRef="slaveSqlSessionFactory")
public class SlaverDataSourceConfiguration {
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.druid.slave")
public DataSource dataSource() {
return new DruidDataSource();
}
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
// 注入数据源
bean.setDataSource(dataSource);
// mapper的xml形式文件位置必须要配置,不然将报错:no statement (这种错误也可能是mapper的xml中,namespace与项目的路径不一致导致)
bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapping/*.xml"));
return bean.getObject();
}
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "slaveSqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate(@Qualifier("slaveSqlSessionFactory") SqlSessionFactory sqlSessionFactory)
throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
SessionFactory初始化时还可以指定配置文件的路径、mapper文件路径、实体类别名映射
配置如下:
@Configuration
public class SessionFactoryConfiguration {
// mybatis-config.xml配置文件的路径
@Value("${mybatis_config_file}")
private String mybatisConfigFilePath;
// mybatis mapper文件所在路径
@Value("${mapper_path}")
private String mapperPath;
// 实体类所在的package
@Value("${entity_package}")
private String entityPackage;
@Autowired
@Qualifier("dataSource")
private DataSource dataSource;
@Bean(name="sqlSessionFactory")
public SqlSessionFactoryBean createSqlSessionFactoryBean() throws IOException {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 扫描mybatis配置文件
sqlSessionFactoryBean.setConfigLocation(new ClassPathResource(mybatisConfigFilePath));
// 扫描相关mapper文件
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
String packageSearchPath = PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + mapperPath;
sqlSessionFactoryBean.setMapperLocations(resolver.getResources(packageSearchPath));
// 调用dataSource
sqlSessionFactoryBean.setDataSource(dataSource);
// 映射实体类
sqlSessionFactoryBean.setTypeAliasesPackage(entityPackage);
return sqlSessionFactoryBean;
}
DruidDataSourceAutoConfigure会注入一个DataSourceWrapper,其会在原生的spring.datasource下找 url, username, password 等。
排除方式有两种,一种是将上述配置文件排除
spring:
autoconfigure:
#去除durid配置
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
还有一种可以在项目启动类排除
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,DruidDataSourceAutoConfigure.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
这个时候,在yml文件当中就不能像单个数据源的时那样配置mapper的位置了:
mybatis:
mapper-locations: classpath:mapper/*.xml
http://localhost:9001/druid/datasource.html
数据源是在第一次请求数据库连接的时候初始化的

访问sql监控的时候,你可能会看到阿里巴巴的广告,如果想去掉,有两种方式
快速集成多数据源的启动器。支持 Jdk 1.7+, SpringBoot 1.5.x 和 2.x.x前缀即为组的名称,相同组名称的数据源会放在一个组下。spring.datasource.dynamic.primary 修改。service的类和方法上添加注解,不建议在mapper上添加注解。<?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>www.test.com</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>horse</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- 引入Spring封装的jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- 引入web项目启动模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--关键0: 引入mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--关键1: mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--关键2: 引入多数据源依赖dynamic-datasource-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!--关键3: 引入连接池druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
<scope>compile</scope>
</dependency>
<!-- 引入Spring Boot 测试模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins> </plugins>
<resources>
<!--src/main/resources下面所有文件打包-->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
<!--src/main/java下面存在xml文件也打包进去,解决 mapper与xml映射文件处于同级目录下却无法找到文件-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
</build>
</project>
配置多个数据源
spring:
datasource:
# druid登陆配置,登录地址为 ip:port/druid
druid:
stat-view-servlet:
enabled: true
loginUsername: xxx #登录名
loginPassword: xxx #登录密码
dynamic:
primary: master #设置默认的数据源或者数据源组,默认值即为master #指定默认数据源(命名必须为master开头否则会报错)
strict: false #设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
datasource:
master:
url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
slave_1:
url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave_2:
url: ENC(xxxxx) # 内置加密,使用请查看详细文档
username: ENC(xxxxx)
password: ENC(xxxxx)
driver-class-name: com.mysql.jdbc.Driver
schema: db/schema.sql # 配置则生效,自动初始化表结构
data: db/data.sql # 配置则生效,自动初始化数据
continue-on-error: true # 默认true,初始化失败是否继续
separator: ";" # sql默认分号分隔符
#......省略
#以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
# 多主多从 纯粹多库(记得设置primary) 混合配置
spring: spring: spring:
datasource: datasource: datasource:
dynamic: dynamic: dynamic:
datasource: datasource: datasource:
master_1: mysql: master:
master_2: oracle: slave_1:
slave_1: sqlserver: slave_2:
slave_2: postgresql: oracle_1:
slave_3: h2: oracle_2:
###MySQL druid多数据源配置(纯粹多库)###
spring:
datasource:
# druid登陆配置,登录地址为 ip:port/druid
druid:
stat-view-servlet:
enabled: true
loginUsername: admin #登录名
loginPassword: 123456 #登录密码
autoconfigure:
#去除durid配置
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
dynamic:
#指定默认数据源(必须配置,且名字必须为master开头否则会报错)
primary: master
#设置严格模式,默认false不启动. 启动后在未匹配到指定数据源时候回抛出异常,不启动会使用默认数据源.
strict: false
datasource:
#db01库
master:
driver-class-name: com.mysql.jdbc.Driver
password: root
url: jdbc:mysql://127.0.0.1:3306/db01?serverTimezone=GMT&useSSL=false
username: root
#db02库
db02:
driver-class-name: com.mysql.cj.jdbc.Driver
password: root
url: jdbc:mysql://127.0.0.1:3306/db02?serverTimezone=GMT&useSSL=false
username: toot
#数据源基础配置
druid:
# 通过connectProperties属性来打开mergeSql功能;慢SQL记录
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,slf4j
initial-size: 5
max-active: 20
max-pool-prepared-statement-per-connection-size: 20
# 配置获取连接等待超时的时间
max-wait: 6000
# 配置一个连接在池中最小生存的时间,单位是毫秒
min-evictable-idle-time-millis: 300000
min-idle: 5
pool-prepared-statements: true
test-on-borrow: false
test-on-return: false
test-while-idle: true
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
time-between-eviction-runs-millis: 60000
validation-query: 'SELECT 1 FROM DUAL '
如: 可以直接编写Mapper接口 或 继承BaseMapper <T> 接口, 就可以直接使用MybatisPlus内置的mapper层方法了。
public interface UserMapper extends BaseMapper<User> {}
| 注解 | 结果 |
|---|---|
| 没有@DS | 默认数据源 |
| @DS(“dsName”) | dsName可以为组名也可以为具体某个库的名称 |
@DS(“”)括号内即是application.properties中配置的数据源名称,不加注解默认是访问主库master通过spring.datasource.dynamic.primary设置,可加在service方法上,也可加在mapper方法上。. 强烈建议只在service的类和方法上添加注解,不建议在mapper上添加注解。方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。伪代码: 在service层调用这个mapper的方法,并且在在方法上添加@DS 验证效果。
@Service
@DS("slave")
public class UserServiceImpl implements UserService {
@Autowired
private JdbcTemplate jdbcTemplate;
public List<Map<String, Object>> selectAll() {
return jdbcTemplate.queryForList("select * from user");
}
@Override
@DS("master")
public List<Map<String, Object>> selectByCondition() {
return jdbcTemplate.queryForList("select * from user where age >10");
}
}
@DS("slave")
public interface UserMapper {
@Insert("INSERT INTO user (name,age) values (#{name},#{age})")
boolean addUser(@Param("name") String name, @Param("age") Integer age);
@Update("UPDATE user set name=#{name}, age=#{age} where id =#{id}")
boolean updateUser(@Param("id") Integer id, @Param("name") String name, @Param("age") Integer age);
@Delete("DELETE from user where id =#{id}")
boolean deleteUser(@Param("id") Integer id);
@Select("SELECT * FROM user")
@DS("master")
List<User> selectAll();
}
在启动类配置@MapperScan注解扫描Mapper层
在启动类@SpringBootApplication注解中,排除原生Druid的配置类。因为项目默认连接Druid的原生配置的mysql服务。
DruidDataSourceAutoConfigure会注入一个DataSourceWrapper,其会在原生的spring.datasource下找 url, username, password 等。//1.@MapperScan扫描Mapper层
@MapperScan("com.egos.web.*.mapper")
//2.排除原生Druid的配置类
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,DruidDataSourceAutoConfigure.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
访问 ip:port/druid,登录密码为


MyBatis-Plus官网文档
MyBatis-Plus-dynamic-datasource官方文档
dynamic-datasource-spring-boot-starter读写分离分析

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。