聊聊Spring的主从数据库配置(springboot配置主从数据库)

  本篇文章为你整理了聊聊Spring的主从数据库配置(springboot配置主从数据库)的详细内容,包含有spring主从数据源配置 springboot配置主从数据库 springboot redis主从配置 spring启动从数据库读取配置 聊聊Spring的主从数据库配置,希望能帮助你了解 聊聊Spring的主从数据库配置。

  在应对日渐复杂的业务环境,单个数据库所能承载的压力已经远远不够。很多业务中诞生了主从数据库的架构模型,将数据读写进行分离,主库写,从库读,以提升服务的吞吐量。

  在进行代码设计的时候,我们很自然会想到一个问题,一个业务操作,往往会包括读 和 写,例如在实现一个阅读点击量的简单需求的时候,是不是需要先查询一下原来有多少点击量Num,然后再给这个获取到的数据Num进行+1操作呢?

  那么问题来了:

  如果很多人同时点击,都在给这个Num进行+1,咱们姑且不论数据没办法实现真实稳定的问题。就单从主库和从库切换上来说,是不是已经会产生问题呢?

  仔细分析一下,假如用户A此时在调用接口读取数据,而用户B在调用接口进行写。这个时候会有两种情况出现,数据库操作全局变量在经过A操作之后,变成了从库,那么这时候B写的时候就会写到从库里面了。第二种情况是,A还没有完成读取从库的行为,B将全局变量设置为主库,数据能够正常写入主库,但是问题也出现了,此时A读取数据的时候可能就是主库了,读写分离的意义也就荡然无存了。而线上实际情况,往往比这个复杂一点。在我经历的项目中,读写数据的行为稍有不当,可能带来的是项目的巨大损失。

  回顾一下上篇文章:为什么建议多用下ThreadLocal

  我提到过,ThreadLocal是线程安全的,借助ThreadLocal,我们可以比较好的规避上面的这个问题。聪明的你一定马上会想到,对了,把这个数据库切换的全局变量,变成一个线程的“本地”变量,不就安全多了吗?

  

  下面我们来简单写个实现类

  主从库切换类,基于ThreadLocal实现调用接口线程的安全性。

  

public class DynamicDataSource extends AbstractRoutingDataSource {

 

   private final static Logger LOGGER = LoggerFactory.getLogger(DynamicDataSource.class);

   private static final ThreadLocal String CONTEXT_HOLDER = new ThreadLocal ();
 

   @Override

   protected Object determineCurrentLookupKey() {
 

   String dataSource = getDataSource();return dataSource;

   * 设置数据源

   * @param dataSource

   public static void setDataSource(String dataSource) {
 

   CONTEXT_HOLDER.set(dataSource);

   * 获取数据源

   public static String getDataSource() {
 

   String dataSource = CONTEXT_HOLDER.get();
// 如果没有指定数据源,使用默认数据源

   if (null == dataSource) {

   DynamicDataSource.setDataSource(DataSourceEnum.MASTER.getDefault());

   return CONTEXT_HOLDER.get();

   * 清除数据源

   public static void clearDataSource() {
 

   CONTEXT_HOLDER.remove();

  }

 

  

   当需要进行数据库操作的时候,调用

  

DynamicDataSource.setDataSource(DataSourceEnum.MASTER.getName());

 

  

或者 DynamicDataSource.setDataSource(DataSourceEnum.SLAVE.getName());

 

  切换数据库;

   用完了,调用

  

DynamicDataSource.clearDataSource();

 

  以便下一次继续使用

  

  其他关联数据和配置:

  主从库枚举:

  

public enum DataSourceEnum {

 

   // 主库

   MASTER("masterDataSource", true),

   // 从库

   SLAVE("slaveDataSource", false),;

   // 数据源名称

   private String name;

   // 是否是默认数据源

   private boolean master;

   DataSourceEnum(String name, boolean master) {

   this.name = name;

   this.master = master;

   public String getName() {

   return name;

   public void setName(String name) {

   this.name = name;

   public boolean isMaster() {

   return master;

   public void setMaster(boolean master) {

   this.master = master;

   public String getDefault() {

   String defaultDataSource = "";

   for (DataSourceEnum dataSourceEnum : DataSourceEnum.values()) {

   if (!"".equals(defaultDataSource)) {

   break;

   if (dataSourceEnum.master) {

   defaultDataSource = dataSourceEnum.getName();

   return defaultDataSource;

  }

 

  

  主从库的配置如下:

  

 !-- 主库数据源 -- 

 

   bean id="masterDataSource" init-method="init"

   destroy-method="close"

   !-- 基本属性 url、user、password --

   property name="driverClassName" value="${master.jdbc.driver}"/

   property name="url" value="${master.jdbc.url}"/

   property name="username" value="${master.jdbc.username}"/

   property name="password" value="${master.jdbc.password}"/

   !-- 配置初始化大小、最小、最大 --

   property name="initialSize" value="1"/

   property name="minIdle" value="1"/

   property name="maxActive" value="20"/

   !-- 配置获取连接等待超时的时间 --

   property name="maxWait" value="60000"/

   !-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --

   property name="timeBetweenEvictionRunsMillis" value="60000"/

   !-- 配置一个连接在池中最小生存的时间,单位是毫秒 --

   property name="minEvictableIdleTimeMillis" value="300000"/

   !-- 校验语句 --

   property name="validationQuery" value="SELECT 1"/

   property name="testWhileIdle" value="true"/

   property name="testOnBorrow" value="false"/

   property name="testOnReturn" value="false"/

   !-- 配置监控统计拦截的filters --

   property name="filters" value="stat"/

   /bean

   !-- 从库数据源 --

   bean id="slaveDataSource" init-method="init" destroy-method="close"

   !-- 基本属性 url、user、password --

   property name="driverClassName" value="${slave.jdbc.driver}"/

   property name="url" value="${slave.jdbc.url}"/

   property name="username" value="${slave.jdbc.username}"/

   property name="password" value="${slave.jdbc.password}"/

   !-- 配置初始化大小、最小、最大 --

   property name="initialSize" value="1"/

   property name="minIdle" value="1"/

   property name="maxActive" value="20"/

   !-- 配置获取连接等待超时的时间 --

   property name="maxWait" value="60000"/

   !-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --

   property name="timeBetweenEvictionRunsMillis" value="60000"/

   !-- 配置一个连接在池中最小生存的时间,单位是毫秒 --

   property name="minEvictableIdleTimeMillis" value="300000"/

   !-- 校验语句 --

   property name="validationQuery" value="SELECT 1"/

   property name="testWhileIdle" value="true"/

   property name="testOnBorrow" value="false"/

   property name="testOnReturn" value="false"/

   !-- 配置监控统计拦截的filters --

   property name="filters" value="stat"/

   /bean

 

  

  好了 ,代码虽然看起来挺简单的,但也能说明ThreadLocal在实现读写分离时候的有它一席用武之地咯。实际应用场景,会有更复杂的处理。

  备注:此案例借用了网上的一些资源,做了简化处理,只作为演示说明使用。

  

  以上就是聊聊Spring的主从数据库配置(springboot配置主从数据库)的详细内容,想要了解更多 聊聊Spring的主从数据库配置的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: