开发者社区> 问答> 正文

《Spring4+Hibernate4+proxool配置多数据源实现读写分离》:配置报错 

我在写一个Spring4+Hibernate4+proxool配置多数据源实现读写分离的demo。但切换不了数据库,请高手指教一下。下面是我的代码:
1、数据库的一个配置

driverClassName=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@192.168.0.41:1521:orcl
username=amb
password=amb

driverName=oracle.jdbc.driver.OracleDriver
dataUrl=jdbc:oracle:thin:@192.168.0.16:1521:orcl
userName=test
passWord=test

hibernateDialect=org.hibernate.dialect.Oracle9Dialect
hibernateShowSQL=true
二、这是关于线程池以及多数据源的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop.xsd
           http://www.springframework.org/schema/tx 
           http://www.springframework.org/schema/tx/spring-tx.xsd">


	<!-- 使用Spring的Annotation的配置 -->
	<context:annotation-config />

	<!-- 除了Controller,Bean全部自动到包里面找 -->
	<context:component-scan base-package="ecen.tenement">
		<context:exclude-filter type="annotation"
			expression="org.springframework.stereotype.Controller" />
	</context:component-scan>

	<!-- 开启占位符来配置Properties文件的值 -->
	<bean
		class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location"> 
        		<value>classpath:ecen/tenement/config/jdbc.properties</value>
		</property>
	</bean>
	
	<!-- 使用Proxool来配置JDBC -->
	<bean id="proxoolDataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
		<property name="alias">
			<value>tenement</value>
		</property>
		<property name="driver">
			<value>${driverClassName}</value>
		</property>
		<property name="driverUrl">
			<value>${url}</value>
		</property>
		<property name="user">
			<value>${username}</value>
		</property>
		<property name="password">
			<value>${password}</value>
		</property>

		<!-- 最大连接数(默认5个),超过了这个连接数,再有请求时,就排在队列中等候 -->
		<property name="maximumConnectionCount">
			<value>20</value>
		</property>

		<!-- 最小连接数(默认2个) -->
		<property name="minimumConnectionCount">
			<value>3</value>
		</property>

		<!-- 最少保持的空闲连接数(默认2个) -->
		<property name="prototypeCount">
			<value>3</value>
		</property>

		<!-- 是否记录数据库的每一步操作 -->
		<property name="trace">
			<value>true</value>
		</property>

		<!-- 是否同时记录多个STUFF,会产生多个日志 -->
		<property name="verbose">
			<value>true</value>
		</property>

		<!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 默认30秒 -->
		<property name="houseKeepingSleepTime">
			<value>90000</value>
		</property>

		<!-- 保持数据库连接所使用的SQL语句 -->
		<property name="houseKeepingTestSql">
			<value>SELECT CURRENT_DATE</value>
		</property>

	</bean>
	<!-- 使用Proxool来配置JDBC -->
	<bean id="proxoolDataSourceTest" class="org.logicalcobwebs.proxool.ProxoolDataSource">
		<property name="alias">
			<value>tenement</value>
		</property>
		<property name="driver">
			<value>${driverName}</value>
		</property>
		<property name="driverUrl">
			<value>${dataUrl}</value>
		</property>
		<property name="user">
			<value>${userName}</value>
		</property>
		<property name="password">
			<value>${passWord}</value>
		</property>

		<!-- 最大连接数(默认5个),超过了这个连接数,再有请求时,就排在队列中等候 -->
		<property name="maximumConnectionCount">
			<value>30</value>
		</property>

		<!-- 最小连接数(默认2个) -->
		<property name="minimumConnectionCount">
			<value>3</value>
		</property>

		<!-- 最少保持的空闲连接数(默认2个) -->
		<property name="prototypeCount">
			<value>3</value>
		</property>

		<!-- 是否记录数据库的每一步操作 -->
		<property name="trace">
			<value>true</value>
		</property>

		<!-- 是否同时记录多个STUFF,会产生多个日志 -->
		<property name="verbose">
			<value>true</value>
		</property>

		<!-- proxool自动侦察各个连接状态的时间间隔(毫秒),侦察到空闲的连接就马上回收,超时的销毁 默认30秒 -->
		<property name="houseKeepingSleepTime">
			<value>90000</value>
		</property>

		<!-- 保持数据库连接所使用的SQL语句 -->
		<property name="houseKeepingTestSql">
			<value>SELECT CURRENT_DATE</value>
		</property>

	</bean>
	
	<bean id="dynamicDataSource" class="ecen.tenement.datasource.DynamicDataSource">
		<!-- 通过key-value的形式来关联数据源 -->
		<property name="targetDataSources">
			<map key-type="java.lang.String">
				<entry value-ref="proxoolDataSource" key="dataSourceA"></entry>
				<entry value-ref="proxoolDataSourceTest" key="dataSourceB"></entry>
			</map>
		</property>
		<property name="defaultTargetDataSource" ref="proxoolDataSource">
		</property>
	</bean>
	<!-- 支持 @AspectJ 标记-->  
     <aop:aspectj-autoproxy />
     <bean class="ecen.tenement.datasource.DynamicDataSourceAspect" />
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
		<property name="dataSource" ref="dynamicDataSource" />


		<!-- 直接扫描这个包里面的Entity类,建议使用 -->
		<property name="packagesToScan">
			<list>
				<value>ecen.tenement.model</value>
			</list>
		</property>

		<!-- Hibernate配置中的各种属性,具体请查询HinbernateDOC文档 -->
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${hibernateDialect}</prop>
				<prop key="hibernate.show_sql">${hibernateShowSQL}</prop>


				<!-- 是否使用CGLIB动态代理对象(小而快,推荐,需要CGLIB包,建议配合Proxool使用) -->
				<prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>

				<!-- 指定Hibernate在何时释放JDBC连接 -->
				<prop key="hibernate.connection.release_mode">auto</prop>
				<prop key="hibernate.hbm2ddl.auto"></prop>
			</props>
		</property>
	</bean>

	<!-- 使用Hibernate模板,极大简化Hibernate的开发 -->
	<bean id="hibernateTemplate" class="org.springframework.orm.hibernate4.HibernateTemplate">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>

	<!-- 自动Hibernate事务处理,自动Rollback,自动TryCatch -->
	<bean id="txManager"
		class="org.springframework.orm.hibernate4.HibernateTransactionManager">
		<!-- 把SessionFactory注给Tx -->
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<!-- 配置事务管理 -->
	<tx:annotation-driven transaction-manager="txManager" />

	<!-- 配置Transcation 自动处理,属于切面编程 -->
	<tx:advice id="txAdvice" transaction-manager="txManager">
		<tx:attributes>
			<tx:method name="load*" read-only="true" />
			<tx:method name="list*" read-only="true" />
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="remove*" propagation="REQUIRED" />
		</tx:attributes>
	</tx:advice>
