Spring实现多数据源配置
一、前言
对于小型项目,服务器与数据库是可以在同一台机子上的,但随着业务的庞大与负责,数据库和服务器就会分离开来。同时随着数据量的增大,数据库也要分开部署到多台机子上。
二、Spring配置文件修改
在理论学习与实践的差距:框架开源与不可逆的趋势[1]一文中曾经介绍过SSM框架,当时的框架采取单一数据源的配置,同时数据库的地址也没有写在properties文件中。但实际开发中,如果需要更换服务器的地址,修改XML文件会比较麻烦,一般都是提倡用properties文件,部署到正式服务器上,就只需要修改properties文件即可。
1、applicationContext.properties文件:
#Mysql
jdbc.mysql.driver=com.mysql.jdbc.Driver
jdbc.mysql.url=jdbc:mysql://localhost:3306/db_test
jdbc.mysql.username=root
jdbc.mysql.password=123456
#Mysql2
jdbc.mysql.driver2=com.mysql.jdbc.Driver
jdbc.mysql.url2=jdbc:mysql://192.168.1.8:3306/db_test
jdbc.mysql.username2=root
jdbc.mysql.password2=123456
2、动态数据源配置 [2]
package com.test.utils;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource{
public static final String mySqlDataSource = "mySqlDataSource";
public static final String mySqlDataSource2 = "mySqlDataSource2";
//本地线程,获取当前正在执行的currentThread
public 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();
}
@Override
protected Object determineCurrentLookupKey() {
// TODO Auto-generated method stub
return getCustomerType();
}
}
3、applicationContext.xml文件:
添加了对配置文件applicationContext.properties的读取,同时在dynamicDataSource中添加两个或以上的数据源,并定义一个默认的数据源
<?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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 自动扫描 -->
<context:component-scan base-package="com.test.dao" />
<context:component-scan base-package="com.test.service" />
<!-- 读取配置文件 -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:applicationContext.properties</value>
<!-- <value>classpath:config.properties</value> -->
</list>
</property>
<property name="ignoreUnresolvablePlaceholders" value="true"/>
</bean>
<!-- 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.mysql.driver}"/>
<property name="url" value="${jdbc.mysql.url}"/>
<property name="username" value="${jdbc.mysql.username}"/>
<property name="password" value="${jdbc.mysql.password}"/>
</bean>
<bean id="dataSource2"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.mysql.driver2}"/>
<property name="url" value="${jdbc.mysql.url2}"/>
<property name="username" value="${jdbc.mysql.username2}"/>
<property name="password" value="${jdbc.mysql.password2}"/>
</bean>
<!-- 动态数据源 -->
<bean id="dynamicDataSource" class="com.test.utils.DynamicDataSource"><!--注意: 这里写选择数据源的类地址 下面跟着给出 -->
<property name="targetDataSources">
<map>
<entry key="mySqlDataSource" value-ref="dataSource" />
<entry key="mySqlDataSource2" value-ref="dataSource2" />
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSource" /><!-- 设置默认为此mySqlDataSource数据源 -->
</bean>
<!-- 配置mybatis的sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dynamicDataSource" />
<!-- 自动扫描mappers.xml文件 -->
<property name="mapperLocations" value="classpath:com/test/mappers/*.xml"></property>
<!-- mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.test.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 配置事务通知属性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 定义事务传播属性 -->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="new*" propagation="REQUIRED" />
<tx:method name="set*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="change*" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="load*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" propagation="REQUIRED" read-only="false" />
</tx:attributes>
</tx:advice>
<!-- 配置事务切面 -->
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* com.test.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
</beans>
三、实际执行代码并动态切换数据源
1、前台jsp页面:
这里简单用a标签同步请求获取数据
<a href="${pageContext.request.contextPath }/blog/searchAllBlog.do">获取列表</a>
<table>
<c:choose>
<c:when test="${blogList==null }">
<tr>
<td>暂无列表</td>
</tr>
</c:when>
<c:otherwise>
<tr>
<th> </th>
<th>标题</th>
<th>内容</th>
</tr>
<c:forEach var="blog" items="${blogList }" varStatus="status">
<tr>
<td>${status.index+1 }</td>
<td>${blog.title }</td>
<td>${blog.content }</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</table>
<hr>
<a href="${pageContext.request.contextPath }/blog/searchAllBlog2.do">获取列表2</a>
<table>
<c:choose>
<c:when test="${blogList2==null }">
<tr>
<td>暂无列表</td>
</tr>
</c:when>
<c:otherwise>
<tr>
<th> </th>
<th>标题</th>
<th>内容</th>
</tr>
<c:forEach var="blog" items="${blogList2 }" varStatus="status">
<tr>
<td>${status.index+1 }</td>
<td>${blog.title }</td>
<td>${blog.content }</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</table>
2、Controller层
@RequestMapping("/searchAllBlog")
public String searchAllBlog(HttpServletRequest request){
List<Blog> blogList=blogService.searchAllBlog();
request.setAttribute("blogList", blogList);
return "add";
}
@RequestMapping("/searchAllBlog2")
public String searchAllBlog2(HttpServletRequest request){
List<Blog> blogList=blogService.searchAllBlog2();
request.setAttribute("blogList2", blogList);
return "add";
}
3、Service层
public interface BlogService {
public int add(Blog blog);
public List<Blog> searchAllBlog();
public List<Blog> searchAllBlog2();
}
对应的实现类:[2]
@Override
public List<Blog> searchAllBlog() {
// TODO Auto-generated method stub
return blogDao.searchAllBlog();
}
@Override
public List<Blog> searchAllBlog2() {
// TODO Auto-generated method stub
List<Blog> list = null;
DynamicDataSource.clearCustomerType();//重点: 实际操作证明,切换的时候最好清空一下
DynamicDataSource.setCustomerType(DynamicDataSource.mySqlDataSource2);
list = blogDao.searchAllBlog();
DynamicDataSource.clearCustomerType();//
DynamicDataSource.setCustomerType(DynamicDataSource.mySqlDataSource);//切换回主数据源
return list;
}
当然也可以用其他方式来实现数据源的切换,详情请参看Spring+MyBatis多数据源配置实现[3]
四、运行程序
运行程序后,点击获取获取列表2,会发现不允许连接服务器。原因是由于Mysql默认只能本机访问,不能够远程连接。这里需要对MySql进行开启权限操作。[4]
grant all on 数据库名.* to ‘数据库账户名’@’%’ identified by ‘密码’ with grant option;
回车
flush privileges;
回车
注意:上面的单引号不能省,数据库名.* 表示要开放的数据库下所有表,如果该连接的所有数据库都要开放,可以用 *.* 代替。
‘数据库账户名’@’%’ 这里表示要开放的账户,百分号表示在任何主机都允许访问。
如果以上两步均显示 “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实现多数据源配置的更多相关文章
- spring mysql多数据源配置
spring mysql多数据源配置 @Configuration public class QuartzConfig { @Autowired private AutowireJobFactory ...
- Java spring mvc多数据源配置
1.首先配置两个数据库<bean id="dataSourceA" class="org.apache.commons.dbcp.BasicDataSource&q ...
- Spring Boot多数据源配置(二)MongoDB
在Spring Boot多数据源配置(一)durid.mysql.jpa 整合中已经讲过了Spring Boot如何配置mysql多数据源.本篇文章讲一下Spring Boot如何配置mongoDB多 ...
- JAVA spring hibernate 多数据源配置记录
数据源配置 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http:// ...
- spring多个数据源配置
sys.properties中的内容 jdbc.driverClassName=oracle.jdbc.driver.OracleDriver DB.url=jdbc\:oracle\:thin\:@ ...
- 三、Spring Boot 多数据源配置
下面一个Java类是已经写好的根据配置文件动态创建多dataSource的代码,其原理也很简单,就是读取配置文件,根据配置文件中配置的数据源数量,动态创建dataSource并注册到Spring中. ...
- Spring Boot Druid数据源配置
package com.hgvip.config; import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.su ...
- spring boot多数据源配置(mysql,redis,mongodb)实战
使用Spring Boot Starter提升效率 虽然不同的starter实现起来各有差异,但是他们基本上都会使用到两个相同的内容:ConfigurationProperties和AutoConfi ...
- 21. Spring Boot Druid 数据源配置解析
1.数据源配置属性类源码 package org.springframework.boot.autoconfigure.jdbc; @ConfigurationProperties( prefix = ...
随机推荐
- 2019 哔哩哔哩java面试笔试题 (含面试题解析)
本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.哔哩哔哩等公司offer,岗位是Java后端开发,因为发展原因最终选择去了哔哩哔哩,入职一年时间了,也成为了面 ...
- maven项目整合SSM配置log4j, 实现控制台打印SQL语句
在原有项目正常启动的情况下, 实现在控制台打印mapper包下SQL语句. 1.在pom.xml配置文件中添加两个依赖(缺一不可) <!--日志包--> <dependency> ...
- 85.webpack的安装失败至成功
webpack怎么安装 1.安装node.js; 2.安装webpack: npm install webpack --save-dev : 注意:webpack 4x以上,webpack将命 ...
- HTML 初始
HTML(Hyper Text Markup Language的缩写)中文译为“超文本标记语言”,主要是通过HTML标签对网页中的文本.图片.声音等内容进行描述. 一.HTML 骨架结构 每种语言都有 ...
- 补充1:IDA的脚本IDC语言
1.IDA脚本的打开与使用: IDA脚本两种语言:IDC(IDC,本地脚本语言)和Python 2.IDC语言介绍 1.IDC变量:IDC是一种松散的语言,没有明确的类型.使用3中数据类型,整数(ID ...
- Kubernetes学习之基础概念
本文章目录 kubernetes特性 kubernetes集群架构与组件 一.kubernetes集群架构 二.集群组件 三.ubernetes集群术语 深入理解Pod对象 一.Pod容器分类 基础容 ...
- C# 7可以在.NET Framework 4上运行吗?
https://stackoverflow.com/questions/42482520/does-c-sharp-7-0-work-for-net-4-5 To sum up: All of C# ...
- pandas 之 数据合并
import numpy as np import pandas as pd Data contained in pandas objects can be combined together in ...
- 【转载】【凯子哥带你学Framework】Activity启动过程全解析
It's right time to learn Android's Framework ! 前言 一个App是怎么启动起来的? App的程序入口到底是哪里? Launcher到底是什么神奇的东西? ...
- 无法打开jetbrains官网
找到下面hosts文件,用记事本打开,删除关于jetbrain的文字 需要管理员权限才能操作这个文档: 先后输入cmd和 notepad hosts 删除掉关于jetbrains的模块,再次访问htt ...