时间:2021-05-19
在数据库层面大都采用读写分离技术,就是一个Master数据库,多个Slave数据库。Master库负责数据更新和实时数据查询,Slave库当然负责非实时数据查询。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的CPU较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。
废话不多说,多数据源配置和主从数据配置原理一样
1、首先配置 jdbc.properties 两个数据库 A 和 B
#============ 双数据源 ======##----------------------A servers--------------------------#A.driver=com.mysql.jdbc.DriverA.url=jdbc:mysql://localhost:3619/gps4?useUnicode=true&characterEncoding=utf8A.username=gpsadminA.password=1qaz&619#----------------------B servers--------------------------#B.driver=com.mysql.jdbc.DriverB.url=jdbc:mysql://localhost:3619/gps6?useUnicode=true&characterEncoding=utf8B.username=gpsadminB.password=1qaz&6192、配置 spring-mybatis.xml 文件【重要】
<!-- 引入配置文件 --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:resources/jdbc.properties" /> </bean> <!-- DBCP连接池 --> <!-- <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${driver}" /> <property name="url" value="${url}" /> <property name="username" value="${username}" /> <property name="password" value="${password}" /> 初始化连接大小 <property name="initialSize" value="${initialSize}"></property> 连接池最大数量 <property name="maxActive" value="${maxActive}"></property> 连接池最大空闲 <property name="maxIdle" value="${maxIdle}"></property> 连接池最小空闲 <property name="minIdle" value="${minIdle}"></property> 获取连接最大等待时间 <property name="maxWait" value="${maxWait}"></property> </``> --> <!-- 【重点】 A 数据源 --> <bean name="dataSourceA" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${A.driver}" /> <property name="url" value="${A.url}" /> <property name="username" value="${A.username}" /> <property name="password" value="${A.password}" /> </bean> <!-- 【重点】 B 数据源 --> <bean name="dataSourceB" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${B.driver}" /> <property name="url" value="${B.url}" /> <property name="username" value="${B.username}" /> <property name="password" value="${B.password}" /> </bean> <!--【重点】 双数据源 配合 --> <bean id="dataSource" class="com.ifengSearch.common.database.DynamicDataSource"> <property name="defaultTargetDataSource" ref="dataSourceB"/> <property name="targetDataSources"> <map> <entry key="dataSourceA" value-ref="dataSourceA"/> <entry key="dataSourceB" value-ref="dataSourceB"/> </map> </property> </bean> <!-- 【重点】 加入 aop 自动扫描 DataSourceAspect 配置数据库注解aop --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <bean id="manyDataSourceAspect" class="com.ifengSearch.common.database.DataSourceAspect" /> <aop:config> <!-- 扫描 注解的 数据源 --> <aop:aspect id="c" ref="manyDataSourceAspect"> <aop:pointcut id="tx" expression="execution(* com.ifengSearch.*.dao.*.*(..))"/> <aop:before pointcut-ref="tx" method="before"/> </aop:aspect> </aop:config> <!-- 配置数据连接 工厂 自动扫描mapping.xml文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <!-- 自动扫描mapping.xml文件 --> <property name="mapperLocations" value="classpath:com/ifengSearch/*/mapping/*.xml"></property> </bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.ifengSearch.*.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property> </bean> <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx 事务 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>3、编写几个java类动态调用数据源【重要】
a:自定义一个注解,负责动态调用数据源
package com.ifengSearch.common.database;import java.lang.annotation.*;/** * 设置 数据源 注解标签的用法 写上注解标签, * 调用相应方法切换数据源咯(就跟你设置事务一样) * 【也可以配置 主从数据库】 * * @author flm * @2017年9月12日 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface DataSource { public static String dataSourceA = "dataSourceA"; // A数据源 public static String dataSourceB = "dataSourceB"; // B数据源 String value();}b、数据源的获取 Object aop实现 (反射)
package com.ifengSearch.common.database;import java.lang.reflect.Method;import org.apache.log4j.Logger;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.reflect.MethodSignature;/** * 数据源的获取 * aop实现 (反射) * @author flm * @2017年9月12日 */public class DataSourceAspect{ private Logger log = Logger.getLogger(DataSourceAspect.class); public void before(JoinPoint point) { Object target = point.getTarget();// 拦截的实体类 String method = point.getSignature().getName();// 拦截的方法名称 Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes();// 拦截的方法参数类型 try { Method m = classz[0].getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m .getAnnotation(DataSource.class); DataSourceHolder.setDataSource(data.value()); log.info("数据源的获取 DataSource: "+data.value()); } } catch (Exception e) { log.error("数据源的获取 aop实现 出错:"+e.getMessage()); } }}c、DataSourceHolder 数据源操作 获取数据源 帮助类
package com.ifengSearch.common.database;/** * 多数据源 * 数据源操作 获取数据源 * @author flm * @2017年9月12日 */public class DataSourceHolder { //线程本地环境 private static final ThreadLocal<String> dataSources = new ThreadLocal<String>(); //设置数据源 public static void setDataSource(String customerType) { dataSources.set(customerType); } //获取数据源 public static String getDataSource() { return (String) dataSources.get(); } //清除数据源 public static void clearDataSource() { dataSources.remove(); }}d、 我们还需要实现spring的抽象类AbstractRoutingDataSource,就是实现determineCurrentLookupKey方法:
package com.ifengSearch.common.database;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/** * 多数据源 * 获取数据源(依赖于spring) * @author flm * @2017年9月12日 */public class DynamicDataSource extends AbstractRoutingDataSource{ @Override protected Object determineCurrentLookupKey() { return DataSourceHolder.getDataSource(); }}4、接下来就可以看结果了
我在dao层直接调用
public interface UserDao { /** * 登录判断 【数据源B】 */ @DataSource(value=DataSource.dataSourceB) public List<UserBean> getLoginUserList(@Param("loginName")String loginName,@Param("loginPwd")String loginPwd); /** * 查找上一级 服务商 【数据源A】 */ @DataSource(value=DataSource.dataSourceA) public UserBean getServerUser(@Param("u_last_id")Integer u_last_id);}总结
以上所述是小编给大家介绍的Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
之前写过一篇博客《Spring+Mybatis+Mysql搭建分布式数据库访问框架》描述如何通过Spring+Mybatis配置动态数据源访问多个数据库。但是之
本文实例讲述了Yii实现多数据库主从读写分离的方法。分享给大家供大家参考。具体分析如下:Yii框架数据库多数据库、主从、读写分离实现,功能描述:1.实现主从数据
你在使用MyBatis的过程中,是否有想过多个数据源应该如何配置,如何去实现?出于这个好奇心,我在DruidWiki的数据库多数据源中知晓Spring提供了对多
在程序中封装了一个List集合对象,然后需要把该集合中的实体插入到数据库中,由于项目使用了Spring+MyBatis的配置,所以打算使用MyBatis批量插入
数据库扩展大概分为以下几个步骤:1、读写分离:当数据库访问量还不是很大的时候,我们可以适当增加服务器,数据库主从复制的方式将读写分离;2、垂直分区:当写入操作一