</beans>
三、我切换数据库的实现
package ecen.tenement.datasource;


import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  /**
   * 设置数据源
   * @author 檀溪
   *
   */
public class DynamicDataSource extends AbstractRoutingDataSource{  
  
    @Override  
    protected Object determineCurrentLookupKey() {  
    	String string = CustomerContextHolder.getCustomerType();
        return string;  
    }  
}
package ecen.tenement.datasource;
/**
 * 控制数据源的类
 * @author 檀溪
 *
 */
public class CustomerContextHolder {  
	  
    public static final String DATA_SOURCE_A = "dataSourceA";  
      
    public static final String DATA_SOURCE_B = "dataSourceB";  
      
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
      
    public static void setCustomerType(String customerType) {  
        contextHolder.set(customerType);  
    }  
      
    public static String getCustomerType() {  
        return contextHolder.get();  
    }  
      
    public static void clearCustomerType() {  
        contextHolder.remove();  
    }

}
package ecen.tenement.datasource;


import java.io.IOException;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
 * 使用AOP切面来切换数据源
 * @author 檀溪
 *
 */
@Aspect
public class DynamicDataSourceAspect {
	//execution (* ecen.tenement.service.*.*.*(..))
	public void serviceExecution(){}
	
	@Before("execution (* ecen.tenement.service.*.*.*(..))")  
    public void getUser(JoinPoint jp) throws IOException {  
		CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
        System.out.println("切换数据源");  
    }  
}

方法每次都执行了,但是就是切换不了数据源,程序也没有出现任何异常

展开
收起
kun坤 2020-05-31 21:39:41 531 0
1 条回答
写回答
取消 提交回答
  • 由于determineCurrentLookupKey 方法优先于切入方法 getUser,所以切换不了数据源######其实是因为你两个数据源的alias名字相同才导致这个问题,最近我也碰到了这个问题,我压根没写alias,本来以为是个可有可无的东西,这个问题 确实很坑爹。。。

    2020-05-31 21:43:16
    赞同 1 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
云栖社区特邀专家徐雷Java Spring Boot开发实战系列课程(第20讲):经典面试题与阿里等名企内部招聘求职面试技巧 立即下载
微服务架构模式与原理Spring Cloud开发实战 立即下载
阿里特邀专家徐雷Java Spring Boot开发实战系列课程(第18讲):制作Java Docker镜像与推送到DockerHub和阿里云Docker仓库 立即下载

相关实验场景

更多