一、前言

对于小型项目,服务器与数据库是可以在同一台机子上的,但随着业务的庞大与负责,数据库和服务器就会分离开来。同时随着数据量的增大,数据库也要分开部署到多台机子上。

二、Spring配置文件修改

理论学习与实践的差距:框架开源与不可逆的趋势[1]一文中曾经介绍过SSM框架,当时的框架采取单一数据源的配置,同时数据库的地址也没有写在properties文件中。但实际开发中,如果需要更换服务器的地址,修改XML文件会比较麻烦,一般都是提倡用properties文件,部署到正式服务器上,就只需要修改properties文件即可。

1、applicationContext.properties文件:

  1. #Mysql
  2. jdbc.mysql.driver=com.mysql.jdbc.Driver
  3. jdbc.mysql.url=jdbc:mysql://localhost:3306/db_test
  4. jdbc.mysql.username=root
  5. jdbc.mysql.password=123456
  6. #Mysql2
  7. jdbc.mysql.driver2=com.mysql.jdbc.Driver
  8. jdbc.mysql.url2=jdbc:mysql://192.168.1.8:3306/db_test
  9. jdbc.mysql.username2=root
  10. jdbc.mysql.password2=123456

2、动态数据源配置 [2]

  1. package com.test.utils;
  2. import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
  3. public class DynamicDataSource extends AbstractRoutingDataSource{
  4. public static final String mySqlDataSource = "mySqlDataSource";
  5. public static final String mySqlDataSource2 = "mySqlDataSource2";
  6. //本地线程,获取当前正在执行的currentThread
  7. public static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
  8. public static void setCustomerType(String customerType) {
  9. contextHolder.set(customerType);
  10. }
  11. public static String getCustomerType() {
  12. return contextHolder.get();
  13. }
  14. public static void clearCustomerType() {
  15. contextHolder.remove();
  16. }
  17. @Override
  18. protected Object determineCurrentLookupKey() {
  19. // TODO Auto-generated method stub
  20. return getCustomerType();
  21. }
  22. }

3、applicationContext.xml文件:

