我们在上篇文章提到了Spring4+Hibernate4整合详解
下面我们开始配置数据库读写分离
第一步:首先在spring-hibernate.xml配置多个datasource,注意datasource的ID不同
<bean name="masterDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_user}" />
<property name="password" value="${jdbc_password}" />
<property name="initialSize" value="0" />
<property name="maxActive" value="20" />
<property name="maxIdle" value="20" />
<property name="minIdle" value="0" />
<property name="maxWait" value="60000" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="25200000" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="1800" />
<property name="logAbandoned" value="true" />
<property name="filters" value="stat" />
bean>
<bean name="slaveDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url1}" />
<property name="username" value="${jdbc_user1}" />
<property name="password" value="${jdbc_password1}" />
<property name="initialSize" value="0" />
<property name="maxActive" value="20" />
<property name="maxIdle" value="20" />
<property name="minIdle" value="0" />
<property name="maxWait" value="60000" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="25200000" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="1800" />
<property name="logAbandoned" value="true" />
<property name="filters" value="stat" />
bean>
第二步:写一个DynamicDataSource类继承AbstractRoutingDataSource,并实现determineCurrentLookupKey方法
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DbContextHolder.getDbType();
}
}
public class DbContextHolder {
private static final ThreadLocal contextHolder = new ThreadLocal();
@SuppressWarnings("unchecked")
public static void setDbType(String dbType) {
contextHolder.set(dbType);
}
public static String getDbType() {
return (String) contextHolder.get();
}
public static void clearDbType() {
contextHolder.remove();
}
}
第三步:在spring-hibernate.xml配置动态数据源
id="dataSource" class="test.jia.com.datasource.DynamicDataSource">
<property name="targetDataSources">
property>
<property name="defaultTargetDataSource" ref="masterDataSource"/>
第四步:在spring-hibernate.xml配置sessionFactory(与上文一致即可)
第五步:在spring-hibernate.xml配置事务管理(与上文一致即可)
第六步:动态数据源的管理控制,可以采用AOP的控制方式
@Aspect
@Component
public class DynamicDataSourceAspect {
/**
* 注:Aspect不属于Spring开发的,需要导入相关Jar包
*
* aspectjrt.jar
* aspectjweaver-1.6.10.jar
*/
@Pointcut("execution (* test.jia.com.service..*.*(..))")
public void serviceExecution(){}
@Before("serviceExecution()")
public void setDynamicDataSource(JoinPoint jp) {
String methodName = jp.getSignature().getName();
if (methodName.contains("save")) {
System.out.println("写入数据库,数据库名称:write_mysql");
DbContextHolder.setDbType("slaveDataSource");
}else if (methodName.contains("get")) {
System.out.println("读取数据库,数据库名称:read_mysql");
DbContextHolder.setDbType("masterDataSource");
}
for(Object o : jp.getArgs()) {
//处理具体的逻辑 ,根据具体的境况
//DbContextHolder.setDbType("slaveDataSource");
}
}
}
在spring-hibernate.xml添加切面注解扫描
<aop:aspectj-autoproxy/>
到此配置完毕,下面开始进行测试
@RequestMapping("login")
public String login(HttpServletRequest request , HttpServletResponse response){
System.out.println(" welcome ! ");
try {
baseService.save(new LoginUser("李四"));
/**
* baseService.getObject()错误:
* org.hibernate.HibernateException:
* Could not obtain transaction-synchronized Session for current thread
* 解决方案:
* Dao中之前使用的是
* sessionFactory.getCurrentSession()获取Session
* 改为使用
* sessionFactory.openSession()获取Session
*
* 但是getCurrentSession是受Spring管理的。
* openSession是不受Spring管理,需要手动开启事务,和释放session
*/
baseService.getObject(LoginUser.class, 1);
} catch (Exception e) {
e.printStackTrace();
}
return "login";
}
文章参考:http://www.cnblogs.com/xiaoblog/p/4720160.html