jeecg主从数据库读写分离配置「建议收藏」

1、修改Dbconfig.properties数据库配置文件:注意:从库属性的名字要与主库的属性名字区分开,属性名将会在后面的配置文件中用到。#数据库配置主库-写入库#MySQLhibernate.dialect=org.hibernate.dialect.MySQLDialectvalidationQuery.sqlserver=SELECT1jdbc.url=jdbc\:mys…

大家好,又见面了,我是你们的朋友全栈君。

1、修改Dbconfig.properties数据库配置文件:
注意:从库属性的名字要与主库的属性名字区分开,属性名将会在后面的配置文件中用到。

#数据库配置 主库-写入库
#MySQL
hibernate.dialect=org.hibernate.dialect.MySQLDialect
validationQuery.sqlserver=SELECT 1
jdbc.url=jdbc\:mysql\://127.0.0.1\:3306/database001?useUnicode\=true&characterEncoding\=UTF-8
jdbc.username=root
jdbc.password=root
jdbc.dbType=mysql
#数据库配置 从库-读库
#MySQL
jdbc.url.slave=jdbc\:mysql\://127.0.0.1\:3306/database002?useUnicode\=true&characterEncoding\=UTF-8
jdbc.username.slave=root
jdbc.password.slave=root
jdbc.dbType.slave=mysql
#更新|创建|验证数据库表结构|不作改变     默认update(create,validate,none)
hibernate.hbm2ddl.auto=none

2、修改spring-mvc-hibernate.xml配置文件
2.1、配置数据源2:复制原有的数据源配置,做以下修改:
1) 数据源的名称name需要重新命名;
2) 将数据库的链接属性设定为Dbconfig.properties中数据源2的属性值。

	<!-- 配置数据源2 -->
	<bean name="dataSource_slave" class="com.alibaba.druid.pool.DruidDataSource"
		init-method="init" destroy-method="close">
		<property name="url" value="${jdbc.url.jeewx.slave}" />
		<property name="username" value="${jdbc.username.jeewx.slave}" />
		<property name="password" value="${jdbc.password.jeewx.slave}" />
		<!-- 初始化连接大小 -->
		<property name="initialSize" value="0" />
		<!-- 连接池最大使用连接数量 -->
		<property name="maxActive" value="250" />
		<!-- 连接池最大空闲 -->
		<property name="maxIdle" value="20" />
		<!-- 连接池最小空闲 -->
		<property name="minIdle" value="5" />
		<!-- 获取连接最大等待时间 -->
		<property name="maxWait" value="60000" />
		<!-- <property name="poolPreparedStatements" value="true" /> <property 
			name="maxPoolPreparedStatementPerConnectionSize" value="33" /> -->
		<property name="validationQuery" value="${validationQuery.sqlserver}" />
		<property name="testOnBorrow" value="false" />
		<property name="testOnReturn" value="false" />
		<property name="testWhileIdle" value="true" />

		<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
		<property name="timeBetweenEvictionRunsMillis" value="60000" />
		<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
		<property name="minEvictableIdleTimeMillis" value="25200000" />

		<!-- 打开removeAbandoned功能 -->
		<property name="removeAbandoned" value="true" />
		<!-- 1800秒,也就是30分钟 -->
		<property name="removeAbandonedTimeout" value="1800" />
		<!-- 关闭abanded连接时输出错误日志 -->
		<property name="logAbandoned" value="true" />

		<!-- 开启Druid的监控统计功能 -->
		<property name="filters" value="stat" />
		<!--<property name="filters" value="mergeStat" /> -->
		<!-- Oracle连接是获取字段注释 -->
		<property name="connectProperties">
			<props>
				<prop key="remarksReporting">true</prop>
			</props>
		</property>
	</bean>

2.2、配置数据源集:

     <!-- 数据源集合 -->
	<bean id="dataSource"
		class="org.jeecgframework.core.extend.datasource.DynamicDataSource">
		<property name="targetDataSources">
			<map key-type="org.jeecgframework.core.extend.datasource.DataSourceType">
				<entry key="dataSource_jeecg" value-ref="dataSource_jeecg" />
				<entry key="dataSource_slave" value-ref="dataSource_slave" />
				<!-- <entry key="mapdataSource" value-ref="mapdataSource" /> -->
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="dataSource_jeecg" />
	</bean>

2.3、定义AOP的切面处理器,关于AOP的语法自行百度查阅,其中重点对以下做说明:
(1) org.jeecgframework.core.interceptors.DataSourceAspect类需要实现,该类主要用来对数据库进行动态切换;
(2) 此处的表达式设定的主要是是针对该包下的CommonService的所有方法进行切面处理;
(3) DataSourceAspect类中必须实现before方法,具体实现对数据库的动态切换就在此控制。

    <!-- 定义AOP切面处理器 -->
    <bean class="org.jeecgframework.core.interceptors.DataSourceAspect" id="dataSourceAspect" />
    <aop:config>
        <!-- 定义切面,CommonService的所有方法 -->
        <aop:pointcut id="txPointcut" expression="execution(* org.jeecgframework.core.common.service.*.*(..))" />
        <!-- 将切面应用到自定义的切面处理器上,-9999保证该切面优先级最高执行 -->
        <aop:aspect ref="dataSourceAspect" order="-9999">
            <aop:before method="before" pointcut-ref="txPointcut" />
        </aop:aspect>
    </aop:config>

