当前位置: 移动技术网 > IT编程>开发语言>Java > Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作

Spring+Mybatis 实现aop数据库读写分离与多数据库源配置操作

2019年07月19日  | 移动技术网IT编程  | 我要评论

在数据库层面大都采用读写分离技术,就是一个master数据库,多个slave数据库。master库负责数据更新和实时数据查询,slave库当然负责非实时数据查询。因为在实际的应用中,数据库都是读多写少(读取数据的频率高,更新数据的频率相对较少),而读取数据通常耗时比较长,占用数据库服务器的cpu较多,从而影响用户体验。我们通常的做法就是把查询从主库中抽取出来,采用多个从库,使用负载均衡,减轻每个从库的查询压力。

废话不多说,多数据源配置和主从数据配置原理一样

1、首先配置  jdbc.properties 两个数据库 a 和 b

#============ 双数据源 ======#
#----------------------a servers--------------------------#
a.driver=com.mysql.jdbc.driver
a.url=jdbc:mysql://localhost:3619/gps4?useunicode=true&characterencoding=utf8
a.username=gpsadmin
a.password=1qaz&619
#----------------------b servers--------------------------#
b.driver=com.mysql.jdbc.driver
b.url=jdbc:mysql://localhost:3619/gps6?useunicode=true&characterencoding=utf8
b.username=gpsadmin
b.password=1qaz&619

 2、配置 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数据库读写分离与多数据库源配置操作,希望对大家有所帮助

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网