spring aop , mysql 主从配置 实现读写分离,接下来把自己的配置过程,以及遇到的问题记录下来,方便下次操作,也希望给一些朋友带来帮助。
1.使用spring aop 拦截机制现数据源的动态选取。
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
 
								11
 
								12
 
								13
 
								14
 
								15
						  | 
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解决多数据源的问题
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
						  | 
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; 
public class ChooseDataSource extends AbstractRoutingDataSource { 
@Override
protected Object determineCurrentLookupKey() { 
return HandleDataSource.getDataSource(); 
} 
} 
 | 
4.利用ThreadLocal解决线程安全问题
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
						  | 
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注解。
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
 
								11
 
								12
 
								13
 
								14
 
								15
 
								16
 
								17
 
								18
 
								19
 
								20
 
								21
 
								22
 
								23
 
								24
 
								25
 
								26
 
								27
 
								28
 
								29
 
								30
 
								31
 
								32
 
								33
 
								34
 
								35
 
								36
						  | 
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
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
 
								11
 
								12
 
								13
 
								14
 
								15
 
								16
 
								17
 
								18
 
								19
 
								20
 
								21
 
								22
 
								23
 
								24
 
								25
 
								26
 
								27
 
								28
 
								29
 
								30
 
								31
 
								32
 
								33
 
								34
 
								35
 
								36
 
								37
 
								38
 
								39
 
								40
 
								41
 
								42
 
								43
 
								44
 
								45
 
								46
 
								47
 
								48
 
								49
 
								50
 
								51
 
								52
 
								53
 
								54
 
								55
 
								56
 
								57
 
								58
 
								59
 
								60
 
								61
 
								62
 
								63
 
								64
 
								65
 
								66
 
								67
 
								68
 
								69
 
								70
 
								71
 
								72
 
								73
 
								74
 
								75
 
								76
 
								77
 
								78
 
								79
 
								80
 
								81
 
								82
 
								83
 
								84
 
								85
 
								86
 
								87
 
								88
 
								89
 
								90
 
								91
						  | 
<!-- 主库数据源 -->
<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.使用注解,动态选择数据源,分别走读库和写库。
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
						  | 
@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中,自动更新:
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
						  | 
<repository> 
<id>nexus</id> 
<name>nexus</name> 
<url>http://repository.sonatype.org/content/groups/public/</url> 
<layout>default</layout> 
</repository>
 | 
配置项目依赖的jar,主要是缺少这两个。
| 
 
								1
 
								2
 
								3
 
								4
 
								5
 
								6
 
								7
 
								8
 
								9
 
								10
						  | 
<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>
 | 
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。
原文链接:http://blog.csdn.net/huoyunshen88/article/details/36674861
相关文章
- ASP.NET本地开发时常见的配置错误及解决方法? 2025-06-10
 - ASP.NET自助建站系统的数据库备份与恢复操作指南 2025-06-10
 - 个人网站服务器域名解析设置指南:从购买到绑定全流程 2025-06-10
 - 个人网站搭建:如何挑选具有弹性扩展能力的服务器? 2025-06-10
 - 个人服务器网站搭建:如何选择适合自己的建站程序或框架? 2025-06-10
 
- 2025-07-10 怎样使用阿里云的安全工具进行服务器漏洞扫描和修复?
 - 2025-07-10 怎样使用命令行工具优化Linux云服务器的Ping性能?
 - 2025-07-10 怎样使用Xshell连接华为云服务器,实现高效远程管理?
 - 2025-07-10 怎样利用云服务器D盘搭建稳定、高效的网站托管环境?
 - 2025-07-10 怎样使用阿里云的安全组功能来增强服务器防火墙的安全性?
 
快网idc优惠网
QQ交流群
- 
            2025-06-04 35
 - 
            2025-05-29 67
 - 
            2025-06-05 37
 - 
            
如何确保从HTTP到HTTPS的平滑过渡,以保障用户数据的安全?
2025-06-04 108 - 
            2025-06-04 25
 
        
    		
            	
        
        
        