乐趣区

关于java:Spring-双层事务我抛出的异常去哪了

作者:AMOS0626\
起源:https://my.oschina.net/AmosWa…

零碎 A 调用零碎 B 执行数据同步,零碎 B 返回了谬误提醒,零碎 A 须要将前边保留的回滚掉,同时把错误信息向上抛。

大抵代码如下

@Service("noteService")
public class NoteServiceImpl implements NoteService {

    @Resource
    private SearchService searchService;


    @Transactional(rollbackFor = Throwable.class)
    @Override
    public CommonResponse<NoteEntity> save(NoteEntity note) {
        // 一系列 DB 操作

        try {searchService.sync(note);
        } catch (Exception e) {e.printStackTrace();
        }

        return CommonResponse.success(entity);
    }

}

@Service("searchService")
public class SearchServiceImpl implements SearchService {@Transactional(rollbackFor = Throwable.class)
    @Override
    public void sync(NoteEntity note) {
        // 一系列 DB 操作

        throw new RuntimeException("同步异样! [XXX]");
    }

}

@SpringBootTest
public class NoteTests {

    @Resource
    private NoteService noteService;

    @Test
    public void saveNote() {NoteEntity entity = new NoteEntity();
        entity.setTitle("念奴娇赤壁怀古");
        entity.setContent("大江东去,浪淘尽,千古风流人物。故垒西边,人道是:三国周郎赤壁。。。");
        entity.setTags("苏轼, 宋代");
        entity.setCategory("苏轼诗词");

        try {noteService.save(entity);
        } catch (Exception e) {e.printStackTrace();
            // FIXME 我想在这里拿到的是 同步异样! [XXX]
            // FIXME 然而这里拿到的是 Transaction silently rolled back because it has been marked as rollback-only
            System.out.println(">>>>>>>>>>" + e.getMessage());
        }
    }

}

无缘无故

代码历史长远,为何这样写已无从追溯。

纳闷了一会儿,看到双层事务,就想起了 Spring 事务流传机制,前边了解得比拟浮浅。

没有非凡的配置,天然是走默认的事务流传机制了,也就是 Propagation.REQUIRED。

国际惯例,列出事务流传机制:

1、PROPAGATION_REQUIRED
以后没事务,则创立事务;存在事务,就退出该事务,这是最罕用的设置。2、PROPAGATION_SUPPORTS
以后存在事务,就退出事务,以后不存在事务,就以非事务形式执行。3、PROPAGATION_MANDATORY
以后存在事务,就退出事务;以后不存在事务,就抛出异样。4、PROPAGATION_REQUIRES_NEW
无条件创立新事务。5、PROPAGATION_NOT_SUPPORTED
以非事务形式执行,如果以后存在事务,就将以后事务挂起。6、PROPAGATION_NEVER
以非事务形式运行,如果存在事务,就抛出异样。7、PROPAGATION_NESTED
开始执行事务前,先保留一个 savepoint,当产生异样时,就回滚到 savepoint;没有异样时,跟着内部事务一起提交或回滚。

具体起因

1、看了上边的事务流传机制,持续细化问题,内外层共用一个事务,内层抛出异样,会导致整个事务失败。

2、持续剖析,外层逻辑进行了 try catch,就导致内层的异样无奈持续向上抛出,外层事务会持续提交。

3、事务提交时,进行事务状态的判断,就发现这个事务是失败的,须要回滚,所以抛出了 Transaction silently rolled back because it has been marked as rollback-only 的异样。

怎么解决?

银弹天然是没有的,依据业务场景抉择适合的计划。

1、以后这种场景,间接把外层逻辑中的 try catch 去掉即可。异样间接向上抛,事务就不会持续提交,调用方拿到的就是一手的异样;

2、如果内层不是外围逻辑,记录个日志啥的,能够把内层事务配置为 @Transactional(rollbackFor = Throwable.class, propagation = Propagation.REQUIRES_NEW),无论如何,都创立新的事务,外层事务不受内层事务影响。然而有个问题,外层事务失败了,内层事务还是把记录入库了,有可能产生脏数据;

3、如果外层事务失败了,内层事务也不能提交,那就能够应用 @Transactional(rollbackFor = Throwable.class, propagation = Propagation.NESTED)。留神:hibernate/jpa 不反对嵌套事务 NESTED,可用 JdbcTemplate 代替。

近期热文举荐:

1.Java 15 正式公布,14 个新个性,刷新你的认知!!

2. 终于靠开源我的项目弄到 IntelliJ IDEA 激活码了,真香!

3. 我用 Java 8 写了一段逻辑,共事直呼看不懂,你试试看。。

4. 吊打 Tomcat,Undertow 性能很炸!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

退出移动版