3、实现类org.jeecgframework.core.interceptors.DataSourceAspect:

package org.jeecgframework.core.interceptors;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.jeecgframework.core.extend.datasource.DataSourceContextHolder;

/**
 * 定义数据源的AOP切面,通过该Service的方法名判断是应该走读库还是写库
 * 
 * @author yaoxy
 *
 */
public class DataSourceAspect {
    /**
     * 在进入Service方法之前执行
     * 
     * @param point 切面对象
     */
    public void before(JoinPoint point) {
        // 获取到当前执行的方法名
        String methodName = point.getSignature().getName();
        if (isSlave(methodName)) {
            // 标记为读库
        	DataSourceContextHolder.markSlave();
        } else {
            // 标记为写库
        	DataSourceContextHolder.markMaster();
        }
    }
    /**
     * 判断是否为读库
     * 
     * @param methodName
     * @return
     */
    private Boolean isSlave(String methodName) {
        // 方法名以query、find、get开头的方法名走从库
        return StringUtils.startsWithAny(methodName, "query","find","get");
    }
}

实现原理:
1) 判断AOP切面处理的CommonService类中被调用的方法名开头中是否包含查询的关键字;
2) 如果CommonService被调用的方法中包含查询的关键字,调用DataSourceContextHolder将库切换到从库进行读取操作,否则切换到主库进行写入操作。
4、DataSourceContextHolder中追加主从切换的方法

ackage org.jeecgframework.core.extend.datasource;
/**
 *类名:DataSourceContextHolder.java
 *功能:获得和设置上下文环境的类,主要负责改变上下文数据源的名称
 */
public class DataSourceContextHolder {
    //读库对应的数据源key
	private static final ThreadLocal contextHolder=new ThreadLocal();
	public static void setDataSourceType(DataSourceType dataSourceType){
		contextHolder.set(dataSourceType);
	}
	public static DataSourceType getDataSourceType(){
		return (DataSourceType) contextHolder.get();
	}
	public static void clearDataSourceType(){
		contextHolder.remove();
	}
	/**
     * 标记写库
     */
    public static void markMaster(){
    	setDataSourceType(DataSourceType.dataSource_jeecg);
    }
    /**
     * 标记读库
     */
    public static void markSlave(){
    	setDataSourceType(DataSourceType.dataSource_slave);
    }
	
}

5、数据源的枚举类DataSourcetype中追加新增的从库数据源名称

package org.jeecgframework.core.extend.datasource;

public enum DataSourceType {
	dataSource_jeecg,dataSource_enter,dataSource4,mapdataSource,dataSource_slave
	//dataSource_jeecg:主库名,dataSource_slave:从库名。
}

总结:
应用层的读写分析涉及到以下5个文件,详见文件夹【应用层读写分离设定文件】:
在这里插入图片描述
实现的原理:利用Spring AOP的切面处理原理,在对数据库进行操作的方法被执行之前根据方法的名字判断是读还是写,进行主从/读写数据库的切换。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/127994.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • docker nginx+php(docker nginx反向代理)

    一、docker安装:将微信公众号项目运行绑定至80端口(微信服务器只能和外部开通了80端口的服务器之间通信)docker一次构建可放在任何地方就可以运行,不需要进行任何改变DocKer就类似于一个容器。这个容器就好像咱们常用的虚拟机一样,当我们虚拟机里面安装过VS、SQL、浏览器……之后咱们就把虚拟机镜像备份下来、等到下一次需要重新搭一个环境的时候,就可以省去很多事情了,直接…

  • springboot详细讲解_Springboot框架

    springboot详细讲解_Springboot框架一、SpringApplication的几种常用方式二、定制启动Banner三、SpringBoot事件和监听器四、SpringBoot的Web环境信息五、SpringBoot的ApplicationRunner接口和CommandLineRunner接口SpringBoot版本:1.5.13.RELEASE对应官方文档链接:https://docs.s…

  • 如何用pycharm编译器打包,最简单的方法[通俗易懂]

    如何用pycharm编译器打包,最简单的方法[通俗易懂]如何用pycharm编译器打包exe,最简单的方法一、找到pycharm上边的位置1.执行之前要确保下载了pyinstaller2.我的是加过了,点击加号二、步骤二1.找到相关位置program:pyinstaller.exe位置进行操作,可以找到你的相关路径2.生成exe代码如下(示例):2.读入数据在你的pycharm写的代码的文件夹里边找到dist,就在里边:生成exe…

  • Entity Framework

    Entity Framework

  • Laravel Exceptions——异常与错误处理「建议收藏」

    Laravel Exceptions——异常与错误处理

  • mybatis 原理[通俗易懂]

    mybatis 原理[通俗易懂]问题:mybatis是基于mapper接口开发的,mapper接口是执行SQL语句的呢?mybatis对mapper代码的包装主要包含了4个类。1.首先mapper需要将接口进行注册,并且需要获得mapper代理工厂(mapperregistry)mapperregistry类将mapper接口进行注册,并获取mapper代理工厂的工具类(mapperproxyfactory)2.加载mapp…

    2022年10月30日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号