Spring Boot 配置JPA数据库主从读写分离失败及解决办法

embedded/2025/2/13 0:13:02/

因为是老项目, Spring Boot 是1.4, 使用 AbstractRoutingDataSource 来做主从切换, 配置切面类在进入事务时切换成主库, 但实际运行起来却失败, 写操作路由到了从库

查了很多文章, 试了很多方法都无效, 包括修改注解 @Transactional 的 propagation 属性, 清空主从标记等等

打断点跟踪代码发现, 进入事务时并没有触发获取数据库连接, 而是事务里第一个查询触发了数据库连接的建立, 选择了从库, 后面的所有操作都不会触发数据源选择

后来查到这篇文章

JPA hibernate AbstractRoutingDataSource 在同一方法内使用不同数据源失败_user springboo jpa controller abstractroutingdatas-CSDN博客

通过这篇文章又找到下面的文章
Spring Data JPA 原理与实战第十一天 Session相关、CompletableFuture、LazyInitializationException_org.hibernate.resource.jdbc.spi.physicalconnection-CSDN博客
 

了解到JPA是有会话保持的, 一旦数据库链接创建在会话期内不会改变, 要想在进入事务时就选择数据源为主库, 需要修改 hibernate.connection.handling_mode 调整处理物理连接的模式。

因为我 Spring Boot  是1.4, 匹配的 hibernate 版本是5.0, 所以是把 release_mode 设置为AFTER_TRANSACTION

java">@Configuration
public class JpaConfig {@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory(@Qualifier("routingDataSource") DataSource dataSource) {LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();em.setDataSource(dataSource);em.setPackagesToScan("com.my.domain");HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();em.setJpaVendorAdapter(vendorAdapter);// 设置 JPA 属性Properties properties = new Properties();properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");properties.setProperty("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");properties.setProperty("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");properties.setProperty("hibernate.connection.release_mode", "AFTER_TRANSACTION");em.setJpaProperties(properties);return em;}
}

部署后又出现了新问题, 进入事务之前如果有查询操作, 还是会路由到从库, 进入事务时, 不会再触发重新获取数据源, 原因出在这部分代码 

java">public class LogicalConnectionManagedImpl extends AbstractLogicalConnectionImplementor {private Connection acquireConnectionIfNeeded() {if ( physicalConnection == null ) {// todo : is this the right place for these observer calls?observer.jdbcConnectionAcquisitionStart();try {physicalConnection = jdbcConnectionAccess.obtainConnection();}catch (SQLException e) {throw sqlExceptionHelper.convert( e, "Unable to acquire JDBC Connection" );}finally {observer.jdbcConnectionAcquisitionEnd( physicalConnection );}}return physicalConnection;}
}

如果之前已经获取了链接, jdbcConnectionAccess.obtainConnection() 会直接返回之前创建好的链接进行复用, 解决办法是进入事务之前不要有数据库查询操作, 把查询放到事务里


http://www.ppmy.cn/embedded/161723.html

相关文章

从小白开始的动态规划

一、动态规划的核心思想 动态规划(DP)通过拆分问题记忆化计算解决复杂问题,核心步骤为: 定义状态:用变量(如dp[i])表示子问题的解 状态转移方程:建立子问题之间的关系式 初始化&a…

ASP.NET Core SignalR的协议协商

SignalR支持多种服务器推送方式:Websocket、Server-Sent Events、长轮询。默认按顺序尝试。F12查看协商过程。websocket和HTTP是不同的协议,为什么能用同一个端口。在【开发人员工具】的【网络】页签中看WebSocket通信过程。 协议协商问题 集群中协议协…

关于SoC产品介绍:ICNM8001

这个是一款关于QHD显示器,主控芯片scaler IC。 功能:支持2路HDMI2.0接收机 支持HDCP1.4和HDCP2.22;支持HDCP1.4和HDCP2.2。 分辨率:2560*1440 刷新率:75Hz HDR:HDR10 封装:QFP216 接口&#xf…

如何在WPF中实现软件内嵌效果

1.创建Process进程,设置运行程序文件路径 Process proc new Process(); proc.StartInfo.FileName "C:\Users\hdevelop.exe"; proc.Start(); proc.WaitForInputIdle(); 2.根据创建的进程获取窗口句柄 IntPtr hWnd proc.MainWindowHandle; 3.开启线程…

antd-react日期组件disabledDate不可选择的日期 (置灰)属性

需求:原定结项时间表单里回显为2025-02-06,延期时间的选择范围要设置从2025-02-07开始选择包括2.7号的; 2.7号之前的置灰,不可选择 PC端部分代码: // react的函数组件写法 const disabledDate function (current) {console.log(c…

CSS 小技巧 —— CSS 实现 Tooltip 功能-鼠标 hover 之后出现弹层

CSS 小技巧 —— CSS 实现 Tooltip 功能-鼠标 hover 之后出现弹层 1. 两个元素实现 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>纯 CSS 实现 Tooltip 功能-鼠标 hover 之后出现弹层</titl…

npm运行Vue项目报错 error:0308010c:digital envelope routines::unsupported

大家好&#xff0c;我是 程序员码递夫。 问题 VSCode 运行Vue项目&#xff0c;提示错误&#xff1a; building 2/2 modules 0 activeError: error:0308010c:digital envelope routines::unsupported 解决方法 原因是 npm 高版本(大于17)&#xff0c;对ssl的处理做了改进&…

Windows命令行学习(和Linux命令比对记忆

本文侧重于记忆Windows简单命令&#xff0c;所以相关Linux命令演示较少&#xff0c;学习Linux命令详见Linux系统专栏&#xff1b;本文示例版本为Windows 10与Linux 7。 目录 一、文件与目录操作 1、列出当前目录下文件及子目录信息 Windows&#xff1a;dir Linux&#xff1…