mysql数据库更新报错,提示readonly,问题分析

在Spring+MyBatis项目中,使用多数据源配置时遇到MySQL更新报只读错误。排查过程包括:1.检查数据库状态,2.确认主从切换逻辑,3.分析代码执行流程。问题出在事务管理器配置错误,导致查询和更新操作使用了不同数据源的连接,更新操作误用从库连接。解决方案是确保TransactionManager与对应数据源绑定,并注意事务内的查询操作。
摘要由CSDN通过智能技术生成

项目背景:spring+mybatis,多数据源,T(T1,T2),P(P1,P2),R(R1,R2),其中1表示主库,2表示从库,使用Spring的AbstractRoutingDataSource在主从之间进行切换
最近在查看请求日志时,发现对数据库P1的一个update操作,提示数据库是只读的,错误提示: Error updating database. Cause: java.sql.SQLException: The MySQL server is running with the –read-only option so it cannot execute this statement.
遇到这类问题,首先会第一时间想到,是不是db出问题了,于是赶紧找到dba确认,结果dba反馈说P1库一切正常,那么会不会是主从路由的时候切换到从库上面去了呢,于是赶紧接着去查日志,发现路由日志显示是master,但为了保险起见,还是请求了dba查看数据库log,看看update的请求究竟是打到哪里了,结果一查,还真是打到从库上了,既然问题已经定位了,那只能接着撸代码了,业务关键代码如下:

@Resource(name = "t_transactionManager")
private DataSourceTransactionManager transactionManager;


TransactionDefinition def = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus   transactionStatus = transactionManager.getTransaction(def);
Pay pay = payService.queryPayInSlave(id);
…………………………………逻辑处理…………………………
payService.updatePay(pay);
transactionManager.commit(transactionStatus);

我们来看下mybatis一次数据库操作是如何执行的,执行堆栈如下:
这里写图片描述
我们看到堆栈的最上层,程序开始获取Connection,这也是我们关注的重点,请求既然到从库P2了,那么获取到的连接肯定是从库P2的连接。获取Connection的源码如下:

public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        Assert.notNull(dataSource, "No DataSource specified");

        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
            conHolder.requested();
            if (!conHolder.hasConnection()) {
                logger.debug("Fetching resumed JDBC Connection from DataSource");
                conHolder.setConnection(dataSource.getConnection());
            }
            return conHolder.getConnection();
        }
        // Else we either got no holder or an empty thread-bound holder here.

        logger.debug("Fetching JDBC Connection from DataSource");
        Connection con = dataSource.getConnection();

        if<
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值