• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Spring boot实现数据库读写分离的方法

springboot 搞代码 4年前 (2022-01-09) 11次浏览 已收录 0个评论

背景

数据库配置主从之后,如何在代码层面实现读写分离?

用户自定义设置数据库路由

Spring boot提供了AbstractRoutingDataSource根据用户定义的规则选择当前的数据库,这样我们可以在执行查询之前,设置读取从库,在执行完成后,恢复到主库。

实现可动态路由的数据源,在每次数据库查询操作前执行

ReadWriteSplitRoutingDataSource.java

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * @author songrgg * @since 1.0 */public class ReadWriteSplitRoutingDataSource extends AbstractRoutingDataSource {  @Override  protected Object determineCurrentLookupKey() {    return DbContextHolder.getDbType();  }}

线程私有路由配置,用于ReadWriteSplitRoutingDataSource动态读取配置

DbContextHolder.java

/** * @author songrgg * @since 1.0 */public class DbContextHolder {  public enum DbType {    MASTER,    SLAVE  }   private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();   public static void setDbType(DbType dbType) {    if(dbType == null){      throw new NullPointerException();    }    contextHolder.set(dbType);  }   public static DbType getDbType() {    return contextHolder.get() == null ? DbType.MASTER : contextHolder.get();  }   public static void clearDbType() {    contextHolder.remove();  }}

AOP优化代码

利用AOP将设置数据库的操作从代码中抽离,这里的粒度控制在方法级别,所以利用注解的形式标注这个方法涉及的数据库事务只读,走从库。

只读注解,用于标注方法的数据库操作只走从库。

ReadOnlyConnection.java

package com.wallstreetcn.hatano.config; import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; /** * Indicates the database operations is bound to the slave database. * AOP interceptor will set the database to the slave with this interface. * @author songrgg * @since 1.0 */@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface ReadOnlyConnection {}

ReadOnlyConnectionInterceptor.java

import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.Ordered;import org.springframework.stereotype.Component; /** * Intercept the database operations, bind database to read-only database as this annotation * is applied. * @author songrgg * @since 1.0 */@Aspect@Componentpublic class ReadOnlyConnectionInterceptor implements Ordered {   private static final Logger logger = LoggerFactory.getLogger(ReadOnlyConnectionInterceptor.class);   @Around("@annotation(readOnlyConnection)")  public Object proceed(ProceedingJoinPoint proceedingJoinPoint, ReadOnlyConnection readOnlyConnection) throws Throwable {    try {      logger.info("set database connection to read only");      DbContextHolder.setDbType(DbContextHolder.DbType.SLAVE);      Object result = proceedingJoinPoint.proceed();      return result;    } finally {      DbContextHolder.clearDbType();      logger.info("restore database connection");    }  }   @Override  public int getOrder() {    return 0;  }}

User本文来源gaodai$ma#com搞$$代**码网Service.java

@ReadOnlyConnectionpublic List<User> getUsers(Integer page, Integer limit) {  return repository.findAll(new PageRequest(page, limit));}

配置Druid数据库连接池

build.gradle

compile("com.alibaba:druid:1.0.18")

groovy依赖注入

配置dataSource为可路由数据源

context.groovy

import com.alibaba.druid.pool.DruidDataSourceimport DbContextHolderimport ReadWriteSplitRoutingDataSource ** SOME INITIALIZED CODE LOAD PROPERTIES **def dataSourceMaster = new DruidDataSource()dataSourceMaster.url = properties.get('datasource.master.url')println("master set to " + dataSourceMaster.url)dataSourceMaster.username = properties.get('datasource.master.username')dataSourceMaster.password = properties.get('datasource.master.password') def dataSourceSlave = new DruidDataSource()dataSourceSlave.url = properties.get('datasource.slave.url')println("slave set to " + dataSourceSlave.url)dataSourceSlave.username = properties.get('datasource.slave.username')dataSourceSlave.password = properties.get('datasource.slave.password')beans {  dataSource(ReadWriteSplitRoutingDataSource) { bean ->    targetDataSources = [        (DbContextHolder.DbType.MASTER): dataSourceMaster,        (DbContextHolder.DbType.SLAVE): dataSourceSlave    ]  }}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持搞代码

更多Spring boot实现数据库读写分离的方法相关文章请关注搞代码


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Spring boot实现数据库读写分离的方法

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址