SSH框架系列:Spring配置多个数据源

时间:2021-11-12 14:30:22
分类: 【java】2013-12-09 16:59 1247人阅读 评论(0) 收藏 举报

1.问题的引入

对于普通的SSH框架而言,一般配置一个数据源,一个SessionFactory,一个事务管理和对应的ProxyCreate。那么当项目需要操作多个数据库时,如何配置呢?

方案1

配置2个数据源,2个对应的SessionFactory,2个事务等。Spring的配置如下:

  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:context="http://www.springframework.org/schema/context"
  4. xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/tx
  8. http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  9. http://www.springframework.org/schema/aop
  10. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  13. <!-- 引入datasource配置文件 -->
  14. <context:property-placeholder location="classpath:datasource.properties" />
  15. <!--创建mysql jdbc数据源 -->
  16. <bean id="mysqlDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  17. destroy-method="close">
  18. <property name="driverClass" value="${jdbc.mysql.driver}" />
  19. <property name="jdbcUrl" value="${jdbc.mysql.url}" />
  20. <property name="user" value="${jdbc.mysql.username}" />
  21. <property name="password" value="${jdbc.mysql.password}" />
  22. <!-- 指定连接数据库连接池的最小连接数 -->
  23. <property name="minPoolSize" value="10" />
  24. <!-- 指定连接数据库连接池的最大连接数 -->
  25. <property name="maxPoolSize" value="30" />
  26. <!-- 指定连接数据库连接池的连接的最大空闲时间 -->
  27. <property name="maxIdleTime" value="1800" />
  28. <property name="acquireIncrement" value="2" />
  29. <property name="maxStatements" value="0" />
  30. <!-- 指定连接数据库连接池的初始化连接数 -->
  31. <property name="initialPoolSize" value="2" />
  32. <property name="idleConnectionTestPeriod" value="1800" />
  33. <!-- 当连接失败时,尝试重新连接的次数 -->
  34. <property name="acquireRetryAttempts" value="30" />
  35. <property name="breakAfterAcquireFailure" value="true" />
  36. <property name="testConnectionOnCheckout" value="false" />
  37. </bean>
  38. <!--创建oracle jdbc数据源 -->
  39. <bean id="oracleDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  40. destroy-method="close">
  41. <property name="driverClass" value="${jdbc.oracle.driver}" />
  42. <property name="jdbcUrl" value="${jdbc.oracle.url}" />
  43. <property name="user" value="${jdbc.oracle.username}" />
  44. <property name="password" value="${jdbc.oracle.password}" />
  45. <!-- 指定连接数据库连接池的最小连接数 -->
  46. <property name="minPoolSize" value="10" />
  47. <!-- 指定连接数据库连接池的最大连接数 -->
  48. <property name="maxPoolSize" value="30" />
  49. <!-- 指定连接数据库连接池的连接的最大空闲时间 -->
  50. <property name="maxIdleTime" value="1800" />
  51. <property name="acquireIncrement" value="2" />
  52. <property name="maxStatements" value="0" />
  53. <!-- 指定连接数据库连接池的初始化连接数 -->
  54. <property name="initialPoolSize" value="2" />
  55. <property name="idleConnectionTestPeriod" value="1800" />
  56. <!-- 当连接失败时,尝试重新连接的次数 -->
  57. <property name="acquireRetryAttempts" value="1" />
  58. <property name="breakAfterAcquireFailure" value="true" />
  59. <property name="testConnectionOnCheckout" value="false" />
  60. </bean>
  61. <!-- 创建MysqlSessionFactory-->
  62. <bean id="mysqlSessionFactory"
  63. class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  64. <property name="dataSource" ref="mysqlDataSource" />
  65. <property name="hibernateProperties">
  66. <props>
  67. <prop key="hibernate.show_sql">true</prop>
  68. <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
  69. <prop key="current_session_context_class">thread</prop>
  70. </props>
  71. </property>
  72. <property name="mappingResources">
  73. <list>
  74. <value>edu/njupt/zhb/model/mysql/Student.hbm.xml</value>
  75. </list>
  76. </property>
  77. </bean>
  78. <!-- 创建OracleSessionFactory-->
  79. <bean id="oracleSessionFactory"
  80. class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  81. <property name="dataSource" ref="oracleDataSource" />
  82. <property name="hibernateProperties">
  83. <props>
  84. <prop key="hibernate.show_sql">true</prop>
  85. <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
  86. <prop key="current_session_context_class">thread</prop>
  87. </props>
  88. </property>
  89. <property name="mappingResources">
  90. <list>
  91. <value>edu/njupt/zhb/model/oracle/Student.hbm.xml</value>
  92. </list>
  93. </property>
  94. </bean>
  95. <!-- 配置Mysql事务 -->
  96. <bean id="mysqlTransactionManager"
  97. class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  98. <property name="sessionFactory">
  99. <ref local="mysqlSessionFactory" />
  100. </property>
  101. </bean>
  102. <!--Mysql hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到-->
  103. <bean id="mysqlTransactionInterceptor"
  104. class="org.springframework.transaction.interceptor.TransactionInterceptor">
  105. <property name="transactionManager">
  106. <ref local="mysqlTransactionManager" />
  107. </property>
  108. <property name="transactionAttributes">
  109. <props>
  110. <prop key="register">PROPAGATION_REQUIRED</prop>
  111. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
  112. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
  113. <prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
  114. <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
  115. <prop key="sync*">PROPAGATION_REQUIRED</prop>
  116. <prop key="finish*">PROPAGATION_REQUIRED</prop>
  117. <prop key="add*">PROPAGATION_REQUIRED</prop>
  118. <prop key="insert*">PROPAGATION_REQUIRED</prop>
  119. <prop key="edit*">PROPAGATION_REQUIRED</prop>
  120. <prop key="update*">PROPAGATION_REQUIRED</prop>
  121. <prop key="save*">PROPAGATION_REQUIRED</prop>
  122. <prop key="remove*">PROPAGATION_REQUIRED</prop>
  123. <prop key="delete*">PROPAGATION_REQUIRED</prop>
  124. <prop key="modify*">PROPAGATION_REQUIRED</prop>
  125. <prop key="*">PROPAGATION_REQUIRED,-java.lang.Exception</prop>
  126. </props>
  127. </property>
  128. </bean>
  129. <!-- 配置oracle事务 -->
  130. <bean id="oracleTransactionManager"
  131. class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  132. <property name="sessionFactory">
  133. <ref local="oracleSessionFactory" />
  134. </property>
  135. </bean>
  136. <!--Mysql hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到-->
  137. <bean id="oracleTransactionInterceptor"
  138. class="org.springframework.transaction.interceptor.TransactionInterceptor">
  139. <property name="transactionManager">
  140. <ref local="oracleTransactionManager" />
  141. </property>
  142. <property name="transactionAttributes">
  143. <props>
  144. <prop key="register">PROPAGATION_REQUIRED</prop>
  145. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
  146. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
  147. <prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
  148. <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
  149. <prop key="sync*">PROPAGATION_REQUIRED</prop>
  150. <prop key="finish*">PROPAGATION_REQUIRED</prop>
  151. <prop key="add*">PROPAGATION_REQUIRED</prop>
  152. <prop key="insert*">PROPAGATION_REQUIRED</prop>
  153. <prop key="edit*">PROPAGATION_REQUIRED</prop>
  154. <prop key="update*">PROPAGATION_REQUIRED</prop>
  155. <prop key="save*">PROPAGATION_REQUIRED</prop>
  156. <prop key="remove*">PROPAGATION_REQUIRED</prop>
  157. <prop key="delete*">PROPAGATION_REQUIRED</prop>
  158. <prop key="modify*">PROPAGATION_REQUIRED</prop>
  159. <prop key="*">PROPAGATION_REQUIRED,-java.lang.Exception</prop>
  160. </props>
  161. </property>
  162. </bean>
  163. <!-- autoproxy 自动创建代理-->
  164. <bean id="ProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  165. <property name="beanNames">
  166. <list>
  167. <value>*ServiceImpl</value>
  168. </list>
  169. </property>
  170. <property name="interceptorNames">
  171. <list>
  172. <value>mysqlTransactionInterceptor</value>
  173. <value>oracleTransactionInterceptor</value>
  174. </list>
  175. </property>
  176. </bean>
  177. <!--********************************注入Mysql Dao*********************************************-->
  178. <bean id="mysqlBaseDao" class="edu.njupt.zhb.dao.MysqlBaseDao">
  179. <property name="sessionFactory" ref="mysqlSessionFactory"></property>
  180. </bean>
  181. <!--********************************注入Oracle Dao*********************************************-->
  182. <bean id="oracleBaseDao" class="edu.njupt.zhb.dao.OracleBaseDao">
  183. <property name="sessionFactory" ref="oracleSessionFactory"></property>
  184. </bean>
  185. <!--********************************注入Services********************************-->
  186. <!--********************************注入Action********************************-->
  187. </beans>

