spring 动态数据源配置以及相关问题
来源:互联网 发布:软件配置管理办法 编辑:程序博客网 时间:2024/05/29 13:33
项目中要求读写分离,在spring中做到读写分离,很简单的想到在配置文件中设置两个数据源,一个datesource(只写),一个datesourceread(只读)。但是要根据上下文动态切换数据源,还需要增加两个帮助类。
类1 ContextHolder
主要功能是帮助切换数据源,其中ThreadLocal保证线程中的一致性,不受其他线程影响。
public class ContextHolder {public static final String DATA_SOURCE = "dataSource";public static final String DATA_SOURCE_READ = "dataSourceRead";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();}}
类2 MyDataSource
自定义数据源,继承AbstractRoutingDataSource,实现determineCurrentLookupKey()方法。
public class MyDataSource extends AbstractRoutingDataSource {/* (non-Javadoc) * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource#determineCurrentLookupKey() */@Overrideprotected Object determineCurrentLookupKey() {return ContextHolder.getCustomerType();}}
配置文件中这样配置:
<bean id="abstractDataSource" abstract="true" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"value="#{configManager.getConfigValue('trade-seller-guestbook-serv','datasource.driverClassName')}" /> <property name="acquireIncrement" value="3" /> <property name="initialPoolSize" value="3" /> <property name="minPoolSize" value="2" /> <property name="maxPoolSize" value="50" /> <property name="maxIdleTime" value="600" /> <property name="idleConnectionTestPeriod" value="900" /> <property name="maxStatements" value="100" /> <property name="numHelperThreads" value="10" /></bean><bean id="dataSourceRead" parent="abstractDataSource"> <property name="jdbcUrl" value="jdbc:mysql://192.168.10.57:3306/trade?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull" /> <property name="user" value="root" /> <property name="password" value="canada" /> <!-- <property name="jdbcUrl"value="#{configManager.getMysqlConfig('trade_public_mysql','1.2','trade').url}" /><property name="user"value="#{configManager.getMysqlConfig('trade_public_mysql','1.2','trade').user}" /><property name="password"value="#{configManager.getMysqlConfig('trade_public_mysql','1.2','trade').pwd}" /> --> </bean><bean id="dataSource" parent="abstractDataSource"><property name="jdbcUrl"value="#{configManager.getMysqlConfig('trade_public_mysql','1.1','trade').url}" /><property name="user"value="#{configManager.getMysqlConfig('trade_public_mysql','1.1','trade').user}" /><property name="password"value="#{configManager.getMysqlConfig('trade_public_mysql','1.1','trade').pwd}" /></bean><bean id="myDataSource" class="com.zhe800.guestbook.database.MyDataSource"><property name="targetDataSources"><map key-type="java.lang.String"><entry value-ref="dataSource" key="dataSource"/><entry value-ref="dataSourceRead" key="dataSourceRead"/></map></property><property name="defaultTargetDataSource" ref="dataSource"/></bean><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="myDataSource" /><property name="configLocation" value="classpath:mybatis/mybatis-config.xml" /><property name="mapperLocations"><array><value>classpath*:mybatis/sqlmap/guestbook/*.xml</value><value>classpath*:mybatis/sqlmap/manual/*.xml</value></array></property></bean><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.zhe800.guestbook.model.mapper" /><property name="sqlSessionFactory" ref="sqlSessionFactory" /></bean><tx:annotation-driven transaction-manager="transactionManager" /><bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="myDataSource" /></bean>
ContextHolder.setCustomerType(ContextHolder.DATA_SOURCE_READ);
1、一直有一个疑问,既然xml配置中bean是启动的时候就加载到内存当中,且全局只有一个对象,那么在运行时设置ContextHolder参数可以修改数据源呢?
2、为什么在配置了事务的时候(@transaction),是改变不了数据源的呢?对于第一个问题,在设置了ContextHolder之后,再开始使用sqlSessionFactory进行数据库相关操作,这时候sqlSessionFactory会找到真正的datasource
public void setDataSource(DataSource dataSource) { if (dataSource instanceof TransactionAwareDataSourceProxy) { // If we got a TransactionAwareDataSourceProxy, we need to perform // transactions for its underlying target DataSource, else data // access code won't see properly exposed transactions (i.e. // transactions for the target DataSource). this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); } else { this.dataSource = dataSource; } }而mydatesource继承自AbstractRoutingDataSource,类中精华部分在这里
/** * Retrieve the current target DataSource. Determines the * {@link #determineCurrentLookupKey() current lookup key}, performs * a lookup in the {@link #setTargetDataSources targetDataSources} map, * falls back to the specified * {@link #setDefaultTargetDataSource default target DataSource} if necessary. * @see #determineCurrentLookupKey() */protected DataSource determineTargetDataSource() {Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");Object lookupKey = determineCurrentLookupKey();DataSource dataSource = this.resolvedDataSources.get(lookupKey);if (dataSource == null && (this.lenientFallback || lookupKey == null)) {dataSource = this.resolvedDefaultDataSource;}if (dataSource == null) {throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");}return dataSource;}
他会调用determineCurrentLookupKey()方法选择合适的数据源的key,而这个方法在我们的MyDataSource类中已经实现,且将向下文需要的ContextHolder设置了进去。
这样就实现了运行时的动态数据库的选择。
0 0
- spring 动态数据源配置以及相关问题
- spring mvc 配置DataSource以及动态数据源
- 动态数据源相关问题
- spring动态数据源配置以及以及利用AOP自动设置
- spring动态数据源配置以及以及利用AOP自动设置
- spring配置动态数据源
- Spring 动态数据源配置
- spring配置数据源问题
- spring + hibernate动态数据源配置
- spring + hibernate动态数据源配置
- Spring+mybatis配置动态数据源
- spring boot 动态数据源配置
- Spring动态数据源创建以及切换方案
- Spring MVC+分布式事务+动态数据源配置
- Spring mvc 动态数据源的配置
- Spring BeanPostProcessor与动态加载数据源配置
- Spring BeanPostProcessor与动态加载数据源配置
- Spring BeanPostProcessor与动态加载数据源配置
- 在最新版的R语言中安装Rwordseg包
- [四种]网络游戏外挂的制作方法
- 关于SQLServer的最大连接数
- sql sever 2008 触发器的问题
- 杰科技任务快乐将诶为己任
- spring 动态数据源配置以及相关问题
- Android-Async-Http介绍
- 分治法--合并排序
- oracle常用函数大全
- 怎样使用initramfs
- LVS路由模式负载均衡
- Git Official Document
- php 连接oracle 无法 启用oci8 解决办法 (摘自oracle官网)
- linux操作系统-3进程管理(3)