开发者社区 > 云原生 > 中间件 > 正文

Seata中在大批频繁操作相同对象时,记录的Select SQL出现 For Update怎么解决?

"Seata中在大批量频繁操作相同对象时,记录的Select SQL出现 For Update。
环境:Mysql 隔离级别(READ-COMMITTED)阿里云, Spring Boot , Seata 1.7.0
描述:两个微服务程序批处理读、写表时。 程序未对 SQL 进行 For Update;
但是阿里云以及(SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;)都出现Select语句 锁等待。 这个问题有遇到过吗?我用的是 @GlobalTransactional,没有用GlobalLocks。我本地跟了一下代码 只有 识别到 程序加的For UPDATE才会走 SelectForUpdateExecutor 。"

展开
收起
小易01 2023-12-05 08:27:42 198 0
3 条回答
写回答
取消 提交回答
  • 意中人就是我呀!

    AT依赖于for update,我理解这个场景的核心是热点数据竞争问题,根本不在for update。update的时候,seata会替你发一条select for update,建议去看官网原理。 for update阻塞只是表象,不是去解决for update的问题,而是共享数据高并发更新的问题。如果你要解决掉for update,就没有全局事物。此群整理至钉群“Seata(分布式事务)”。

    2023-12-05 21:19:24
    赞同 展开评论 打赏
  • 面对过去,不要迷离;面对未来,不必彷徨;活在今天,你只要把自己完全展示给别人看。

    这个问题可能是由于Seata在处理大批量频繁操作相同对象时,自动添加了For Update锁导致的。在MySQL的READ-COMMITTED隔离级别下,当一个事务对某个数据行加锁后,其他事务仍然可以对该数据行进行读操作,但是不能进行写操作,直到该事务提交或者回滚。

    为了解决这个问题,你可以尝试以下方法:

    1. 调整事务的隔离级别。将隔离级别从READ-COMMITTED降低到READ-UNCOMMITTED,这样可以避免Seata自动添加For Update锁。但请注意,这样做可能会导致脏读、不可重复读和幻读的问题。

    2. 使用Seata的GlobalLocks功能。通过在@GlobalTransactional注解中添加GlobalLocks参数,可以手动指定需要锁定的数据行。例如:

    @GlobalTransactional(name = "myTransaction", rollbackFor = Exception.class, globalLocks = {
        @GlobalLock(value = {"tableName"}, lockType = GlobalLockType.SELECT),
        @GlobalLock(value = {"tableName"}, lockType = GlobalLockType.UPDATE)
    })
    public void myMethod() {
        // your code here
    }
    
    1. 优化你的代码逻辑,尽量减少大批量频繁操作相同对象的情况。可以通过分批处理数据、使用缓存等方法来减少锁的竞争。
    2023-12-05 14:08:09
    赞同 展开评论 打赏
  • Seata 1.7.0 中出现的这个问题可能是由于 Spring Boot 和 Seata 集成时的某些默认行为导致的。在 Seata 中,当你使用 @GlobalTransactional 注解来声明一个全局事务时,Seata 会自动将读操作(SELECT)转换为带有 FOR UPDATE 子句的查询,以确保在分布式事务中的一致性。

    根据你的描述,尽管程序本身没有显式地对 SQL 进行 FOR UPDATE,但在运行过程中却观察到了这个现象。这可能是因为 Seata 在背后进行了这样的处理。如果两个微服务都在频繁地进行批处理读写,并且它们的操作涉及到相同的对象,那么在 READ-COMMITTED 隔离级别下,确实可能会发生锁等待的情况。

    对于这种情况,你可以考虑以下几种解决方案:

    1. 检查数据访问模式
      确保应用程序不是在并发地修改相同的数据记录。避免在同一时间内对同一记录执行多个更新操作。可以尝试优化业务逻辑,或者使用数据库层面的悲观锁或乐观锁来控制并发。

    2. 调整隔离级别
      考虑将数据库的隔离级别从 READ-COMMITTED 更改为 REPEATABLE READ 或 SERIALIZABLE。更高的隔离级别可以减少并发问题,但可能会增加锁定开销和降低性能。

    3. 减少事务范围
      尽量减小事务的范围,只包含那些真正需要在事务中执行的操作。这样可以减少锁冲突的机会。

    4. 优化Seata配置
      可能需要深入研究 Seata 的配置选项,看看是否有办法关闭 Seata 对 SELECT 语句的 FOR UPDATE 自动转换。这通常可以通过 Seata 的配置文件来进行设置。

    5. 使用 GlobalLocks
      虽然你提到当前未使用 GlobalLocks,但是在一些情况下,使用 Seata 提供的 GlobalLocks 功能可以帮助更好地管理分布式锁和事务一致性。

    2023-12-05 09:19:39
    赞同 展开评论 打赏

为企业提供高效、稳定、易扩展的中间件产品。

相关电子书

更多
SQL Server 2017 立即下载
GeoMesa on Spark SQL 立即下载
原生SQL on Hadoop引擎- Apache HAWQ 2.x最新技术解密malili 立即下载