spring aop , mysql 主从配置 实现读写分离,接下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。
1.使用spring aop 拦截机制现数据源的动态选取。
import java.lang.annotation.elementtype;
import java.lang.annotation.target;
import java.lang.annotation.retention;
import java.lang.annotation.retentionpolicy;
/**
* runtime
* 编译器将把注释记录在类文件中,在运行时 vm 将保留注释,因此可以反射性地读取。
* @author yangguang
*
*/
@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface datasource {
string value();
}
3.利用spring的abstractroutingdatasource解决多数据源的问题
import org.springframework.jdbc.datasource.lookup.abstractroutingdatasource;
public class choosedatasource extends abstractroutingdatasource {
@override
protected object determinecurrentlookupkey() {
return handledatasource.getdatasource();
}
}
4.利用threadlocal解决线程安全问题
public class handledatasource {
public static final threadlocal<string> holder = new threadlocal<string>();
public static void putdatasource(string datasource) {
holder.set(datasource);
}
public static string getdatasource() {
return holder.get();
}
}
5.定义一个数据源切面类,通过aop访问,在spring配置文件中配置了,所以没有使用aop注解。
import java.lang.reflect.method;
import org.aspectj.lang.joinpoint;
import org.aspectj.lang.annotation.aspect;
import org.aspectj.lang.annotation.before;
import org.aspectj.lang.annotation.pointcut;
import org.aspectj.lang.reflect.methodsignature;
import org.springframework.stereotype.component;
//@aspect
//@component
public class datasourceaspect {
//@pointcut("execution(* com.apc.cms.service.*.*(..))")
public void pointcut(){};
// @before(value = "pointcut()")
public void before(joinpoint point)
{
object target = point.gettarget();
system.out.println(target.tostring());
string method = point.getsignature().getname();
system.out.println(method);
class<?>[] classz = target.getclass().getinterfaces();
class<?>[] parametertypes = ((methodsignature) point.getsignature())
.getmethod().getparametertypes();
try {
method m = classz[0].getmethod(method, parametertypes);
system.out.println(m.getname());
if (m != null && m.isannotationpresent(datasource.class)) {
datasource data = m.getannotation(datasource.class);
handledatasource.putdatasource(data.value());
}
} catch (exception e) {
e.printstacktrace();
}
}
}
6.配置applicationcontext.xml
<!-- 主库数据源 -->
<bean id="writedatasource" class="com.jolbox.bonecp.bonecpdatasource" destroy-method="close">
<property name="driverclass" value="com.mysql.jdbc.driver"/>
<property name="jdbcurl" value="jdbc:mysql://172.22.14.6:3306/cpp?autoreconnect=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="partitioncount" value="4"/>
<property name="releasehelperthreads" value="3"/>
<property name="acquireincrement" value="2"/>
<property name="maxconnectionsperpartition" value="40"/>
<property name="minconnectionsperpartition" value="20"/>
<property name="idlemaxageinseconds" value="60"/>
<property name="idleconnectiontestperiodinseconds" value="60"/>
<property name="poolavailabilitythreshold" value="5"/>
</bean>
<!-- 从库数据源 -->
<bean id="readdatasource" class="com.jolbox.bonecp.bonecpdatasource" destroy-method="close">
<property name="driverclass" value="com.mysql.jdbc.driver"/>
<property name="jdbcurl" value="jdbc:mysql://172.22.14.7:3306/cpp?autoreconnect=true"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="partitioncount" value="4"/>
<property name="releasehelperthreads" value="3"/>
<property name="acquireincrement" value="2"/>
<property name="maxconnectionsperpartition" value="40"/>
<property name="minconnectionsperpartition" value="20"/>
<property name="idlemaxageinseconds" value="60"/>
<property name="idleconnectiontestperiodinseconds" value="60"/>
<property name="poolavailabilitythreshold" value="5"/>
</bean>
<!-- transaction manager, 事务管理 -->
<bean id="transactionmanager" class="org.springframework.jdbc.datasource.datasourcetransactionmanager">
<property name="datasource" ref="datasource" />
</bean>
<!-- 注解自动载入 -->
<context:annotation-config />
<!--enale component scanning (beware that this does not enable mapper scanning!)-->
<context:component-scan base-package="com.apc.cms.persistence.rdbms" />
<context:component-scan base-package="com.apc.cms.service">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.component" />
</context:component-scan>
<context:component-scan base-package="com.apc.cms.auth" />
<!-- enable transaction demarcation with annotations -->
<tx:annotation-driven />
<!-- define the sqlsessionfactory -->
<bean id="sqlsessionfactory" class="org.mybatis.spring.sqlsessionfactorybean">
<property name="datasource" ref="datasource" />
<property name="typealiasespackage" value="com.apc.cms.model.domain" />
</bean>
<!-- scan for mappers and let them be autowired -->
<bean class="org.mybatis.spring.mapper.mapperscannerconfigurer">
<property name="basepackage" value="com.apc.cms.persistence" />
<property name="sqlsessionfactory" ref="sqlsessionfactory" />
</bean>
<bean id="datasource" class="com.apc.cms.utils.choosedatasource">
<property name="targetdatasources">
<map key-type="java.lang.string">
<!-- write -->
<entry key="write" value-ref="writedatasource"/>
<!-- read -->
<entry key="read" value-ref="readdatasource"/>
</map>
</property>
<property name="defaulttargetdatasource" ref="writedatasource"/>
</bean>
<!-- 激活自动代理功能 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 配置数据库注解aop -->
<bean id="datasourceaspect" class="com.apc.cms.utils.datasourceaspect" />
<aop:config>
<aop:aspect id="c" ref="datasourceaspect">
<aop:pointcut id="tx" expression="execution(* com.apc.cms.service..*.*(..))"/>
<aop:before pointcut-ref="tx" method="before"/>
</aop:aspect>
</aop:config>
<!-- 配置数据库注解aop -->
7.使用注解,动态选择数据源,分别走读库和写库。
@datasource("write")
public void update(user user) {
usermapper.update(user);
}
@datasource("read")
public document getdocbyid(long id) {
return documentmapper.getbyid(id);
}
测试写操作:可以通过应用修改数据,修改主库数据,发现从库的数据被同步更新了,所以定义的write操作都是走的写库
测试读操作: 后台修改从库数据,查看主库的数据没有被修改,在应用页面中刷新,发现读的是从库的数据,说明读写分离ok。
遇到的问题总结:
问题1:项目是maven工程,用到了spring aop机制,除了spring的核心jar包以为,还需要用到的jar包有aspectj.jar,aspectjweaver.jar,aopalliance.jar查看项目中的pom,发现缺少依赖包,由于本地仓库没有这些jar,查找可以提供下载jar包的maven中央库库,配置到maven中,自动更新:
<repository>
<id>nexus</id>
<name>nexus</name>
<url>http://repository.sonatype.org/content/groups/public/</url>
<layout>default</layout>
</repository>
配置项目依赖的jar,主要是缺少这两个。
<dependency>
<groupid>aspectj</groupid>
<artifactid>aspectjrt</artifactid>
<version>1.5.4</version>
</dependency>
<dependency>
<groupid>aspectj</groupid>
<artifactid>aspectjweaver</artifactid>
<version>1.5.4</version>
lt;/dependency>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
更多详解使用spring aop实现业务层mysql 读写分离。
