`
tooby
  • 浏览: 117284 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

spring多数据源配置

 
阅读更多

项目中我们经常会遇到多数据源的问题,尤其是数据同步或定时任务等项目更是如此。多数据源让人最头痛的,不是配置多个数据源,而是如何能灵活动态的切换数据源。例如在一个springhibernate的框架的项目中,我们在spring配置中往往是配置一个dataSource来连接数据库,然后绑定给sessionFactory,在dao层代码中再指定sessionFactory来进行数据库操作。

正如上图所示,每一块都是指定绑死的,如果是多个数据源,也只能是下图中那种方式。

可看出在Dao层代码中写死了两个SessionFactory,这样日后如果再多一个数据源,还要改代码添加一个SessionFactory,显然这并不符合开闭原则。

那么正确的做法应该是

代码如下:

1. applicationContext.xml

[html] view plain copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
  4.     xmlns:cache="http://www.springframework.org/schema/cache"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"  
  7.     xmlns:jms="http://www.springframework.org/schema/jms" xmlns:lang="http://www.springframework.org/schema/lang"  
  8.     xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:oxm="http://www.springframework.org/schema/oxm"  
  9.     xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task"  
  10.     xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"  
  11.     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd    
  12.     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd    
  13.     http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd    
  14.     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd    
  15.     http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd    
  16.     http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd    
  17.     http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd    
  18.     http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd    
  19.     http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd    
  20.     http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd    
  21.     http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd    
  22.     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd    
  23.     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">  
  24.   
  25.     <context:annotation-config />  
  26.   
  27.     <context:component-scan base-package="com"></context:component-scan>  
  28.   
  29.     <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  30.         <property name="locations">  
  31.             <list>  
  32.                 <value>classpath:com/resource/config.properties</value>  
  33.             </list>  
  34.         </property>  
  35.     </bean>  
  36.   
  37.     <bean id="dataSourceOne" class="com.mchange.v2.c3p0.ComboPooledDataSource"  
  38.         destroy-method="close">  
  39.         <property name="driverClass" value="${dbOne.jdbc.driverClass}" />  
  40.         <property name="jdbcUrl" value="${dbOne.jdbc.url}" />  
  41.         <property name="user" value="${dbOne.jdbc.user}" />  
  42.         <property name="password" value="${dbOne.jdbc.password}" />  
  43.         <property name="initialPoolSize" value="${dbOne.jdbc.initialPoolSize}" />  
  44.         <property name="minPoolSize" value="${dbOne.jdbc.minPoolSize}" />  
  45.         <property name="maxPoolSize" value="${dbOne.jdbc.maxPoolSize}" />  
  46.     </bean>  
  47.   
  48.     <bean id="dataSourceTwo" class="com.mchange.v2.c3p0.ComboPooledDataSource"  
  49.         destroy-method="close">  
  50.         <property name="driverClass" value="${dbTwo.jdbc.driverClass}" />  
  51.         <property name="jdbcUrl" value="${dbTwo.jdbc.url}" />  
  52.         <property name="user" value="${dbTwo.jdbc.user}" />  
  53.         <property name="password" value="${dbTwo.jdbc.password}" />  
  54.         <property name="initialPoolSize" value="${dbTwo.jdbc.initialPoolSize}" />  
  55.         <property name="minPoolSize" value="${dbTwo.jdbc.minPoolSize}" />  
  56.         <property name="maxPoolSize" value="${dbTwo.jdbc.maxPoolSize}" />  
  57.     </bean>  
  58.   
  59.     <bean id="dynamicDataSource" class="com.core.DynamicDataSource">  
  60.         <property name="targetDataSources">  
  61.             <map key-type="java.lang.String">  
  62.                 <entry value-ref="dataSourceOne" key="dataSourceOne"></entry>  
  63.                 <entry value-ref="dataSourceTwo" key="dataSourceTwo"></entry>  
  64.             </map>  
  65.         </property>  
  66.         <property name="defaultTargetDataSource" ref="dataSourceOne">  
  67.         </property>  
  68.     </bean>  
  69.   
  70.     <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">  
  71.         <property name="dataSource" ref="dynamicDataSource" />  
  72.         <property name="hibernateProperties">  
  73.             <props>  
  74.                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>  
  75.                 <prop key="hibernate.current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext</prop>  
  76.                 <prop key="hibernate.show_sql">false</prop>  
  77.                 <prop key="hibernate.format_sql">true</prop>  
  78.                 <prop key="hbm2ddl.auto">create</prop>  
  79.             </props>  
  80.         </property>  
  81.         <property name="packagesToScan">  
  82.             <list>  
  83.                 <value>com.po</value>  
  84.             </list>  
  85.         </property>  
  86.     </bean>  
  87.   
  88.     <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">  
  89.         <property name="sessionFactory" ref="sessionFactory" />  
  90.     </bean>  
  91.   
  92.     <aop:config>  
  93.         <aop:pointcut id="transactionPointCut" expression="execution(* com.dao..*.*(..))" />  
  94.         <aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointCut" />  
  95.     </aop:config>  
  96.   
  97.     <tx:advice id="txAdvice" transaction-manager="transactionManager">  
  98.         <tx:attributes>  
  99.             <tx:method name="add*" propagation="REQUIRED" />  
  100.             <tx:method name="save*" propagation="REQUIRED" />  
  101.             <tx:method name="update*" propagation="REQUIRED" />  
  102.             <tx:method name="delete*" propagation="REQUIRED" />  
  103.             <tx:method name="*" read-only="true" />  
  104.         </tx:attributes>  
  105.     </tx:advice>  
  106.   
  107.     <aop:config>  
  108.         <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor">  
  109.             <aop:pointcut id="daoOne" expression="execution(* com.dao.one.*.*(..))" />  
  110.             <aop:pointcut id="daoTwo" expression="execution(* com.dao.two.*.*(..))" />  
  111.             <aop:before pointcut-ref="daoOne" method="setdataSourceOne" />  
  112.             <aop:before pointcut-ref="daoTwo" method="setdataSourceTwo" />  
  113.         </aop:aspect>  
  114.     </aop:config>  
  115. </beans>  

2. DynamicDataSource.class

[java] view plain copy
 
  1. package com.core;  
  2.   
  3. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
  4.   
  5. public class DynamicDataSource extends AbstractRoutingDataSource{  
  6.   
  7.     @Override  
  8.     protected Object determineCurrentLookupKey() {  
  9.         return DatabaseContextHolder.getCustomerType();   
  10.     }  
  11.   
  12. }  

3. DatabaseContextHolder.class

[java] view plain copy
 
  1. package com.core;  
  2.   
  3. public class DatabaseContextHolder {  
  4.   
  5.     private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
  6.   
  7.     public static void setCustomerType(String customerType) {  
  8.         contextHolder.set(customerType);  
  9.     }  
  10.   
  11.     public static String getCustomerType() {  
  12.         return contextHolder.get();  
  13.     }  
  14.   
  15.     public static void clearCustomerType() {  
  16.         contextHolder.remove();  
  17.     }  
  18. }  

4. DataSourceInterceptor.class

[java] view plain copy
 
  1. package com.core;  
  2.   
  3. import org.aspectj.lang.JoinPoint;  
  4. import org.springframework.stereotype.Component;  
  5.   
  6. @Component  
  7. public class DataSourceInterceptor {  
  8.   
  9.     public void setdataSourceOne(JoinPoint jp) {  
  10.         DatabaseContextHolder.setCustomerType("dataSourceOne");  
  11.     }  
  12.       
  13.     public void setdataSourceTwo(JoinPoint jp) {  
  14.         DatabaseContextHolder.setCustomerType("dataSourceTwo");  
  15.     }  
  16. }  

5. po实体类

[java] view plain copy
 
  1. package com.po;  
  2.   
  3. import javax.persistence.Column;  
  4. import javax.persistence.Entity;  
  5. import javax.persistence.Id;  
  6. import javax.persistence.Table;  
  7.   
  8. @Entity  
  9. @Table(name = "BTSF_BRAND", schema = "hotel")  
  10. public class Brand {  
  11.   
  12.     private String id;  
  13.     private String names;  
  14.     private String url;  
  15.   
  16.     @Id  
  17.     @Column(name = "ID", unique = true, nullable = false, length = 10)  
  18.     public String getId() {  
  19.         return this.id;  
  20.     }  
  21.   
  22.     public void setId(String id) {  
  23.         this.id = id;  
  24.     }  
  25.   
  26.     @Column(name = "NAMES", nullable = false, length = 50)  
  27.     public String getNames() {  
  28.         return this.names;  
  29.     }  
  30.   
  31.     public void setNames(String names) {  
  32.         this.names = names;  
  33.     }  
  34.   
  35.     @Column(name = "URL", length = 200)  
  36.     public String getUrl() {  
  37.         return this.url;  
  38.     }  
  39.   
  40.     public void setUrl(String url) {  
  41.         this.url = url;  
  42.     }  
  43. }  
[java] view plain copy
 
  1. package com.po;  
  2.   
  3. import javax.persistence.Column;  
  4. import javax.persistence.Entity;  
  5. import javax.persistence.Id;  
  6. import javax.persistence.Table;  
  7.   
  8. @Entity  
  9. @Table(name = "CITY", schema = "car")  
  10. public class City {  
  11.   
  12.     private Integer id;  
  13.       
  14.     private String name;  
  15.   
  16.     @Id  
  17.     @Column(name = "ID", unique = true, nullable = false)  
  18.     public Integer getId() {  
  19.         return id;  
  20.     }  
  21.   
  22.     public void setId(Integer id) {  
  23.         this.id = id;  
  24.     }  
  25.   
  26.     @Column(name = "NAMES", nullable = false, length = 50)  
  27.     public String getName() {  
  28.         return name;  
  29.     }  
  30.   
  31.     public void setName(String name) {  
  32.         this.name = name;  
  33.     }  
  34. }  

6. BrandDaoImpl.class

[java] view plain copy
 
  1. package com.dao.one;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.annotation.Resource;  
  6.   
  7. import org.hibernate.Query;  
  8. import org.hibernate.SessionFactory;  
  9. import org.springframework.stereotype.Repository;  
  10.   
  11. import com.po.Brand;  
  12.   
  13. @Repository  
  14. public class BrandDaoImpl implements IBrandDao {  
  15.   
  16.     @Resource  
  17.     protected SessionFactory sessionFactory;  
  18.   
  19.     @SuppressWarnings("unchecked")  
  20.     @Override  
  21.     public List<Brand> findAll() {  
  22.         String hql = "from Brand";  
  23.         Query query = sessionFactory.getCurrentSession().createQuery(hql);  
  24.         return query.list();  
  25.     }  
  26. }  

7. CityDaoImpl.class

[java] view plain copy
 
  1. package com.dao.two;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.annotation.Resource;  
  6.   
  7. import org.hibernate.Query;  
  8. import org.hibernate.SessionFactory;  
  9. import org.springframework.stereotype.Repository;  
  10.   
  11. import com.po.City;  
  12.   
  13. @Repository  
  14. public class CityDaoImpl implements ICityDao {  
  15.   
  16.     @Resource  
  17.     private SessionFactory sessionFactory;  
  18.   
  19.     @SuppressWarnings("unchecked")  
  20.     @Override  
  21.     public List<City> find() {  
  22.         String hql = "from City";  
  23.         Query query = sessionFactory.getCurrentSession().createQuery(hql);  
  24.         return query.list();  
  25.     }  
  26. }  

8. DaoTest.class

[java] view plain copy
 
  1. package com.test;  
  2.   
  3. import java.util.List;  
  4.   
  5. import javax.annotation.Resource;  
  6.   
  7. import org.junit.Test;  
  8. import org.junit.runner.RunWith;  
  9. import org.springframework.test.context.ContextConfiguration;  
  10. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  11. import org.springframework.test.context.transaction.TransactionConfiguration;  
  12.   
  13. import com.dao.one.IBrandDao;  
  14. import com.dao.two.ICityDao;  
  15. import com.po.Brand;  
  16. import com.po.City;  
  17.   
  18. @RunWith(SpringJUnit4ClassRunner.class)  
  19. @ContextConfiguration(locations = "classpath:com/resource/applicationContext.xml")  
  20. @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)  
  21. public class DaoTest {  
  22.   
  23.     @Resource  
  24.     private IBrandDao brandDao;  
  25.   
  26.     @Resource  
  27.     private ICityDao cityDao;  
  28.   
  29.     @Test  
  30.     public void testList() {  
  31.         List<Brand> brands = brandDao.findAll();  
  32.         System.out.println(brands.size());  
  33.   
  34.         List<City> cities = cityDao.find();  
  35.         System.out.println(cities.size());  
  36.     }  
  37. }  

利用aop,达到动态更改数据源的目的。当需要增加数据源的时候,我们只需要在applicationContext配置文件中添加aop配置,新建个DataSourceInterceptor即可。而不需要更改任何代码。

 

多数据源配置时的重点:

1. 注意事务拦截器的配置

这是首要的一条。首先你要明白,Spring的事务管理是与数据源绑定的,一旦程序执行到事务管理的那一层(如service)的话,由于在进入该层之前事务已经通过拦截器开启,因此在该层切换数据源是不行的,明白事务的原理是尤为重要的,我之前的文章中,将切换数据源的拦截器配置在了Dao层是有问题的(因为是示例,所以粗心了,对误导了大家我表示道歉),但提供的思路是没有问题的。

Demo中将切换数据源的拦截器(dataSourceInterceptor)配置在了事务拦截器(txadvice)的上一层,也就是Controller层。

2. 注意数据库表的创建

一些人喜欢用hibernate的自动创建表的功能,但需要注意,在多数据源中,尤其是不同数据库的多数据源,想都自动建表是不行的。因为Hibernate自动建表是在项目启动时触发的,因此只会建立项目配置的默认数据源的表,而其他数据源的表则不会自动创建。大家要注意着点。

3. Hibernate的数据库方言(dialect)可以忽略

在多数据源时,方言的设置可以忽略,Hibernate在使用时会自动识别不同的数据库,因此不必纠结这个配置,甚至不配置也可以。

4. 报No current session错误

这个是因为使用了sessionFactory.getCurrentSession()导致的,current session是与线程绑定的,一个线程只会开启一个Session(除非使用openSession()就不会报错),因此需要设置session与线程的绑定关系。

Demo中使用了Spring管理Hibernate的session,因此在web.xml中配置了OpenSessionInViewFilter,并在hibernate.cfg.xml中配置了current_session_context_class。【PS:使用Spring管理Hibernate时,可以去掉hibernate.cfg.xml,而全部配置的Spring的配置文件里,即hibernateProperties

分享到:
评论

相关推荐

    Spring多数据源配置

    Spring多数据源配置,支持mysql、oracle等多个数据源同时存在的情况

    基于注解的Spring多数据源配置和使用

    ### 基于注解的Spring多数据源配置与使用详解 #### 一、引言 在企业级应用开发中,经常会遇到需要从多个数据库拉取数据的情况,比如进行跨库查询、定时任务中的数据分析及报表统计等。Spring框架作为Java开发领域的...

    Spring多数据源配置_分布式数据

    ### Spring多数据源配置与分布式数据管理 #### 环境及框架介绍 在本案例中,我们将探讨如何在基于Tomcat服务器的环境下配置多个数据源,并实现分布式数据的交互。该系统的架构主要包括:Tomcat作为应用服务器,...

    spring数据源配置

    ### Spring 数据源配置详解 #### 一、Spring与数据源简介 在Java企业级应用开发中,数据库操作是必不可少的一部分。Spring框架作为一种流行的轻量级Java应用开发框架,提供了强大的数据库访问支持,其中包括对数据...

    基于注解和Spring的多数据源配置和使用

    本篇文章将深入探讨如何基于注解和Spring实现多数据源配置和使用。 首先,我们需要理解"注解"在Java中的作用。注解是一种元数据,它提供了一种安全的方法来关联信息和代码(类、方法、变量等)。Spring框架广泛使用...

    spring boot多数据源配置

    在Spring Boot应用中,多数据源配置是一项关键的技术,它允许我们同时管理多个数据库,比如主库和从库,或者不同类型的数据库。本教程将详细阐述如何在Spring Boot项目中实现这一功能,从数据源配置、实体管理到...

    Spring多数据源分布式事务管理

    首先,让我们来了解一下Spring多数据源配置。在Spring中,我们可以通过DataSourceProxy和AbstractRoutingDataSource来实现多数据源的切换。DataSourceProxy是Spring的一个代理类,它可以对数据源进行包装,以便在...

    spring多数据源配置实现方法实例分析

    Spring多数据源配置实现方法实例分析 在实际开发中,我们经常会遇到多数据源配置的问题,而Spring框架提供了多种方式来实现多数据源配置。今天,我们将从实例出发,探索Spring多数据源配置实现方法的实例分析。 多...

    spring 动态多数据源配置代码

    下面将详细介绍Spring动态多数据源配置的相关知识点。 1. **为什么要使用多数据源**: 在实际项目中,可能需要连接到不同的数据库,例如,一个用于存储主业务数据,另一个用于日志记录或数据分析。通过多数据源...

    SSM(Spring+SpringMVC+MyBatis)多数据源配置框架

    在多数据源配置中,Spring能够帮助管理不同的数据源,通过配置bean来切换和控制数据源的使用。 **SpringMVC** 是Spring框架的一部分,专为Web开发设计。它简化了模型-视图-控制器(Model-View-Controller,MVC)的...

    springboot多数据源配置

    在Spring Boot应用中,多数据源配置是一项重要的技术实践,特别是在大型系统中,可能需要连接到多个数据库以实现数据隔离、读写分离或是分布式事务管理。Spring Boot以其强大的自动化配置能力,使得设置多数据源变得...

    Spring Boot+Jpa多数据源配置Demo(支持不同数据库)

    Spring Boot结合JPA(Java Persistence API)和JdbcTemplate,为开发者提供了灵活且强大的多数据源配置能力。本示例将详细介绍如何在Spring Boot项目中实现这样的配置,以支持不同类型的数据库。 首先,我们要理解...

    Spring 数据源不同配置

    对于需要同时连接多个数据库的应用,Spring支持多数据源配置。可以通过`@Qualifier`注解指定使用哪个数据源,或者使用`AbstractRoutingDataSource`动态路由数据源。 6. **JNDI数据源** 在应用服务器中,数据源...

    springboot +mybatis+oracle 配置多个数据源,配置两个数据库信息

    本配置示例将详细介绍如何在Spring Boot中整合MyBatis与Oracle数据库,并配置两个不同的数据源。 首先,我们需要理解数据源(DataSource)的概念。数据源是Java应用程序与数据库之间的桥梁,它负责管理数据库连接,...

    Spring多数据源atomikos所有jar包

    Atomikos是一个开源的事务管理器,专门用于处理分布式事务,它在Spring多数据源配置中扮演着重要的角色。 Atomikos是JTA(Java Transaction API)的实现,遵循X/Open XA规范,可以提供强一致性的分布式事务处理能力...

    SpringBoot配置多数据源实现动态切换数据源

    多数据源配置允许我们灵活地管理这些数据。 SpringBoot实现多数据源主要依靠Spring的`@Configuration`和`@DataSourceConfiguration`注解,以及Spring JDBC的`DataSource`接口。下面是一个基本的配置示例: ```java...

    spring多数据源.rar

    这个压缩包"spring多数据源.rar"很可能包含了详细的配置文件、样例代码、甚至可能有具体的说明文档,帮助开发者理解和实践Spring多数据源配置。这些资料将提供实际操作的指导,确保开发者能够成功地在Spring应用中...

    springAop多数据源

    总结来说,"springAop多数据源"项目涉及到Spring框架的多数据源配置、JdbcTemplate的使用、面向切面编程的应用,以及使用JUnit进行测试。理解并掌握这些技术对于构建灵活、可扩展的Java应用程序至关重要。在实践中,...

    spring mvc 配置多数据源

    # Oracle数据源配置 jdbc.driver=oracle.jdbc.OracleDriver jdbc.url=jdbc:oracle:thin:@127.0.0.1:1521:dev jdbc.username=ling jdbc.password=229 # MySQL数据源配置 jdbc-mysql.driver=com.mysql.jdbc.Driver ...

Global site tag (gtag.js) - Google Analytics