优缺点分析:

优点:我们能够在程序中正常得使用2个不同的Dao,而且可以调用dao的getSessionFactory().getCurrentSession(),使用起来特别的方便。每个Dao都有自己的事务管理,安全性各方面和一个数据库一样。

缺点:由于事务的配置和自动创建代理的配置,只要有一个数据库连接不了,即便两外一个数据库可以连接,整个项目仍然无法正常启动。对于一些特殊的应用场景,该方案有着很大的缺陷。

比如某项目的需求为:一个项目需要同时操作2个数据库,如果一个数据库无法连接,那么项目就操作另外一个数据库,同时,将操作的动作记录下来,等另外一个数据库可以连接的时候,再将之前的操作同步到这个数据库中。而且要求,当项目启动的时候,即便只有一个数据库可以连接,那么项目仍然要正常运行。

方案2

为了解决上述的需求,我们将其中一个数据库作为本地数据库,另外一个作为远程数据库,当远程数据库无法连接时,我们跳过。整个项目使用本地数据库即可,同时将需要同步的数据,保存起来,待可连接时,再同步。

  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:context="http://www.springframework.org/schema/context"
  4. xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  7. http://www.springframework.org/schema/tx
  8. http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
  9. http://www.springframework.org/schema/aop
  10. http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
  11. http://www.springframework.org/schema/context
  12. http://www.springframework.org/schema/context/spring-context-3.0.xsd">
  13. <!-- 引入datasource配置文件 -->
  14. <context:property-placeholder location="classpath:datasource.properties" />
  15. <!--创建mysql jdbc数据源 -->
  16. <bean id="mysqlDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  17. destroy-method="close">
  18. <property name="driverClass" value="${jdbc.mysql.driver}" />
  19. <property name="jdbcUrl" value="${jdbc.mysql.url}" />
  20. <property name="user" value="${jdbc.mysql.username}" />
  21. <property name="password" value="${jdbc.mysql.password}" />
  22. <!-- 指定连接数据库连接池的最小连接数 -->
  23. <property name="minPoolSize" value="10" />
  24. <!-- 指定连接数据库连接池的最大连接数 -->
  25. <property name="maxPoolSize" value="30" />
  26. <!-- 指定连接数据库连接池的连接的最大空闲时间 -->
  27. <property name="maxIdleTime" value="1800" />
  28. <property name="acquireIncrement" value="2" />
  29. <property name="maxStatements" value="0" />
  30. <!-- 指定连接数据库连接池的初始化连接数 -->
  31. <property name="initialPoolSize" value="2" />
  32. <property name="idleConnectionTestPeriod" value="1800" />
  33. <!-- 当连接失败时,尝试重新连接的次数 -->
  34. <property name="acquireRetryAttempts" value="30" />
  35. <property name="breakAfterAcquireFailure" value="true" />
  36. <property name="testConnectionOnCheckout" value="false" />
  37. </bean>
  38. <!--创建oracle jdbc数据源 -->
  39. <bean id="oracleDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
  40. destroy-method="close">
  41. <property name="driverClass" value="${jdbc.oracle.driver}" />
  42. <property name="jdbcUrl" value="${jdbc.oracle.url}" />
  43. <property name="user" value="${jdbc.oracle.username}" />
  44. <property name="password" value="${jdbc.oracle.password}" />
  45. <!-- 指定连接数据库连接池的最小连接数 -->
  46. <property name="minPoolSize" value="10" />
  47. <!-- 指定连接数据库连接池的最大连接数 -->
  48. <property name="maxPoolSize" value="30" />
  49. <!-- 指定连接数据库连接池的连接的最大空闲时间 -->
  50. <property name="maxIdleTime" value="1800" />
  51. <property name="acquireIncrement" value="2" />
  52. <property name="maxStatements" value="0" />
  53. <!-- 指定连接数据库连接池的初始化连接数 -->
  54. <property name="initialPoolSize" value="2" />
  55. <property name="idleConnectionTestPeriod" value="1800" />
  56. <!-- 当连接失败时,尝试重新连接的次数 -->
  57. <property name="acquireRetryAttempts" value="1" />
  58. <property name="breakAfterAcquireFailure" value="true" />
  59. <property name="testConnectionOnCheckout" value="false" />
  60. </bean>
  61. <!-- 创建MysqlSessionFactory-->
  62. <bean id="mysqlSessionFactory"
  63. class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  64. <property name="dataSource" ref="mysqlDataSource" />
  65. <property name="hibernateProperties">
  66. <props>
  67. <prop key="hibernate.show_sql">true</prop>
  68. <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
  69. <prop key="current_session_context_class">thread</prop>
  70. </props>
  71. </property>
  72. <property name="mappingResources">
  73. <list>
  74. <value>edu/njupt/zhb/model/mysql/Student.hbm.xml</value>
  75. </list>
  76. </property>
  77. </bean>
  78. <!-- 创建OracleSessionFactory-->
  79. <bean id="oracleSessionFactory"
  80. class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
  81. <property name="dataSource" ref="oracleDataSource" />
  82. <property name="hibernateProperties">
  83. <props>
  84. <prop key="hibernate.show_sql">true</prop>
  85. <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
  86. <prop key="current_session_context_class">thread</prop>
  87. </props>
  88. </property>
  89. <property name="mappingResources">
  90. <list>
  91. <value>edu/njupt/zhb/model/oracle/Student.hbm.xml</value>
  92. </list>
  93. </property>
  94. </bean>
  95. <!-- 配置Mysql事务 -->
  96. <bean id="mysqlTransactionManager"
  97. class="org.springframework.orm.hibernate4.HibernateTransactionManager">
  98. <property name="sessionFactory">
  99. <ref local="mysqlSessionFactory" />
  100. </property>
  101. </bean>
  102. <!--Mysql hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到-->
  103. <bean id="mysqlTransactionInterceptor"
  104. class="org.springframework.transaction.interceptor.TransactionInterceptor">
  105. <property name="transactionManager">
  106. <ref local="mysqlTransactionManager" />
  107. </property>
  108. <property name="transactionAttributes">
  109. <props>
  110. <prop key="register">PROPAGATION_REQUIRED</prop>
  111. <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
  112. <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
  113. <prop key="select*">PROPAGATION_REQUIRED,readOnly</prop>
  114. <prop key="query*">PROPAGATION_REQUIRED,readOnly</prop>
  115. <prop key="sync*">PROPAGATION_REQUIRED</prop>
  116. <prop key="finish*">PROPAGATION_REQUIRED</prop>
  117. <prop key="add*">PROPAGATION_REQUIRED</prop>
  118. <prop key="insert*">PROPAGATION_REQUIRED</prop>
  119. <prop key="edit*">PROPAGATION_REQUIRED</prop>
  120. <prop key="update*">PROPAGATION_REQUIRED</prop>
  121. <prop key="save*">PROPAGATION_REQUIRED</prop>
  122. <prop key="remove*">PROPAGATION_REQUIRED</prop>
  123. <prop key="delete*">PROPAGATION_REQUIRED</prop>
  124. <prop key="modify*">PROPAGATION_REQUIRED</prop>
  125. <prop key="*">PROPAGATION_REQUIRED,-java.lang.Exception</prop>
  126. </props>
  127. </property>
  128. </bean>
  129. <!-- autoproxy 自动创建代理-->
  130. <bean id="ProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  131. <property name="beanNames">
  132. <list>
  133. <value>*ServiceImpl</value>
  134. </list>
  135. </property>
  136. <property name="interceptorNames">
  137. <list>
  138. <value>mysqlTransactionInterceptor</value>
  139. </list>
  140. </property>
  141. </bean>
  142. <!--********************************注入Mysql Dao*********************************************-->
  143. <bean id="mysqlBaseDao" class="edu.njupt.zhb.dao.MysqlBaseDao">
  144. <property name="sessionFactory" ref="mysqlSessionFactory"></property>
  145. </bean>
  146. <!--********************************注入Oracle Dao*********************************************-->
  147. <bean id="oracleBaseDao" class="edu.njupt.zhb.dao.OracleBaseDao">
  148. <property name="sessionFactory" ref="oracleSessionFactory"></property>
  149. </bean>
  150. <!--********************************注入Services********************************-->
  151. <!--********************************注入Action********************************-->
  152. </beans>

这种配置下,oracleBaseDao的数据源的属性:acquireRetryAttempts的值配置为1,即便无法连接,我们也只需要连接一次,不会出现“卡住”的情况。而且,由于oracleBaseDao中,我们没有配置事务,因此,dao无法获得getCurrentSession,只能通过sessionFactory().openSession()来使用Hibernate。同时为了捕获异常,我们将session设置成手动提交的方式。