一个Web项目实现多个数据库存储数据并相互切换
1、使用场景
多数据源使用场景一般为:
- 主从数据库切换
- 读写分离
- 兼容旧库
2、具体实现
实现原理
Spring2.x的版本中采用Proxy模式,就是在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文,由虚拟的DynamicDataSource根据Client提供的上下文来实现数据源的选择。
具体的实现是创建一个名为DynamicDataSource的类仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey(),该方法返回需要使用的DataSource的key值,然后根据这个key从resolvedDataSources这个map里取出对应的DataSource,如果找不到则用默认的resolvedDefaultDataSource。
具体实现过程
1.修改jdbcConfig.properties数据源配置文件为一下内容(具体数据源可自行修改)
# A 数据库源A
jdbc.a.driver = com.mysql.cj.jdbc.Driver
jdbc.a.url = jdbc:mysql://localhost:3306/test1?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
jdbc.a.username = root
jdbc.a.password = 123456 # B 数据库源B
jdbc.b.driver = com.mysql.cj.jdbc.Driver
jdbc.b.url = jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
jdbc.b.username = root
jdbc.b.password = 123456
2.修改applicationContext.xml配置文件,需要配置多个数据源,修改后配置如下
<!-- 引入jdbc配置文件 -->
<context:property-placeholder location="classpath:jdbcConfig.properties"></context:property-placeholder>
<!-- spring 整合 mybatis-->
<!-- 1.配置数据源 C3P0 1 -->
<bean id="dataSourceTargetA" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.a.driver}" />
<property name="jdbcUrl" value="${jdbc.a.url}" />
<property name="user" value="${jdbc.a.username}" />
<property name="password" value="${jdbc.a.password}" />
</bean>
<!-- 配置数据源 C3P0 2 -->
<bean id="dataSourceTargetB" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="${jdbc.b.driver}" />
<property name="jdbcUrl" value="${jdbc.b.url}" />
<property name="user" value="${jdbc.b.username}" />
<property name="password" value="${jdbc.b.password}" />
</bean>
<!-- 动态数据源 -->
<bean id="dataSource" class="com.hk.handler.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref="dataSourceTargetA" key="dataSourceTargetA"></entry>
<entry value-ref="dataSourceTargetB" key="dataSourceTargetB"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceTargetA"></property> </bean>
<!-- 2.配置SqlSessionFactory工厂 -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 注入数据源 -->
<property name="dataSource" ref="dataSource" />
<!-- 实体类起别名 -->
<property name="typeAliasesPackage" value="com.hk.model"></property>
<!-- 指定mapper接口所对应的xml-->
<property name="mapperLocations" value="classpath:com/hk/mapper/*.xml"></property>
<!-- 指定Mybatis的核心配置文件 -->
<property name="configLocation" value="classpath:mybatis.xml"></property>
</bean>
<!-- 3.配置接口AccountDao所在的包 映射扫描配置类 mvc配置 -->
<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 接口所在的包 -->
<property name="basePackage" value="com.hk.mapper" />
<!-- 扫描工厂并注入sqlSessionFactoryBeanName -->
<property name="sqlSessionFactoryBeanName" value="sessionFactory" />
</bean>
<!-- 配置spring声明式事务管理 -->
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 传入连接池对象 -->
<property name="dataSource" ref="dataSource" />
</bean>
3.创建动态数据源管理类
DynamicDataSource类继承AbstractRoutingDataSource,实现determineCurrentLookupKey()方法。
/**
* @Author: aerfazhe
* @Date: 2021/6/26 10:00
* @Statement: 数据源切换类
*/
public class CustomerContextHolder { public static final String DATA_SOURCE_DEFAULT = "dataSourceTargetA"; public static final String DATA_SOURCE_B = "dataSourceTargetB"; private 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();
} }
5.使用多数据源代码
以Controller层代码为演示,需要添加信息到B数据源,完成后切换到A数据源进行查询,具体代码如下
@PostMapping("/save")
public String save(User user) {
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_B);
int save = iuserService.save(user);
CustomerContextHolder.setCustomerType(CustomerContextHolder.DATA_SOURCE_DEFAULT);
if (save == 1) {
return "success";
}
return "error";
}
@GetMapping("/findAll")
@ResponseBody
public Map<String,Object> findAll() {
List<User> userList = iuserService.findAll();
Map<String,Object> map = new HashMap<>();
map.put("status",0);
map.put("msg","success");
map.put("list",userList);
return map;
}
先从数据库B中的表进行添加数据,添加完成后,会切换到默认的数据库A,然后再从数据库A中的表查询数据,这样就达到了在一个Web项目中,根据不用的模块和业务需求,实现多个数据库存储数据和它们之间的切换了。
如有任何问题,欢迎评论区留言,希望可以帮助到大家。
学习参考至:https://www.cnblogs.com/zhaosq/p/10616244.html
一个Web项目实现多个数据库存储数据并相互切换的更多相关文章
- 一个Web项目中实现多个数据库存储数据并相互切换用过吗?
最近公司一个项目需要连接多个数据库(A和B)操作,根据不同的业务模块查询不同的数据库,因此需要改造下之前的spring-mybatis.xml配置文件以及jdbc.properties配置文件,项目后 ...
- 转 一个web项目web.xml的配置中<context-param>配置作用
一个web项目web.xml的配置中<context-param>配置作用 <context-param>的作用:web.xml的配置中<context-param& ...
- 使用Maven+ssm框架搭建一个web项目
1,前期准备:Eclipse(Mars.2 Release (4.5.2)).jdk1.7.tomcat7.maven3.2.1 2.使用eclipse中的maven新建一个web项目 点击next: ...
- 一个web项目web.xml的配置中<context-param>配置作用
<context-param>的作用: web.xml的配置中<context-param>配置作用 1. 启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置文件 ...
- 一个web项目中web.xml<context-param>的作用
转 <context-param>的作用:web.xml的配置中<context-param>配置作用1. 启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置 ...
- eclipes创建一个web项目web.xml不能自动更新的原因(web.xml和@WebServlet的作用)
在eclipse中创建一个Web项目的时候,虽然有web.xml生成,但是再添加Servlet类文件的时候总是看不见web.xml的更新,所以异常的郁闷!上网查了查,原来我们在创建Web项目的时候,会 ...
- Eclipse的maven构建一个web项目,以构建SpringMVC项目为例
http://www.cnblogs.com/javaTest/archive/2012/04/28/2589574.html springmvc demo实例教程源代码下载:http://zuida ...
- Web —— java web 项目 Tomcat 的配置 与 第一个web 项目创建
目录: 0.前言 1.Tomcat的配置 2.第一个Web 项目 0.前言 刚刚开始接触web开发,了解的也不多,在这里记录一下我的第一个web项目启动的过程.网上教程很多,使用的java IDE 好 ...
- 一个web项目在myeclipse中add deployment时无法被识别出来的原因
当我们一个web项目,在myeclipse中,add deployment时,可能发现,根本无法被识别成web项目,可能的原因有: 1. 项目的properties ->Myeclipse ...
- 如何在Linux中tomcat下运行一个web项目
如何在Linux中tomcat下运行一个web项目 然后启动Tomcat项目.运行的运行后会自动将war包解压. 如果页面报404,那么请查看tomcat日志文件,它一定是报错了....
随机推荐
- 利用机器人类Robot写出自动登录QQ的小代码
最近写了一个小代码控制鼠标键盘使他自己登录QQ,下面给大家分享下这一小代码. 这段小程序是用Java里的Robot类实现的,控制鼠标键盘的一个机器人类. 我们想要实现自动登录QQ首先得想要做到这一步需 ...
- Python 列表定义
列表定义 由一系列按特定排序排列的元素组成,各元素之间无任何关系 用方括号[]来表示列表,并用逗号分隔其中的元素 访问列表元素 列表是有序集合,访问列表元素时,只需将该元素的位置或索引告知python ...
- Sementic Kernel 案例之网梯科技在线教育
2023年4月25日,微软公布了2023年第一季度财报,营收528亿美元, 微软CEO纳德称,「世界上最先进的AI模型与世界上最通用的用户界面--自然语言--相结合,开创了一个新的计算时代.」该公司有 ...
- 【问题排查篇】一次业务问题对 ES 的 cardinality 原理探究
作者:京东科技 王长春 业务问题 小编工作中负责业务的一个服务端系统,使用了 Elasticsearch 服务做数据存储,业务运营人员反馈,用户在使用该产品时发现,用户后台统计的订单笔数和导出的订单笔 ...
- 自动化运维工具-Ansible PlayBook
自动化运维工具-Ansible PlayBook PlayBook基本概念 PlayBook的组成 PlayBook即"剧本","兵书"之意,PlayBook是 ...
- ad-hoc实战
ad-hoc实战 要求:利用Ansible搭建一个简易的作业网站,web端文件上传目录共享至nfs端,nfs的数据同步至backup 环境准备 主机名 主机角色 外网IP 内网IP m01 ansib ...
- 民谣女神唱流行,基于AI人工智能so-vits库训练自己的音色模型(叶蓓/Python3.10)
流行天后孙燕姿的音色固然是极好的,但是目前全网都是她的声音复刻,听多了难免会有些审美疲劳,在网络上检索了一圈,还没有发现民谣歌手的音色模型,人就是这样,得不到的永远在骚动,本次我们自己构建训练集,来打 ...
- 2023-03-29:如何高效计算三条线路选择方案?小A的旅行线路规划问题
2023-03-29:第一行有一个正整数n(3<=n<=100000),代表小A拟定的路线数量 第二行有n个正整数,第i个代表第i条路线的起始日期 第三行有n个正整数,第i个代表第i条路线 ...
- 2022-07-10:以下go语言代码输出什么?A:A,B;B:A,C:A,fatal error;D:fatal error... func main() { var m sync.Mute
2022-07-10:以下go语言代码输出什么?A:A,B:B:A,C:A,fatal error:D:fatal error- func main() { var m sync.Mutex fmt. ...
- 小知识:设置archive_lag_target参数强制日志切换
为客户测试一个ADG场景问题,发现测试环境的日志切换频率过低,总是需要定期手工切换,这非常影响测试心情. 实际上,可以设置archive_lag_target参数强制日志切换. 比如设置: alter ...