V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
NoKey
V2EX  ›  程序员

Java 中异步执行,事务只能手动提交么

  •  
  •   NoKey · 2023-01-05 22:17:17 +08:00 · 1809 次点击
    这是一个创建于 674 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如我需要执行很多任务,执行任务比较耗时,所以才去了异步执行

    我的调度方法把要执行的任务拿到(比如在方法 A 中)

    然后通过异步方法去执行(方法 B 中)

    我需要修改这个任务状态为执行中

    这个时候,有个事务问题,就是,我修改任务状态是在 A 中,不能在 B 中,因为 B 有可能会执行很久才完成,才进行事

    务提交,外部看着任务的状态会很长一段时间没有状态

    所以,我在 A 中修改任务状态,然后异步执行 B

    但是,如果 B 执行的足够快,有可能我的 A 还没有提交,B 查询得到的状态就是空的,这个时候,A 提交了,然后 B 提交

    了,那么 B 提交的数据里,状态就是空的,把 A 提交的任务状态覆盖了

    这个场景可能没那么恰当,但是应该能表达我想说的意思了

    就是这种有异步执行的场景下,为了确保前一个事务确实提交了,再执行异步方法,只有手动提交事务么?有没有

    更优雅的方法呢,谢谢~

    15 条回复    2023-01-06 10:48:37 +08:00
    t202201
        1
    t202201  
       2023-01-05 22:21:15 +08:00 via iPhone
    没看明白,需要异步执行的到底是什么?

    A 、B 和异步的任务,三者是什么关系?
    NoKey
        2
    NoKey  
    OP
       2023-01-05 22:24:50 +08:00
    @t202201 实际意思就是,A 要写数据,B 要读写数据,A ,B 各在一个事务里面,如何确保 A 的事务先提交,然后 B 就能够读取到正确的数据。目前采取的是手动提交事务的方式,想知道有没更好的办法
    t202201
        3
    t202201  
       2023-01-05 22:31:04 +08:00
    @NoKey 要想保证 B 正确读到数据,直接加锁啊
    Avn
        4
    Avn  
       2023-01-05 22:32:30 +08:00
    既不在 A 的事务中进行、也不在 B 的事务中进行,而是在 B 前面再开个独立的小事务,把任务状态修改掉。
    NoKey
        5
    NoKey  
    OP
       2023-01-05 22:38:53 +08:00
    @Avn 我理解一下,是不是说,在 A 和 B 之间,新开一个事务,把事情给干了,这个事务返回的时候,就提交了,然后执行 B ?
    Avn
        6
    Avn  
       2023-01-05 22:45:37 +08:00
    @NoKey 对的。记录状态或日志的操作,不需要放在主事务里面。因为即使主事务发生异常事务回滚,大部分情况下记录状态或日志的操作也不需要、不能回滚,而是要被准确地记录下来,所以可以用独立的小事务来处理这些操作。
    imv2er
        7
    imv2er  
       2023-01-05 22:56:22 +08:00
    countdownlatch 解忧愁。A 的事务提交完 就 countdown b 读代码开始运行
    kwh
        8
    kwh  
       2023-01-06 02:15:43 +08:00
    有 aop 啊,spring 事务是通过 autoproxy 方式的 aop 进行事务开启和提交的。
    只需要在事务代理的外面再 aop 一下,不就能在事务提交后执行吗?
    Ayanokouji
        9
    Ayanokouji  
       2023-01-06 09:09:28 +08:00
    spring TransactionalEventListener
    vishun
        10
    vishun  
       2023-01-06 09:31:36 +08:00   ❤️ 1
    springboot 自带事务提交后再执行的方法:
    ```
    //执行 A 事务
    TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronization() {
    @Override
    public void afterCommit() {
    B 相关代码 //这里会在 A 事务提交后,执行 B 事务
    }
    }
    );
    ```
    HarrisonLee
        11
    HarrisonLee  
       2023-01-06 09:46:49 +08:00
    楼上正解,正在使用这种方案
    NoKey
        12
    NoKey  
    OP
       2023-01-06 10:26:48 +08:00
    @Avn 谢谢,是个好方法
    NoKey
        13
    NoKey  
    OP
       2023-01-06 10:28:16 +08:00
    @vishun 谢谢,我看看这种方式
    cryboy007
        14
    cryboy007  
       2023-01-06 10:30:47 +08:00
    用事务提交事件即可
    NoKey
        15
    NoKey  
    OP
       2023-01-06 10:48:37 +08:00
    @cryboy007 谢谢,这种方式也可以,但是这么写的话,会多出不少代码😂
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2701 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 11:10 · PVG 19:10 · LAX 03:10 · JFK 06:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.