当我们使用SpringCloud和Mybatis时,有时需要使用多数据源来访问不同的数据库。下面介绍四种实现方式。
方式一:使用Mybatis-Plus
Mybatis-Plus 是一个 MyBatis 的增强工具,提供了许多方便的功能,其中就包括多数据源的支持。
- 引入 mybatis-plus-boot-starter 依赖
xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus.version}</version>
</dependency>
需要设置 mybatis-plus.mapper-locations
属性,指定 mapper 文件的位置:
properties
mybatis-plus.mapper-locations=classpath:/mapper/**/*Mapper.xml
- 配置多数据源
application.yml
yaml
spring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://localhost:3306/master?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
- 使用注解配置数据源和事务
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@DataSource("master")
@Transactional(rollbackFor = Exception.class)
public void addUser(User user) {
userMapper.insert(user);
}
@Override
@DataSource("slave")
public List<User> findAllUsers() {
return userMapper.selectList(null);
}
}
```
@DataSource 是自定义注解,用来指定数据源,实现如下:
java
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value() default "master";
}
方式二:使用 aop 和 ThreadLocal 实现多数据源
- 创建数据源配置类,动态获取数据源
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceContextHolder.getDataSourceKey();
}
}
```
- 创建数据源上下文类,存储当前线程的数据源 key
```java
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceKey(String dataSourceKey) {
contextHolder.set(dataSourceKey);
}
public static String getDataSourceKey() {
return contextHolder.get();
}
public static void clearDataSourceKey() {
contextHolder.remove();
}
}
```
- 在切面中拦截指定方法,根据方法名称判断数据源
```java
@Slf4j
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("execution(* com.example.demo.service.*.*(..))")
private void serviceAspect() {
}
@Before("serviceAspect()")
public void before(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
if (methodName.startsWith("get")) {
DynamicDataSourceContextHolder.setDataSourceKey("slave");
} else {
DynamicDataSourceContextHolder.setDataSourceKey("master");
}
log.info("data source switch to [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
}
@After("serviceAspect()")
public void after() {
DynamicDataSourceContextHolder.clearDataSourceKey();
log.info("data source cleared");
}
}
```
方式三:使用 JdbcTemplate
- 在配置文件中定义数据源
yaml
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
- 在代码中使用 JdbcTemplate 访问数据
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("masterJdbcTemplate")
private JdbcTemplate masterJdbcTemplate;
@Autowired
@Qualifier("slaveJdbcTemplate")
private JdbcTemplate slaveJdbcTemplate;
@Override
public void addUser(User user) {
masterJdbcTemplate.update("INSERT INTO user(id, name) VALUES (?,?)", user.getId(), user.getName());
}
@Override
public List<User> findAllUsers() {
return slaveJdbcTemplate.query("SELECT * FROM user", new BeanPropertyRowMapper<>(User.class));
}
}
```
DataSource 的配置类:
```java
@Configuration
public class DataSourceConfig {
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "masterJdbcTemplate")
public JdbcTemplate masterJdbcTemplate(@Qualifier("masterDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "slaveJdbcTemplate")
public JdbcTemplate slaveJdbcTemplate(@Qualifier("slaveDataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
```
方式四:使用 SqlSessionFactory
- 在配置文件中定义数据源
yaml
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave?characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
- 创建数据源工厂
```java
@Configuration
public class DataSourceConfig {
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
public DataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
targetDataSources.put("slave", slaveDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(masterDataSource);
return dataSource;
}
@Bean(name = "masterSqlSessionFactory")
@Primary
public SqlSessionFactory masterSqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResource("classpath*:mapper/*/*Mapper.xml"));
return sessionFactoryBean.getObject();
}
@Bean(name = "slaveSqlSessionFactory")
public SqlSessionFactory slaveSqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource);
sessionFactoryBean.setMapperLocations(
new PathMatchingResourcePatternResolver().getResource("classpath*:mapper/*/*Mapper.xml"));
return sessionFactoryBean.getObject();
}
@Bean(name = "masterTransactionManager")
@Primary
public DataSourceTransactionManager masterTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "slaveTransactionManager")
public DataSourceTransactionManager slaveTransactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
```
- 在代码中指定数据源
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("masterSqlSessionFactory")
private SqlSessionFactory masterSqlSessionFactory;
@Autowired
@Qualifier("slaveSqlSessionFactory")
private SqlSessionFactory slaveSqlSessionFactory;
@Override
public void addUser(User user) {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(masterSqlSessionFactory);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.insert(user);
sqlSession.commit();
SqlSessionUtils.closeSqlSession(sqlSession, masterSqlSessionFactory);
}
@Override
public List<User> findAllUsers() {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(slaveSqlSessionFactory);
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> users = userMapper.selectAll();
SqlSessionUtils.closeSqlSession(sqlSession, slaveSqlSessionFactory);
return users;
}
}
```
以上就是四种使用 SpringCloud 和 Mybatis 实现多数据源的方法,按照自己的场景选择适合的方法即可。
下面是示例代码:
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springcloud+Mybatis使用多数据源的四种方式(小结) - Python技术站