spring框架多数据源切换问题的解决
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。
Spring配置多数据源的方式和具体使用过程。
Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况:
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。
1、根据用户的选择,使用不同的数据源。
2、解决思路锁定:将sessionFactory的属性dataSource设置成不同的数据源,以达到切换数据源的目的。
4、多资源共享解决思路:同一资源被抢夺的时候,通常有两种做法,a、以时间换空间 b、以空间换时间。
5、线程同步机制就是典型的“以时间换空间”,采用排队稍等的方法,一个个等待,直到前面一个用完,后面的才跟上,多人共用一个变量,用synchronized锁定排队。
6、“ThreadLocal”就是典型的“以空间换时间”,她可以为每一个人提供一份变量,因此可以同时访问并互不干扰。
- package com.easyway.stage.commons;
- public class DbContextHolder
- {
- // ThreadLocal是线程安全的,并且不能在多线程之间共享。
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
- public static void setDbType(String dbType)
- {
- contextHolder.set(dbType);
- }
- public static String getDbType()
- {
- return ((String) contextHolder.get());
- }
- public static void clearDbType()
- {
- contextHolder.remove();
- }
- }
MultiDataSource.java
- package com.easyway.stage.commons;
- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
- public class MultiDataSource extends AbstractRoutingDataSource
- {
- @Override
- protected Object determineCurrentLookupKey()
- {
- return DbContextHolder.getDbType();
- }
- }
applicationContext.xml
- <?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:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
- xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="
- http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
- http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <context:annotation-config/>
- <!-- 数据源 -->
- <bean id="parentDataSource" class="com.alibaba.druid.pool.DruidDataSource">
- <!-- 配置初始化大小、最小、最大 -->
- <property name="initialSize" value="1" />
- <property name="maxActive" value="20" />
- <property name="minIdle" value="1" />
- <!-- 配置获取连接等待超时的时间60s -->
- <property name="maxWait" value="60000" />
- <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
- <property name="timeBetweenEvictionRunsMillis" value="60000" />
- <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
- <property name="minEvictableIdleTimeMillis" value="300000" />
- <property name="validationQuery" value="SELECT 'x'" />
- <property name="testWhileIdle" value="true" />
- <property name="testOnBorrow" value="false" />
- <property name="testOnReturn" value="false" />
- <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
- <property name="poolPreparedStatements" value="true" />
- <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
- <!-- 配置监控统计拦截的filters -->
- <property name="filters" value="wall,stat,slf4j" />
- <!-- 对于长时间不使用的连接强制关闭 -->
- <property name="removeAbandoned" value="true" />
- <!-- 超过30分钟开始关闭空闲连接 -->
- <property name="removeAbandonedTimeout" value="1800" />
- <!-- 关闭abanded连接时输出错误日志 -->
- <property name="logAbandoned" value="true" />
- </bean>
- <bean id="local" parent="parentDataSource" init-method="init" destroy-method="close">
- <property name="url" value="${local.jdbc.url}" />
- <property name="username" value="${local.jdbc.username}" />
- <property name="password" value="${local.jdbc.password}" />
- </bean>
- <bean id="server" parent="parentDataSource" init-method="init" destroy-method="close">
- <property name="url" value="${jdbc.url}" />
- <property name="username" value="${jdbc.username}" />
- <property name="password" value="${jdbc.password}" />
- </bean>
- <bean id="dataSource" class="com.autrade.stage.commons.MultiDataSource">
- <property name="targetDataSources">
- <map key-type="java.lang.String">
- <entry value-ref="local" key="local"></entry>
- <entry value-ref="server" key="server"></entry>
- </map>
- </property>
- <!-- 默认使用server的数据源 -->
- <property name="defaultTargetDataSource" ref="server"></property>
- </bean>
- <!-- MyBatis -->
- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="configLocation" value="classpath:resources/mybatis/myBatisConfig.xml" />
- <property name="mapperLocations" value="classpath:resources/mybatis/mapper/*.xml"/>
- </bean>
- <bean class="org.mybatis.spring.SqlSessionTemplate">
- <constructor-arg ref="sqlSessionFactory"/>
- </bean>
- <!-- MyBatis -->
- <!-- 配置事务管理对象-->
- <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource"/>
- </bean>
- <!-- 将所有具有@Transactional注解的Bean自动配置为声明式事务支持 -->
- <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>
- <!-- 自定义的拦截器 -->
- <bean id="methodAdvisor" class="com.easyway.app.interceptor.InjectorManager" />
- <aop:config proxy-target-class="true">
- <aop:pointcut id="baseMethods"
- expression="execution(* com.easyway.app.service..*.*(..))" />
- <aop:advisor advice-ref="methodAdvisor" pointcut-ref="baseMethods" />
- </aop:config>
- </beans>
Test.java测试类
- package com.easyway.stage.test;
- import javax.sql.DataSource;
- import org.apache.ibatis.session.SqlSession;
- import org.apache.ibatis.session.SqlSessionFactory;
- import org.mybatis.spring.SqlSessionFactoryBean;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.core.io.FileSystemResource;
- import org.springframework.core.io.Resource;
- import com.easyway.stage.commons.DbContextHolder;
- public class Test
- {
- /**
- * @param args
- */
- public static void main(String[] args)
- {
- ApplicationContext appContext = new ClassPathXmlApplicationContext("client-beans.xml");
- DbContextHolder.setDbType("local");
- String res = "resources/mybatis/myBatisConfig.xml";
- DataSource datasource = (DataSource) appContext.getBean("dataSource");
- SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
- bean.setDataSource(datasource);
- Resource resource = new FileSystemResource(res);
- bean.setConfigLocation(resource);
- try
- {
- SqlSessionFactory sessionfactory = bean.getObject();
- SqlSession session = sessionfactory.openSession();
- User user = session.selectOne("com.easyway.mybatis.mapper.findOne");
- System.out.println(user.getName());
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- DbContextHolder.setDbType("server");
- String res1 = "resources/mybatis/myBatisConfig.xml";
- DataSource datasource1 = (DataSource) appContext.getBean("dataSource");
- SqlSessionFactoryBean bean1 = new SqlSessionFactoryBean();
- bean1.setDataSource(datasource1);
- Resource resource1 = new FileSystemResource(res1);
- bean1.setConfigLocation(resource1);
- try
- {
- SqlSessionFactory sessionfactory = bean.getObject();
- SqlSession session = sessionfactory.openSession();
- User user = session.selectOne("com.easyway.mybatis.mapper.findOne");
- System.out.println(user.getName());
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
spring框架多数据源切换问题的解决相关推荐
- spring+mybatis 多数据源切换
spring+mybatis 多数据源切换 摘自: http://www.oschina.net/code/snippet_347813_12525 1. 代码: DbContextHolder pu ...
- spring框架完整配置(后面),以及解决No qualifying bean of type 或Error creating bean with name。。。
本人刚接触spring,被这问题活活困扰了两天,问题让人快速跳过这坑,特写下此文章共参考. 先说本文下出现的问题. 说下出问题的原因:这是因为我使用了两个spring的配置文件,而在web.xml配置 ...
- Spring(AbstractRoutingDataSource)实现动态数据源切换
参考:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中 ...
- Spring(AbstractRoutingDataSource)实现动态数据源切换--转载
原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目 ...
- spring mysql 多数据源_spring框架学习【多数据源配置】
在我们的项目中遇到这样一个问题:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库.我们以往在spring和hibernate框架中总是配置一个数据源,因而sessi ...
- spring boot多数据源动态切换, 多数据源事务管理
1 . 项目目标 实现 不同数据源的切换 (使用AbstractRoutingDataSource) 不同数据源之间,事物管理,多个数据源之间同时commit或者同时rollback 兼容不同的连接池 ...
- spring 动态数据源切换实例
我们很多项目中业务都需要涉及到多个数据源,最简单的做法就是直接在java代码里面lookup需要的数据源,但是这样的做法很明显耦合度太高了, 而且当逻辑流程不够严谨的时候就会出现各种大家不愿意看到的问 ...
- Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置
Spring Boot + Mybatis 配合 AOP 和注解实现动态数据源切换配置 前言: 1. 数据库准备: 2. 环境准备: 3.代码部分 4. 测试: 5.等等 6.配合注解实现 7 .测试 ...
- spring boot+mybatis 多数据源切换
由于公司业务划分了多个数据库,开发一个项目会同时调用多个库,经过学习我们采用了注解+aop的方式实现的 1.首先定义一个注解类 @Retention(RetentionPolicy.RUNTIME) ...
最新文章
- wordpress 首页调用文章 不同样式的方法
- java HashMap实现原理
- (数字IC)低功耗设计入门(六)——门级电路低功耗设计优化
- 指定Gradle构建属性
- 【C语言】结构体赋值
- List 、Set、 Map有什么区别和联系
- freecplus框架-PostgreSQL数据库操作
- mysqli 语句和mysql语句一样吗_如何为动态sql语句准备mysqli语句
- 如何利用Printconfig dll:从 iPhone 到 NT AUTHORITY\SYSTEM 的真实案例
- PROTEL 99 使用之添加库
- Java OCR文字识别(Tess4J)
- linux系统是不是国产的,LINUX是什么系统,是国产软件吗
- docker desktop 阿里云镜像加速
- [机器学习]1模型评估与选择
- TiDB at 丰巢:尝鲜分布式数据库
- jieba 详细介绍
- Yield Guild Games 和 MOBLAND 达成合作
- 【英语:语法基础】B1.核心语法-名词与代词
- java大数据课程大纲(小牛学堂)
- 转帖【编码原则十日谈】