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与Spring boot后端项目Bug超全总结

    Java与Spring Boot后端项目Bug超全总结 为什么会有Bug Bug是不可避免的,尤其是在软件开发的过程中。它们可能由多种原因引起,例如人为疏忽、缺少测试、设计错误或未能理解业务需求。在Java和Spring Boot后端项目中,由于开发过程通常比较复杂,可能出现更多的Bug。以下是一些解决这些问题的技术和策略。 解决Bug的技巧和策略 1. 编…

    Java 2023年6月16日
    00
  • Java图形化界面编程介绍

    针对Java图形化界面编程介绍,我将会提供一份完整的攻略。 1. 什么是Java图形化界面编程 Java图形化界面编程指的是使用Java语言进行设计、开发和创建GUI(graphical user interface)应用程序。通过GUI应用程序,用户可以使用鼠标、键盘等人机交互方式方便地与应用程序进行交互。Java图形化界面编程主要涉及以下知识点: 1.1…

    Java 2023年5月23日
    00
  • Hibernate中5个核心接口知识点整理

    当我们使用Hibernate进行数据库操作时,会经常接触到如下5个核心接口: SessionFactory Session Transaction Query Criteria 它们分别是什么,有何作用?下面我们进行详细讲解。 SessionFactory SessionFactory是Hibernate的核心接口之一,通常也是Hibernate启动过程中的…

    Java 2023年5月19日
    00
  • struts2框架入门

    当你想开发一个Java Web应用程序时,一些的Java Web框架可以大大简化开发过程。其中,Struts2框架是一个非常流行的Java Web框架,这里为你提供Struts2框架入门的完整攻略。 Struts2框架入门 1. Struts2框架概述 Struts 2是一个Web框架,是基于MVC(模型视图控制器)设计模式的开源框架。它是Struts 1.…

    Java 2023年5月20日
    00
  • java实现输出任意整数的每一位

    下面是java实现输出任意整数的每一位的完整攻略。 步骤一:将整数转成字符串 我们知道,字符串中每个字符都可以通过下标访问。所以,我们只需要将整数转换成字符串,就可以通过下标依次访问每个数字了。 int num = 123456; String numStr = String.valueOf(num); // 将整数转换成字符串 步骤二:遍历字符串,输出每一…

    Java 2023年5月26日
    00
  • Java使用线程池执行定时任务

    使用线程池执行定时任务是提高 Java 程序性能的重要手段之一。下面就来详细讲解 Java 使用线程池执行定时任务的完整攻略。 1. 什么是线程池? 线程池是一种线程管理机制,它主要解决两个问题:线程复用和线程管理。线程池中维护了一组已经创建好的线程,供我们执行任务,这样就避免了每次执行任务都需要创建和销毁线程的开销。 2. Java 如何使用线程池执行定时…

    Java 2023年5月19日
    00
  • JVM Tomcat性能实战(推荐)

    下面是针对“JVM Tomcat性能实战(推荐)”的完整攻略: 1. 了解JVM和Tomcat 在开始优化之前,需要了解JVM和Tomcat的基本知识。JVM是Java虚拟机,用于运行Java代码。Tomcat是一个流行的Web应用程序服务器,常用于运行Java Web应用程序。 2. 性能测试 在进行优化之前,需要先进行性能测试。可以使用各种工具进行测试,…

    Java 2023年5月20日
    00
  • SpringBoot设置动态定时任务的方法详解

    Spring Boot设置动态定时任务的方法详解 在Spring Boot中,我们可以使用Spring Task来实现定时任务。本文将详细讲解如何使用Spring Task设置动态定时任务,并提供两个示例。 1. 动态定时任务的概念 动态定时任务是指可以在运行时动态添加、修改和删除的定时任务。相比于静态定时任务,动态定时任务更加灵活和可扩展。 2. 动态定时…

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