添加了对配置文件applicationContext.properties的读取,同时在dynamicDataSource中添加两个或以上的数据源,并定义一个默认的数据源

  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"
  4. xmlns:p="http://www.springframework.org/schema/p"
  5. xmlns:aop="http://www.springframework.org/schema/aop"
  6. xmlns:context="http://www.springframework.org/schema/context"
  7. xmlns:jee="http://www.springframework.org/schema/jee"
  8. xmlns:tx="http://www.springframework.org/schema/tx"
  9. xsi:schemaLocation="
  10. http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
  11. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  12. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
  13. http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
  14. http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
  15. <!-- 自动扫描 -->
  16. <context:component-scan base-package="com.test.dao" />
  17. <context:component-scan base-package="com.test.service" />
  18. <!-- 读取配置文件 -->
  19. <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  20. <property name="locations">
  21. <list>
  22. <value>classpath:applicationContext.properties</value>
  23. <!-- <value>classpath:config.properties</value> -->
  24. </list>
  25. </property>
  26. <property name="ignoreUnresolvablePlaceholders" value="true"/>
  27. </bean>
  28. <!-- 配置数据源 -->
  29. <bean id="dataSource"
  30. class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  31. <property name="driverClassName" value="${jdbc.mysql.driver}"/>
  32. <property name="url" value="${jdbc.mysql.url}"/>
  33. <property name="username" value="${jdbc.mysql.username}"/>
  34. <property name="password" value="${jdbc.mysql.password}"/>
  35. </bean>
  36. <bean id="dataSource2"
  37. class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  38. <property name="driverClassName" value="${jdbc.mysql.driver2}"/>
  39. <property name="url" value="${jdbc.mysql.url2}"/>
  40. <property name="username" value="${jdbc.mysql.username2}"/>
  41. <property name="password" value="${jdbc.mysql.password2}"/>
  42. </bean>
  43. <!-- 动态数据源 -->
  44. <bean id="dynamicDataSource" class="com.test.utils.DynamicDataSource"><!--注意: 这里写选择数据源的类地址 下面跟着给出 -->
  45. <property name="targetDataSources">
  46. <map>
  47. <entry key="mySqlDataSource" value-ref="dataSource" />
  48. <entry key="mySqlDataSource2" value-ref="dataSource2" />
  49. </map>
  50. </property>
  51. <property name="defaultTargetDataSource" ref="dataSource" /><!-- 设置默认为此mySqlDataSource数据源 -->
  52. </bean>
  53. <!-- 配置mybatis的sqlSessionFactory -->
  54. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  55. <property name="dataSource" ref="dynamicDataSource" />
  56. <!-- 自动扫描mappers.xml文件 -->
  57. <property name="mapperLocations" value="classpath:com/test/mappers/*.xml"></property>
  58. <!-- mybatis配置文件 -->
  59. <property name="configLocation" value="classpath:mybatis-config.xml"></property>
  60. </bean>
  61. <!-- DAO接口所在包名,Spring会自动查找其下的类 -->
  62. <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
  63. <property name="basePackage" value="com.test.dao" />
  64. <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
  65. </bean>
  66. <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
  67. <bean id="transactionManager"
  68. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  69. <property name="dataSource" ref="dataSource" />
  70. </bean>
  71. <!-- 配置事务通知属性 -->
  72. <tx:advice id="txAdvice" transaction-manager="transactionManager">
  73. <!-- 定义事务传播属性 -->
  74. <tx:attributes>
  75. <tx:method name="insert*" propagation="REQUIRED" />
  76. <tx:method name="update*" propagation="REQUIRED" />
  77. <tx:method name="edit*" propagation="REQUIRED" />
  78. <tx:method name="save*" propagation="REQUIRED" />
  79. <tx:method name="add*" propagation="REQUIRED" />
  80. <tx:method name="new*" propagation="REQUIRED" />
  81. <tx:method name="set*" propagation="REQUIRED" />
  82. <tx:method name="remove*" propagation="REQUIRED" />
  83. <tx:method name="delete*" propagation="REQUIRED" />
  84. <tx:method name="change*" propagation="REQUIRED" />
  85. <tx:method name="get*" propagation="REQUIRED" read-only="true" />
  86. <tx:method name="find*" propagation="REQUIRED" read-only="true" />
  87. <tx:method name="load*" propagation="REQUIRED" read-only="true" />
  88. <tx:method name="*" propagation="REQUIRED" read-only="false" />
  89. </tx:attributes>
  90. </tx:advice>
  91. <!-- 配置事务切面 -->
  92. <aop:config>
  93. <aop:pointcut id="serviceOperation"
  94. expression="execution(* com.test.service.*.*(..))" />
  95. <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
  96. </aop:config>
  97. </beans>

三、实际执行代码并动态切换数据源

1、前台jsp页面:

这里简单用a标签同步请求获取数据

  1. <a href="${pageContext.request.contextPath }/blog/searchAllBlog.do">获取列表</a>
  2. <table>
  3. <c:choose>
  4. <c:when test="${blogList==null }">
  5. <tr>
  6. <td>暂无列表</td>
  7. </tr>
  8. </c:when>
  9. <c:otherwise>
  10. <tr>
  11. <th>&nbsp;&nbsp;&nbsp;&nbsp;</th>
  12. <th>标题</th>
  13. <th>内容</th>
  14. </tr>
  15. <c:forEach var="blog" items="${blogList }" varStatus="status">
  16. <tr>
  17. <td>${status.index+1 }</td>
  18. <td>${blog.title }</td>
  19. <td>${blog.content }</td>
  20. </tr>
  21. </c:forEach>
  22. </c:otherwise>
  23. </c:choose>
  24. </table>
  25. <hr>
  26. <a href="${pageContext.request.contextPath }/blog/searchAllBlog2.do">获取列表2</a>
  27. <table>
  28. <c:choose>
  29. <c:when test="${blogList2==null }">
  30. <tr>
  31. <td>暂无列表</td>
  32. </tr>
  33. </c:when>
  34. <c:otherwise>
  35. <tr>
  36. <th>&nbsp;&nbsp;&nbsp;&nbsp;</th>
  37. <th>标题</th>
  38. <th>内容</th>
  39. </tr>
  40. <c:forEach var="blog" items="${blogList2 }" varStatus="status">
  41. <tr>
  42. <td>${status.index+1 }</td>
  43. <td>${blog.title }</td>
  44. <td>${blog.content }</td>
  45. </tr>
  46. </c:forEach>
  47. </c:otherwise>
  48. </c:choose>
  49. </table>

