日常開發(fā)中,我們可能需要連接多個(gè)數(shù)據(jù)源娩脾,例如數(shù)據(jù)庫(kù)進(jìn)行了主從配置知市,寫操作走主庫(kù),讀操作走從庫(kù)活孩。本來(lái)結(jié)合Spring Boot + MyBatis + Druid 來(lái)演示如何配置多個(gè)數(shù)據(jù)源物遇。
1. 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">
<!-- Inherit defaults from Spring Boot -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-boot-mybatis3-multi-datasource</artifactId>
<packaging>jar</packaging>
<name>spring-boot-mybatis3-multi-datasource</name>
<url>http://maven.apache.org</url>
<properties>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
<druid.version>1.0.25</druid.version>
<mysql.connector.version>5.1.39</mysql.connector.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<!-- db-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.connector.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
</dependencies>
<build>
<finalName>spring-boot-mybatis3-multi-datasource</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
</project>
2. application.properties
mybatis.config-locations=classpath:mybatis-config.xml
spring.datasource.master.driverClassName=com.mysql.jdbc.Driver
spring.datasource.master.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8
spring.datasource.master.username=root
spring.datasource.master.password=root
spring.datasource.slave.driverClassName=com.mysql.jdbc.Driver
spring.datasource.slave.url=jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8
spring.datasource.slave.username=root
spring.datasource.slave.password=root
3. 數(shù)據(jù)源配置
多數(shù)據(jù)源配置的時(shí)候注意,必須要有一個(gè)主數(shù)據(jù)源(使用 @Primary 標(biāo)識(shí))憾儒,本例中即 MasterDataSourceConfig 配置:
package com.mindflow.springboot.mybatis.config.datasource;
import com.alibaba.druid.pool.DruidDataSource;
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 javax.sql.DataSource;
/**
* @author Ricky Fung
*/
@Configuration
@MapperScan(basePackages = MasterDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
static final String PACKAGE = "com.mindflow.springboot.mybatis.mapper.master";
static final String MAPPER_LOCATION = "classpath:mapper/master/*.xml";
@Value("${spring.datasource.master.url}")
private String url;
@Value("${spring.datasource.master.username}")
private String user;
@Value("${spring.datasource.master.password}")
private String password;
@Value("${spring.datasource.master.driverClassName}")
private String driverClass;
@Bean(name = "masterDataSource")
@Primary
public DataSource masterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
dataSource.setInitialSize(5);
dataSource.setMaxActive(50);
dataSource.setMinIdle(0);
return dataSource;
}
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource());
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(masterDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(MasterDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
@Primary 標(biāo)志這個(gè) Bean 如果在多個(gè)同類 Bean 候選時(shí)询兴,該 Bean 優(yōu)先被考慮∑鹬海「多數(shù)據(jù)源配置的時(shí)候注意诗舰,必須要有一個(gè)主數(shù)據(jù)源,用 @Primary 標(biāo)志該 Bean」训裆;
@MapperScan 掃描 Mapper 接口并容器管理眶根,包路徑精確到 master,為了和下面 slave數(shù)據(jù)源做到精確區(qū)分缭保;
sqlSessionFactoryRef 表示定義了 key 汛闸,表示一個(gè)唯一 SqlSessionFactory 實(shí)例。
同理艺骂,SlaveDataSourceConfig 如下:
package com.mindflow.springboot.mybatis.config.datasource;
import com.alibaba.druid.pool.DruidDataSource;
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 javax.sql.DataSource;
/**
* @author Ricky Fung
*/
@Configuration
@MapperScan(basePackages = SlaveDataSourceConfig.PACKAGE, sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourceConfig {
static final String PACKAGE = "com.mindflow.springboot.mybatis.mapper.slave";
static final String MAPPER_LOCATION = "classpath:mapper/slave/*.xml";
@Value("${spring.datasource.slave.url}")
private String url;
@Value("${spring.datasource.slave.username}")
private String user;
@Value("${spring.datasource.slave.password}")
private String password;
@Value("${spring.datasource.slave.driverClassName}")
private String driverClass;
@Bean(name = "slaveDataSource")
public DataSource clusterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUrl(url);
dataSource.setUsername(user);
dataSource.setPassword(password);
dataSource.setInitialSize(5);
dataSource.setMaxActive(50);
return dataSource;
}
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager clusterTransactionManager() {
return new DataSourceTransactionManager(clusterDataSource());
}
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory clusterSqlSessionFactory(@Qualifier("slaveDataSource") DataSource clusterDataSource)
throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(clusterDataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources(SlaveDataSourceConfig.MAPPER_LOCATION));
return sessionFactory.getObject();
}
}
4. service層
service照常注入了兩個(gè) DAO诸老,如同以前一樣正常工作。不用關(guān)心和指定到具體說(shuō)明數(shù)據(jù)源。
UserService :
package com.mindflow.springboot.mybatis.service.impl;
import com.mindflow.springboot.mybatis.domain.UserDO;
import com.mindflow.springboot.mybatis.domain.UserDOExample;
import com.mindflow.springboot.mybatis.mapper.master.UserDOMapper;
import com.mindflow.springboot.mybatis.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Ricky Fung
*/
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDOMapper userDOMapper;
@Override
public UserDO getUserByName(String username) {
UserDOExample example = new UserDOExample();
List<UserDO> list = userDOMapper.selectByExample(example);
if(list==null || list.isEmpty()) {
return null;
}
return list.get(0);
}
@Override
public int insert(UserDO userDO) {
return userDOMapper.insertSelective(userDO);
}
}
OrderService :
package com.mindflow.springboot.mybatis.service.impl;
import com.mindflow.springboot.mybatis.domain.OrderDO;
import com.mindflow.springboot.mybatis.domain.OrderDOExample;
import com.mindflow.springboot.mybatis.mapper.slave.OrderDOMapper;
import com.mindflow.springboot.mybatis.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author Ricky Fung
*/
@Service
public class OrderServiceImpl implements OrderService {
@Autowired
private OrderDOMapper orderDOMapper;
@Override
public List<OrderDO> getOrders(Long userId) {
OrderDOExample example = new OrderDOExample();
example.createCriteria().andUserIdEqualTo(userId);
return orderDOMapper.selectByExample(example);
}
@Override
public int insert(OrderDO orderDO) {
return orderDOMapper.insert(orderDO);
}
}