MySQL-SpringBoot集成JPA实现数据读写分离

https://blog.csdn.net/Anbang713/article/details/83240353

在上篇博客《MySQL-主从复制之同步主从数据》中,我们实现了读库和写库的数据同步。今天,我们继续学习SpringBoot集成JPA如何实现数据读写分离。废话不多话直接上代码。

一、配置数据源

1.  # 数据源
2.  spring.datasource.druid.write.url=jdbc:mysql://localhost:3380/test
3.  spring.datasource.druid.write.username=root
4.  spring.datasource.druid.write.password=Anbang713
5.  spring.datasource.druid.write.driver-class-name=com.mysql.jdbc.Driver
6.   
7.  spring.datasource.druid.read.url=jdbc:mysql://localhost:3381/test
8.  spring.datasource.druid.read.username=root
9.  spring.datasource.druid.read.password=Anbang713
10.  spring.datasource.druid.read.driver-class-name=com.mysql.jdbc.Driver
11.   
12.  # JPA
13.  spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
14.  spring.jpa.database=mysql
15.  spring.jpa.generate-ddl=false
16.  spring.jpa.hibernate.ddl-auto=none
17.  spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.DefaultComponentSafeNamingStrategy
18.  spring.jpa.show-sql=false

二、数据源配置类

1.  /**
2.   * 数据源配置
3.   * 
4.   * @author Administrator
5.   *
6.   */
7.  @Configuration
8.  public class DataSourceConfig {
9.   
10.    public final static String WRITE_DATASOURCE_KEY = "writeDruidDataSource";
11.    public final static String READ_DATASOURCE_KEY = "readDruidDataSource";
12.   
13.    @ConfigurationProperties(prefix = "spring.datasource.druid.read")
14.    @Bean(name = READ_DATASOURCE_KEY)
15.    public DataSource readDruidDataSource() {
16.      return new DruidDataSource();
17.    }
18.   
19.    @ConfigurationProperties(prefix = "spring.datasource.druid.write")
20.    @Bean(name = WRITE_DATASOURCE_KEY)
22.    public DataSource writeDruidDataSource() {
23.      return new DruidDataSource();
24.    }
25.   
26.    /**
27.     * 注入AbstractRoutingDataSource
28.     * 
29.     * @param readDruidDataSource
30.     * @param writeDruidDataSource
31.     * @return
32.     * @throws Exception
33.     */
34.    @Bean
34.    @Primary
35.    public AbstractRoutingDataSource routingDataSource(
36.        @Qualifier(READ_DATASOURCE_KEY) DataSource readDruidDataSource,
37.        @Qualifier(WRITE_DATASOURCE_KEY) DataSource writeDruidDataSource) throws Exception {
38.      DynamicDataSource dataSource = new DynamicDataSource();
39.      Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
40.      targetDataSources.put(WRITE_DATASOURCE_KEY, writeDruidDataSource);
41.      targetDataSources.put(READ_DATASOURCE_KEY, readDruidDataSource);
42.      dataSource.setTargetDataSources(targetDataSources);// 配置数据源
43.      dataSource.setDefaultTargetDataSource(writeDruidDataSource);// 默认为主库用于写数据
44.      return dataSource;
45.    }
46.  }

三、使用ThreadLocal使数据源与线程绑定

1.  public class DynamicDataSourceHolder {
2.    // 使用ThreadLocal把数据源与当前线程绑定
3.    private static final ThreadLocal<String> dataSources = new ThreadLocal<String>();
4.   
5.    public static void setDataSource(String dataSourceName) {
6.      dataSources.set(dataSourceName);
7.    }
8.   
9.    public static String getDataSource() {
10.      return (String) dataSources.get();
11.    }
12.   
13.    public static void clearDataSource() {
14.      dataSources.remove();
15.    }
16.  }

四、动态数据源配置

1.  public class DynamicDataSource extends AbstractRoutingDataSource {
2.   
3.    @Override
4.    protected Object determineCurrentLookupKey() {
5.      // 可以做一个简单的负载均衡策略
6.      String lookupKey = DynamicDataSourceHolder.getDataSource();
7.      System.out.println("------------lookupKey---------" + lookupKey);
8.      return lookupKey;
9.    }
10.  }

五、自定义注解

1.  @Target({
2.      ElementType.METHOD, ElementType.TYPE })
3.  @Retention(RetentionPolicy.RUNTIME)
4.  @Documented
5.  public @interface TargetDateSource {
6.    String dataSource() default "";// 数据源
7.  }

六、定义切面,实现数据源切换

1.  @Aspect
2.  @Component
3.  public class DynamicDataSourceAspect {
4.   
5.    @Around("execution(public * com.study.mysql.jpa.core..*.*(..))")
6.    public Object around(ProceedingJoinPoint pjp) throws Throwable {
7.      MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
8.      Method targetMethod = methodSignature.getMethod();
9.      if (targetMethod.isAnnotationPresent(TargetDateSource.class)) {
10.        String targetDataSource = targetMethod.getAnnotation(TargetDateSource.class).dataSource();
11.        System.out.println("----------数据源是:" + targetDataSource + "------");
12.        DynamicDataSourceHolder.setDataSource(targetDataSource);
13.      }
14.      // 执行方法
15.      Object result = pjp.proceed();
16.      DynamicDataSourceHolder.clearDataSource();
17.      return result;
18.    }
19.  }

在完成上面的相关配置后,我们写个简单的学生增删改查接口做测试。至此,我们的项目结构是这样的:

当然在这里,我们有必要看一下业务层实现类的代码,通过注解@TargetDataSource注解实现读写分离。

1.  @Service
2.  public class StudentServiceImpl implements StudentService {
3.   
4.    @Autowired
5.    private StudentDao studentDao;
6.   
7.    @Override
8.    @TargetDateSource(dataSource = DataSourceConfig.READ_DATASOURCE_KEY)
9.    public List<Student> findAll() {
10.      return studentDao.findAll();
11.    }
12.   
13.    @Override
14.    @TargetDateSource(dataSource = DataSourceConfig.READ_DATASOURCE_KEY)
15.    public Student findById(Integer id) {
16.      Optional<Student> students = studentDao.findById(id);
17.      if (students.isPresent() && students.get() != null) {
18.        return students.get();
19.      }
20.      return null;
21.    }
22.   
23.    @Override
24.    @Transactional
25.    @TargetDateSource(dataSource = DataSourceConfig.WRITE_DATASOURCE_KEY)
26.    public Integer save(Student entity) throws Exception {
27.      if (entity.getId() != null) {
28.        Student perz = studentDao.saveAndFlush(entity);
29.        return perz.getId();
30.      }
31.      Student perz = studentDao.save(entity);
32.      return perz.getId();
33.    }
34.   
35.  }

七、测试

启动SpringBoot启动类,并通过http://localhost:8080/swagger-ui.html访问我们的学生类接口。在测试之前,我们现在看下数据库的数据。可以看到我们的主从数据库数据是一样的。(MySQL5.6-3380为主数据库,用于写数据;MySQL5.6-3381为从数据库,用于读数据)

那么我们现在往数据库插入一条数据,执行save接口:

首先可以看到,在切面类中打印的日志,已经实现数据源的自动切换了。

然后我们看下数据库的数据,可以看到两边的数据是一模一样的。

最后,我们测试一下读的时候是从哪个数据源读的。

可以看到,在读请求的时候,是从从数据库读的数据。至此,我们使用SpringBoot集成JPA实现读写分离的目的已经达到。

源代码地址: MySQL: SpringBoot集成JPA实现MySQL数据库的读写分离

参考博客:https://www.jb51.net/article/111588.htm

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值