pom.xml
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.1.0version>
dependency>
添加配置 application.yml
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql:///bank? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
username: root
password: 123456
mybatis:
# 扫描 mapper.xml 文件路径
mapper-locations: classpath:mapper/*.xml
定义接口 com.demo.mapper.UserMapper
public interface UserMapper {
List<User> findAll();
}
编写 xml 文件 mapper/UserMapper.xml
<mapper namespace="com.demo.mapper.UserMapper">
<select id="findAll" resultType="com.demo.pojo.User">
select * from user
select>
mapper>
添加配置 application.yml
spring:
datasource:
master:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql:///bank? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
username: root
password: 123456
slave:
driver-class-name: com.mysql.cj.jdbc.Driver
jdbc-url: jdbc:mysql:///test? useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
根据配置生成 DataSource
@Configuration
public class MultipleDataSourceConfig {
@Bean("masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
private DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean("slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
private DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
}
将生成的 DataSource 放入 targetDataSources 这个 Map中
@Configuration
public class PrimaryDataSourceConfig {
@Autowired
@Qualifier("masterDataSource")
private DataSource masterDataSource;
@Autowired
@Qualifier("slaveDataSource")
private DataSource slaveDataSource;
@Bean
@Primary
DataSource primaryDataSource() {
Map<Object, Object> map = new HashMap<>();
map.put("masterDataSource", masterDataSource);
map.put("slaveDataSource", slaveDataSource);
RoutingDataSource routing = new RoutingDataSource();
routing.setTargetDataSources(map);
return routing;
}
}
继承 AbstractRoutingDataSource 返回需要使用的 数据源的 key
public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return "masterDataSource";
}
}
此时 key 不能写死,将 key 放入 ThreadLocal 中
public class RoutingDataSourceContext {
private static final ThreadLocal<String> threadLocalDataSourceKey = new ThreadLocal<>();
// 获取数据源的 key
public static String getDataSourceRoutingKey() {
String key = threadLocalDataSourceKey.get();
return key == null ? "masterDataSource" : key;
}
// 往 ThreadLocal 中设置 key
public RoutingDataSourceContext(String key) {
threadLocalDataSourceKey.set(key);
}
// 移除 ThreadLocal 中的 key
public void close() {
threadLocalDataSourceKey.remove();
}
}
// 进行设置 key
// RoutingDataSourceContext routingDataSourceContext = new RoutingDataSourceContext("slaveDataSource");
public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return RoutingDataSourceContext.getDataSourceRoutingKey();
}
}
此时每次调用方法都需要设置数据源的 key,可以按照 AOP 思想,将设置 key 的方法提取出来
定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RoutingWith {
String value() default "masterDataSource";
}
@Aspect
@Component
public class RoutingAspect {
@Around("@annotation(routingWith)")
public Object routingWithDataSource(ProceedingJoinPoint joinPoint, RoutingWith routingWith) throws Throwable {
String key = routingWith.value();
RoutingDataSourceContext ctx = new RoutingDataSourceContext(key);
return joinPoint.proceed();
}
}
@RequestMapping("/findAll")
// 该注解能够判断使用哪个数据源
@RoutingWith("slaveDataSource")
public List<User> findAll() {
return userMapper.findAll();
}
pom.xml
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
定义接口
public interface UserRepository extends JpaRepository<User, Integer> {}
application.yml 配置同上
根据配置生成 DataSource
@Configuration
public class MultipleDataSourceConfig {
// 此处和 Mybatis 的设置区别,需要 @Primary
@Primary
@Bean("masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
DataSource masterDataSource() {
System.out.println("create master datasource...");
return DataSourceBuilder.create().build();
}
@Bean("slaverDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
DataSource slaveDataSource() {
System.out.println("create slave datasource...");
return DataSourceBuilder.create().build();
}
}
根据两个 DataSource 生成 entityManager
@Configuration
@EnableJpaRepositories(
// //配置连接工厂 entityManagerFactory
entityManagerFactoryRef = "entityManagerFactoryMaster",
// com.demo.repository 为 repository 接口所在的目录
basePackages = {"com.demo.repository"}
)
public class MasterDataSourceConfig {
@Autowired
@Qualifier("masterDataSource")
private DataSource dataSourceMaster;
@Primary
@Bean("entityManagerMaster")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryBean(builder).getObject().createEntityManager();
}
@Primary
@Bean("entityManagerFactoryMaster")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
// com.demo.pojo 为实体类所在目录
return builder.dataSource(dataSourceMaster).packages("com.demo.pojo").build();
}
}
@Configuration
@EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactorySlave",
basePackages = {"com.demo.slaveRepository"}
)
public class SlaveDataSourceConfig {
@Autowired
@Qualifier("slaverDataSource")
private DataSource dataSource;
@Bean("entityManagerSlave")
public EntityManager entityManager(EntityManagerFactoryBuilder builder) {
return entityManagerFactoryBean(builder).getObject().createEntityManager();
}
@Bean("entityManagerFactorySlave")
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(EntityManagerFactoryBuilder builder) {
return builder.dataSource(dataSource).packages("com.demo.slave").build();
}
}
定义 repository 接口
public interface MasterUserRepository extends JpaRepository<User, Integer> {}
public interface SlaveUserRepository extends JpaRepository<User, Integer> {}
@Autowired
private masterUserRepository userRepository;
List<User> all = userRepository.findAll();
@Repository("masterUserRepository")
public interface UserRepository extends JpaRepository<User, Integer> {}
@Repository("slaveUserRepository")
public interface UserRepository extends JpaRepository<User, Integer> {}
@Autowired
@Qualifier("masterUserRepository")
private UserRepository userRepository;
List<User> all = userRepository.findAll();
参考git:https://gitee.com/zhangyizhou/learning-spring-boot-datasource-demo.git