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的切面处理原理,在对数据库进行操作的方法被执行之前根据方法的名字判断是读还是写,进行主从/读写数据库的切换。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • SpringBoot框架总结

    SpringBoot框架总结SpringBoot框架总结一、SpringBoot框架的概念1、传统框架的弊端例如传统的SSM框架整合了MyBatis、Spring、SpringMVC框架,但其需要繁琐且重复的配置使程序员很是痛苦2、SpringBoot框架SpringBoot框架在传统框架的基础上对其进一步封装,只需要一些简单的配置,省去了传统框架繁琐的配置,解放了程序员,使程序员只需要关注业务而无需将经历花费在框架的配置上,大幅提高了编程的效率二、SpringBoot框架的创建1、idea创建SpringBoot工程

    2022年8月21日
    22
  • netty 自定义协议_自定义annotation

    netty 自定义协议_自定义annotationNetty实现自定义协议

    2022年4月22日
    51
  • MQTT 服务器介绍

    MQTT 服务器介绍MQTT发布订阅模式简述MQTT是基于发布(Publish)/订阅(Subscribe)模式来进行通信及数据交换的,与HTTP的请求(Request)/应答(Response)的模式有本质的不同。订阅者(Subscriber)会向消息服务器(Broker)订阅一个主题(Topic)。成功订阅后,消息服务器会将该主题下的消息转发给所有的订阅者。主题(Topic)以‘…

    2022年5月9日
    61
  • wincc远程服务器配置,WINCC-OPC服务器配置

    wincc远程服务器配置,WINCC-OPC服务器配置《WINCC-OPC服务器配置》由会员分享,可在线阅读,更多相关《WINCC-OPC服务器配置(13页珍藏版)》请在人人文库网上搜索。1、两台WinCC之间OPC通讯方法(WinXP)OPC客户端1、登陆计算机名及密码要与服务器端(OPCServer)一致。a)如:用户名:administrator密码:12342、OPC客户端要与服务器端处于同一个网络。a)如:OPCServerIP:…

    2022年6月20日
    30
  • 2021年河北高考成绩位次怎么查询,河北高考一分一段表2021,河北高考位次排名表…[通俗易懂]

    2021年河北高考成绩位次怎么查询,河北高考一分一段表2021,河北高考位次排名表…[通俗易懂]河北高考一分一段表它显示每一个分数在全省考生有多少名,能让你计算出自己的排位。目前的段表,是将全省所有考生的档案分(高考各科成绩+优惠加分)从高到低排列(分数相同的则为并列),再按每1分一段,统计“本段人数”;从本段向上一直到最高分段的所有“本段人数”相加,则为“累计人数”。一分一段表上显示出每一个分数全省的考生有多少名,这个数据的参考价值最大。2020年河北高考一分一段表会在成绩公布后一起公布,…

    2022年7月14日
    16
  • C#中write和writeline的区别「建议收藏」

    writeLine:将要输出的字符串与换行控制字符一起输出,当次语句执行完毕时候,光标会移到目前输出字符串的下一行。例如:write:光标会停在输出字符串的最后一个字符,不会移动到下一行。writeLine实例运行效果如下图:write实例运行效果如下图:…

    2022年4月10日
    35

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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