Springcloud+Mybatis使用多数据源的四种方式(小结)

当我们使用SpringCloud和Mybatis时,有时需要使用多数据源来访问不同的数据库。下面介绍四种实现方式。

方式一:使用Mybatis-Plus

Mybatis-Plus 是一个 MyBatis 的增强工具,提供了许多方便的功能,其中就包括多数据源的支持。

  1. 引入 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

  1. 配置多数据源

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

  1. 使用注解配置数据源和事务

```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 实现多数据源

  1. 创建数据源配置类,动态获取数据源

```java
public class DynamicDataSource extends AbstractRoutingDataSource {

   @Override
   protected Object determineCurrentLookupKey() {
       return DynamicDataSourceContextHolder.getDataSourceKey();
   }

}
```

  1. 创建数据源上下文类,存储当前线程的数据源 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();
   }

}
```

  1. 在切面中拦截指定方法,根据方法名称判断数据源

```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

  1. 在配置文件中定义数据源

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

  1. 在代码中使用 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

  1. 在配置文件中定义数据源

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

  1. 创建数据源工厂

```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);
   }

}
```

  1. 在代码中指定数据源

```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 实现多数据源的方法,按照自己的场景选择适合的方法即可。

下面是示例代码:

  1. SpringCloud-Mybatis-Plus
  2. SpringCloud-MultipleDataSource

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Springcloud+Mybatis使用多数据源的四种方式(小结) - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Java List转换成String数组几种实现方式详解

    Java List转换成String数组几种实现方式详解 问题描述 在Java开发中,我们经常会遇到将List转换成String数组的需求,比如将数据库查询结果转换为字符串数组进行后续处理。那么如何实现List转换为String数组呢?本文将详细介绍几种实现方式,以供大家参考使用。 方案一:使用循环遍历 最基本的实现方式是使用循环遍历List,逐个转换为字符…

    Java 2023年5月26日
    00
  • Android解析json数据示例代码(三种方式)

    下面我来为您提供关于“Android解析json数据示例代码(三种方式)”的完整攻略。 Android解析json数据示例代码(三种方式) 在 Android 应用开发中,我们需要经常与后端 API 接口进行数据交互,并解析 JSON 格式的数据。本文将介绍三种常用的 Android 解析 JSON 数据的方法。 GSON GSON 是 Google 推出的…

    Java 2023年5月26日
    00
  • Java对象深复制与浅复制实例详解

    Java对象深复制与浅复制实例详解 在 Java 中,对象的复制分为浅复制和深复制两种方式。本文将详细讲解 Java 中对象复制的概念、浅复制和深复制的实现方式、以及深浅复制的应用场景。 对象复制的概念 在 Java 中,我们可以通过 new 运算符来生成新的对象实例,但是有时候我们需要创建一个新对象,它的属性和原对象一模一样而且它们内存地址不同,这个时候就…

    Java 2023年5月26日
    00
  • 基础不牢,地动山摇,Java基础速来刷刷

    基础不牢,地动山摇,Java基础速来刷刷攻略 1. 基础概念的理解 在学习 Java 的过程中,首先需要掌握一些基础概念,例如:JVM、JRE、JDK、类、对象、接口、继承、多态、异常等等。这些基础概念是 Java 编程的基石,如果不牢固掌握这些基础概念,日后的 Java 编程会遇到很多问题。 2. 编程语言和工具的熟练掌握 在掌握了基础概念后,需要熟练掌握…

    Java 2023年5月26日
    00
  • java.lang.Runtime.exec() Payload知识点详解

    下面我将详细讲解一下“java.lang.Runtime.exec() Payload知识点详解”的完整攻略。 什么是java.lang.Runtime.exec() Payload? java.lang.Runtime.exec()是Java语言中一个可以执行外部命令的方法。正常使用该方法可以很方便地执行各种系统命令,功能非常强大。但是,当我们在执行该方法…

    Java 2023年5月20日
    00
  • mybatis深入讲解resultMap的定义及用法

    MyBatis深入讲解resultMap的定义及用法 在使用MyBatis进行数据操作时,查询结果可能会被映射到Java对象中或者直接返回Map类型数据,而MyBatis提供了resultMap来帮助我们自定义查询结果的映射方式。本文将详细介绍resultMap的定义及用法。 ResultMap定义 resultMap是一个非常重要的MyBatis配置元素,…

    Java 2023年5月20日
    00
  • Java Web端程序实现文件下载的方法分享

    首先我们需要了解Java Web端程序实现文件下载的基本流程。在Java Web项目中,文件下载的基本流程如下: 客户端发送下载请求。 服务器端根据请求的文件路径和文件名,读取文件并将文件流写入response输出流。 客户端接收到服务器返回的文件流后,将文件流写入本地文件。 具体实现方法如下: 首先定义一个Servlet处理文件下载请求,实现Servlet…

    Java 2023年5月19日
    00
  • Java Apache Commons报错“IllegalStateException”的原因与解决方法

    当使用Java的Apache Commons类库时,可能会遇到“IllegalStateException”错误。这个错误通常由以下原因之一起: 对象状态不正确:如果对象状态不正确,则可能会出现此错误。在这种情况下,需要确保对象状态正确。 方法调用不正确:如果方法调用不正确,则可能会出现此错误。在这种情况下,需要确保正确调用方法。 以下是两个实例: 例1 如…

    Java 2023年5月5日
    00
合作推广
合作推广
分享本页
返回顶部