当两个线程同时访问带有@Transactional的方法时,我们会获得多少个事务?

问题描述 投票:2回答:2

假设我们有这个代码:

@Transactional
public String getUser(long id) {

    User user = userDao.getUserById(id);
    if(user == null) {
        user = new User();
        user.setXXX(XXX);
        userDao.insert(user);
    }   
}

假设数据源是mysql5

如果两个线程同时访问getUser()方法,我们会得到多少交易?如果答案是两个,那么两个交易之间的关系是什么?

java mysql spring multithreading transactional
2个回答
3
投票

从Spring文档开始:

getTransaction(..)方法返回TransactionStatus对象,具体取决于TransactionDefinition参数。返回的TransactionStatus可能表示新事务,或者如果当前调用堆栈中存在匹配的事务,则可以表示现有事务。后一种情况的含义是,与Java EE事务上下文一样,TransactionStatus与执行线程相关联。

这意味着对于每个线程,Spring将创建一个新事务,除非该线程已经存在一个。

当两个线程进入此方法时,会创建两个单独的事务,它们之间没有关系。这里没有嵌套或任何东西(这是一个不同的场景)。我能想到的唯一可以解决的问题是使用Propagation.REQUIRES_NEW,但这不是这种情况。


0
投票

如果两个线程同时访问getUser()方法,我们会得到多少个事务?

答案取决于连接工厂和数据库类型。如果您正在使用连接池或以其他方式创建两个连接,则每个线程将与数据库进行单独的事务。此处的详细信息高度依赖于您的连接池和数据库设置。

如果答案是两个,那么两个交易之间的关系是什么?

这取决于数据库对这些事务的处理方式。重要的是要意识到事务不是关于互斥,而是关于数据库的一致性。引用wikipedia

事务表示在数据库管理系统(或类似系统)内针对数据库执行的工作单元,并以独立于其他事务的连贯且可靠的方式进行处理。事务通常表示数据库中的任何更改。

事务如何交互在很大程度上取决于创建的事务类型以及在其中执行的操作。如果你问两个线程是否有可能同时查找具有相同id的User,然后尝试创建相同的User两次,那么答案肯定是肯定的。

这样做的一个问题是,两个userDao.insert(...)调用都可能成功,但第二个提交其事务(竞争条件警报)可能会抛出某种唯一约束异常,但这可能是AOP级别而不是代码。

© www.soinside.com 2019 - 2024. All rights reserved.