baomidou / dynamic-datasource

dynamic datasource for springboot 多数据源 动态数据源 主从分离 读写分离 分布式事务
https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611
Apache License 2.0
4.74k stars 1.19k forks source link

afterCommit 再触发事务会死循环 #620

Closed sunyj-003 closed 5 months ago

sunyj-003 commented 10 months ago

Please fill it out carefully, or it will be closed. 请认真填写,不然会直接关闭。

Enviroment

JDK Version(required): 17

SpringBoot Version(required): 2.7.18

dynamic-datasource-spring-boot-starter Version(required):4.3.0

druid Version(optional):

Describe what happened

使用@DSTransactional发生死循环,代码如下

image
package com.baomidou.samples.druid.test;

import com.baomidou.samples.druid.DruidApplication;
import com.baomidou.samples.druid.service.impl.TxService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

/**
 * @author sunyj
 * @date 2024/1/14 20:42
 */
@SpringBootTest(classes = DruidApplication.class)
public class TxTest {
    @Resource
    private TxService txService;

    @Test
    public void testTx() {
        txService.tx();
    }
}

package com.baomidou.samples.druid.service.impl;

import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.tx.TransactionContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionSynchronization;

import javax.annotation.Resource;

@Service
public class TxService {

    @Lazy
    @Resource
    private TxService txService;

    @DSTransactional
    public void tx() {
        System.out.println("method tx");

        TransactionContext.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                txService.txAfterCommit();
            }
        });
    }

    @DSTransactional
    public void txAfterCommit() {
        System.out.println("method txAfterCommit");
    }
}

使用 @Transactional , afterCommit只会调用一次, 代码如下

image
package com.baomidou.samples.druid.test;

import com.baomidou.samples.druid.DruidApplication;
import com.baomidou.samples.druid.service.impl.TxService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;

/**
 * @author sunyj
 * @date 2024/1/14 20:42
 */
@SpringBootTest(classes = DruidApplication.class)
public class TxTest {
    @Resource
    private TxService txService;

    @Test
    public void testTx() {
        txService.tx();
    }
}

package com.baomidou.samples.druid.service.impl;

import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.annotation.Resource;

@Service
public class TxService {

    @Lazy
    @Resource
    private TxService txService;

    @Transactional
    public void tx() {
        System.out.println("method tx");

        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                txService.txAfterCommit();
            }
        });
    }

    @Transactional
    public void txAfterCommit() {
        System.out.println("method txAfterCommit");
    }
}

Expected Result: 和Spring的一致

Actual Result: 死循环

If there is an exception,or aop invalid,please attach the exception trace:

Steps to reproduce

ZPZP1 commented 10 months ago

现在的事务模板同一线程事务传播会在finally里invokeAfterCompletion清除此线程同步属性,确实可能存在aftercommit再套事务出现这个情况 @huayanYu 指派我吧,晚上或者明天修一下

huayanYu commented 5 months ago

4.3.1