2、Controller层

  1. @RequestMapping("/searchAllBlog")
  2. public String searchAllBlog(HttpServletRequest request){
  3. List<Blog> blogList=blogService.searchAllBlog();
  4. request.setAttribute("blogList", blogList);
  5. return "add";
  6. }
  7. @RequestMapping("/searchAllBlog2")
  8. public String searchAllBlog2(HttpServletRequest request){
  9. List<Blog> blogList=blogService.searchAllBlog2();
  10. request.setAttribute("blogList2", blogList);
  11. return "add";
  12. }

3、Service层

  1. public interface BlogService {
  2. public int add(Blog blog);
  3. public List<Blog> searchAllBlog();
  4. public List<Blog> searchAllBlog2();
  5. }

对应的实现类:[2]

  1. @Override
  2. public List<Blog> searchAllBlog() {
  3. // TODO Auto-generated method stub
  4. return blogDao.searchAllBlog();
  5. }
  6. @Override
  7. public List<Blog> searchAllBlog2() {
  8. // TODO Auto-generated method stub
  9. List<Blog> list = null;
  10. DynamicDataSource.clearCustomerType();//重点: 实际操作证明,切换的时候最好清空一下
  11. DynamicDataSource.setCustomerType(DynamicDataSource.mySqlDataSource2);
  12. list = blogDao.searchAllBlog();
  13. DynamicDataSource.clearCustomerType();//
  14. DynamicDataSource.setCustomerType(DynamicDataSource.mySqlDataSource);//切换回主数据源
  15. return list;
  16. }

当然也可以用其他方式来实现数据源的切换,详情请参看Spring+MyBatis多数据源配置实现[3]

四、运行程序

运行程序后,点击获取获取列表2,会发现不允许连接服务器。原因是由于Mysql默认只能本机访问,不能够远程连接。这里需要对MySql进行开启权限操作。[4]

  1. grant all on 数据库名.* to ‘数据库账户名’@’%’ identified by ‘密码’ with grant option;
  2. 回车
  3. flush privileges;
  4. 回车
  5. 注意:上面的单引号不能省,数据库名.* 表示要开放的数据库下所有表,如果该连接的所有数据库都要开放,可以用 *.* 代替。
  6. ‘数据库账户名’@’%’ 这里表示要开放的账户,百分号表示在任何主机都允许访问。
  7. 如果以上两步均显示 Query OK, 0 rows affected (0.00 sec)”,那么说明命令已经成功执行,现在就可以远程连接你的mysql数据库了。

五、总结

随着业务的复杂增加,一般都会采取多数据源的方式,减轻服务器压力。一般来说Mysql占用系统资源比较少,对服务器性能影响不大,如果需要多种不同类型的数据库,那么分别部署到不同的服务器上可以优化性能,提供系统的运行速度。当然,如果项目过于巨大,会被变成分布式项目,将不同功能的子系统部署到不同服务器上。

Reference:

[1] ryelqy, 理论学习与实践的差距:框架开源与不可逆的趋势, https://blog.csdn.net/ryelqy/article/details/81368083

[2] 现世安稳。SpringMVC配置多个数据源,  https://www.cnblogs.com/hero123/p/8945914.html

[3] 懒惰的肥兔Spring+MyBatis多数据源配置实现https://www.cnblogs.com/lzrabbit/p/3750803.html

[4] 沐浴星光mysql无法远程连接的解决方法https://www.cnblogs.com/star91/p/4980024.html

