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

发布于 2021-11-30 00:29:13 字数 10104 浏览 908 评论 1

我在写一个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("切换数据源");  
    }  
}



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



如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

韬韬不绝 2021-12-01 03:26:04

由于determineCurrentLookupKey 方法优先于切入方法 getUser,所以切换不了数据源

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文