详解使用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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。