Spring实现多数据源配置的更多相关文章

  1. spring mysql多数据源配置

    spring mysql多数据源配置 @Configuration public class QuartzConfig { @Autowired private AutowireJobFactory ...

  2. Java spring mvc多数据源配置

    1.首先配置两个数据库<bean id="dataSourceA" class="org.apache.commons.dbcp.BasicDataSource&q ...

  3. Spring Boot多数据源配置(二)MongoDB

    在Spring Boot多数据源配置(一)durid.mysql.jpa 整合中已经讲过了Spring Boot如何配置mysql多数据源.本篇文章讲一下Spring Boot如何配置mongoDB多 ...

  4. JAVA spring hibernate 多数据源配置记录

    数据源配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...

  5. spring多个数据源配置

    sys.properties中的内容 jdbc.driverClassName=oracle.jdbc.driver.OracleDriver DB.url=jdbc\:oracle\:thin\:@ ...

  6. 三、Spring Boot 多数据源配置

    下面一个Java类是已经写好的根据配置文件动态创建多dataSource的代码,其原理也很简单,就是读取配置文件,根据配置文件中配置的数据源数量,动态创建dataSource并注册到Spring中. ...

  7. Spring Boot Druid数据源配置

    package com.hgvip.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.su ...

  8. spring boot多数据源配置(mysql,redis,mongodb)实战

    使用Spring Boot Starter提升效率 虽然不同的starter实现起来各有差异,但是他们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfi ...

  9. 21. Spring Boot Druid 数据源配置解析

    1.数据源配置属性类源码 package org.springframework.boot.autoconfigure.jdbc; @ConfigurationProperties( prefix = ...

随机推荐

  1. BZOJ3209: 花神的数论题(数位DP)

    题目: 3209: 花神的数论题 解析: 二进制的数位DP 因为\([1,n]\)中每一个数对应的二进制数是唯一的,我们枚举\(1\)的个数\(k\),计算有多少个数的二进制中有\(k\)个\(1\) ...

  2. English--不定式

    English|不定式 不定式短语在英语的写作中,比较常见,所以需要多留意.英语的学习需要多加阅读,在阅读中,看句子,学语法. 前言 目前所有的文章思想格式都是:知识+情感. 知识:对于所有的知识点的 ...

  3. 【转载】 Windows系统电脑通过设备管理器查看电脑配置信息

    在采购电脑或者使用电脑的过程中,有时候我们需要查看到电脑的所有设备硬件信息,此时就可以通过Windows系统自带的设备管理器界面来查看该电脑所有的设备配置信息,包括CPU型号频率.内存.硬盘型号以及容 ...

  4. 学习笔记之Coding / Design / Tool

    CODING 学习笔记之代码大全2 - 浩然119 - 博客园 https://www.cnblogs.com/pegasus923/p/5301123.html 学习笔记之编程珠玑 Programm ...

  5. 99.9%的Java程序员都说不清的问题:JVM中的对象内存布局?

    本文转载自公众号:石彬的架构笔记,阅读大约需要8分钟. 作者:李瑞杰 目前就职于阿里巴巴,资深 JVM 研究人员 在 Java 程序中,我们拥有多种新建对象的方式.除了最为常见的 new 语句之外,我 ...

  6. LINUX基础学习之基础命令(3)--2019-11-22

    1.命令行展开   ~ USERNAME:展开用户的主目录 [root@CentOS-7-43 ~]# ls ~roo 公共 模板 视频 图片 文档 下载 音乐 桌面 {}:可承载一个以逗号分隔的列表 ...

  7. 如何在macOS下调整磁盘分区大小?

    可以在“macOS”下利用磁盘工具并且不抹掉主分区的情况下,随意更改磁盘分区大小的方法.“OS X”经过几次大版本升级以后,也改名为“macOS”,而且系统自带的“磁盘工具”无论是功能和界面也有很大的 ...

  8. 常用Windows命令、常用 Cmd命令(补充)

    常用的Windows 命令使用能够提升工作效率以及快捷处理事项. 下面为平时常用的Windows 命令/cmd 命令. 一.以下命令无需打开cmd 窗口即可操作(输入完毕 打个 回车,即可执行). 1 ...

  9. 在github上优雅的搭建个人博客

    前言 啊啊啊---,经过差不多两天的持续摸索优化,个人博客算是初步完成了,现在自己看的效果还是非常不错的.这篇文章就是讲我怎么搭建一个这样的博客的.早在17年的时候就用hexo 结合github搭建过 ...

  10. Ruby——报错总结

    前言 记录ruby的一些报错 错误 Could not find a valid gem 'pumagem' (>= 0) in any repository ERROR: Could not ...