详解使用spring aop实现业务层mysql 读写分离
springaop,mysql主从配置实现读写分离,接下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。
1.使用springaop拦截机制现数据源的动态选取。
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Target;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
/**
*RUNTIME
*编译器将把注释记录在类文件中,在运行时VM将保留注释,因此可以反射性地读取。
*@authoryangGuang
*
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public@interfaceDataSource{
Stringvalue();
}
3.利用Spring的AbstractRoutingDataSource解决多数据源的问题
importorg.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
publicclassChooseDataSourceextendsAbstractRoutingDataSource{
@Override
protectedObjectdetermineCurrentLookupKey(){
returnHandleDataSource.getDataSource();
}
}
4.利用ThreadLocal解决线程安全问题
publicclassHandleDataSource{
publicstaticfinalThreadLocal<String>holder=newThreadLocal<String>();
publicstaticvoidputDataSource(Stringdatasource){
holder.set(datasource);
}
publicstaticStringgetDataSource(){
returnholder.get();
}
}
5.定义一个数据源切面类,通过aop访问,在spring配置文件中配置了,所以没有使用aop注解。
importjava.lang.reflect.Method;
importorg.aspectj.lang.JoinPoint;
importorg.aspectj.lang.annotation.Aspect;
importorg.aspectj.lang.annotation.Before;
importorg.aspectj.lang.annotation.Pointcut;
importorg.aspectj.lang.reflect.MethodSignature;
importorg.springframework.stereotype.Component;
//@Aspect
//@Component
publicclassDataSourceAspect{
//@Pointcut("execution(*com.apc.cms.service.*.*(..))")
publicvoidpointCut(){};
//@Before(value="pointCut()")
publicvoidbefore(JoinPointpoint)
{
Objecttarget=point.getTarget();
System.out.println(target.toString());
Stringmethod=point.getSignature().getName();
System.out.println(method);
Class<?>[]classz=target.getClass().getInterfaces();
Class<?>[]parameterTypes=((MethodSignature)point.getSignature())
.getMethod().getParameterTypes();
try{
Methodm=classz[0].getMethod(method,parameterTypes);
System.out.println(m.getName());
if(m!=null&&m.isAnnotationPresent(DataSource.class)){
DataSourcedata=m.getAnnotation(DataSource.class);
HandleDataSource.putDataSource(data.value());
}
}catch(Exceptione){
e.printStackTrace();
}
}
}
6.配置applicationContext.xml
<!--主库数据源--> <beanid="writeDataSource"class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close"> <propertyname="driverClass"value="com.mysql.jdbc.Driver"/> <propertyname="jdbcUrl"value="jdbc:mysql://172.22.14.6:3306/cpp?autoReconnect=true"/> <propertyname="username"value="root"/> <propertyname="password"value="root"/> <propertyname="partitionCount"value="4"/> <propertyname="releaseHelperThreads"value="3"/> <propertyname="acquireIncrement"value="2"/> <propertyname="maxConnectionsPerPartition"value="40"/> <propertyname="minConnectionsPerPartition"value="20"/> <propertyname="idleMaxAgeInSeconds"value="60"/> <propertyname="idleConnectionTestPeriodInSeconds"value="60"/> <propertyname="poolAvailabilityThreshold"value="5"/> </bean> <!--从库数据源--> <beanid="readDataSource"class="com.jolbox.bonecp.BoneCPDataSource"destroy-method="close"> <propertyname="driverClass"value="com.mysql.jdbc.Driver"/> <propertyname="jdbcUrl"value="jdbc:mysql://172.22.14.7:3306/cpp?autoReconnect=true"/> <propertyname="username"value="root"/> <propertyname="password"value="root"/> <propertyname="partitionCount"value="4"/> <propertyname="releaseHelperThreads"value="3"/> <propertyname="acquireIncrement"value="2"/> <propertyname="maxConnectionsPerPartition"value="40"/> <propertyname="minConnectionsPerPartition"value="20"/> <propertyname="idleMaxAgeInSeconds"value="60"/> <propertyname="idleConnectionTestPeriodInSeconds"value="60"/> <propertyname="poolAvailabilityThreshold"value="5"/> </bean> <!--transactionmanager,事务管理--> <beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <propertyname="dataSource"ref="dataSource"/> </bean> <!--注解自动载入--> <context:annotation-config/> <!--enalecomponentscanning(bewarethatthisdoesnotenablemapperscanning!)--> <context:component-scanbase-package="com.apc.cms.persistence.rdbms"/> <context:component-scanbase-package="com.apc.cms.service"> <context:include-filtertype="annotation" expression="org.springframework.stereotype.Component"/> </context:component-scan> <context:component-scanbase-package="com.apc.cms.auth"/> <!--enabletransactiondemarcationwithannotations--> <tx:annotation-driven/> <!--definetheSqlSessionFactory--> <beanid="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean"> <propertyname="dataSource"ref="dataSource"/> <propertyname="typeAliasesPackage"value="com.apc.cms.model.domain"/> </bean> <!--scanformappersandletthembeautowired--> <beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer"> <propertyname="basePackage"value="com.apc.cms.persistence"/> <propertyname="sqlSessionFactory"ref="sqlSessionFactory"/> </bean> <beanid="dataSource"class="com.apc.cms.utils.ChooseDataSource"> <propertyname="targetDataSources"> <mapkey-type="java.lang.String"> <!--write--> <entrykey="write"value-ref="writeDataSource"/> <!--read--> <entrykey="read"value-ref="readDataSource"/> </map> </property> <propertyname="defaultTargetDataSource"ref="writeDataSource"/> </bean> <!--激活自动代理功能--> <aop:aspectj-autoproxyproxy-target-class="true"/> <!--配置数据库注解aop--> <beanid="dataSourceAspect"class="com.apc.cms.utils.DataSourceAspect"/> <aop:config> <aop:aspectid="c"ref="dataSourceAspect"> <aop:pointcutid="tx"expression="execution(*com.apc.cms.service..*.*(..))"/> <aop:beforepointcut-ref="tx"method="before"/> </aop:aspect> </aop:config> <!--配置数据库注解aop-->
7.使用注解,动态选择数据源,分别走读库和写库。
@DataSource("write")
publicvoidupdate(Useruser){
userMapper.update(user);
}
@DataSource("read")
publicDocumentgetDocById(longid){
returndocumentMapper.getById(id);
}
测试写操作:可以通过应用修改数据,修改主库数据,发现从库的数据被同步更新了,所以定义的write操作都是走的写库
测试读操作: 后台修改从库数据,查看主库的数据没有被修改,在应用页面中刷新,发现读的是从库的数据,说明读写分离ok。
遇到的问题总结:
问题1:项目是maven工程,用到了Springaop机制,除了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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。