有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java什么是Spring事务的原子性?

我对原子操作的理解是,该操作的步骤不可能与任何其他操作的步骤交叉——它应该作为单个单元执行

我有一个创建数据库记录的方法,首先检查是否已经存在具有相同值的记录,该值也满足某些其他参数,如果存在,则不会创建该记录

伪造代码:

public class FooDao implements IFooDao {

    @Transactional
    public void createFoo(String fooValue) {
        if (!fooExists(fooValue)) {
            // DB call to create foo
        }
    }

    @Transactional
    public boolean fooExists(String fooValue) {
        // DB call to check if foo exists
    }
}

然而,我发现有可能创建两个具有相同值的记录,这表明这些操作以某种方式交错。我知道,使用Spring的事务代理,对象内方法的自调用将不会使用事务逻辑,但是如果从对象外部调用createFoo(),那么我希望fooExists()仍然包含在同一事务中

我对什么事务原子性应该强制执行的期望是错误的吗?我是否需要使用同步块来强制执行此操作


共 (3) 个答案

  1. # 1 楼答案

    事务性意味着所有更新都发生在同一事务中,即所有更新/插入/删除成功或全部回滚(例如,如果更新多个表)

    它不能保证事务中查询的行为,这取决于RDBMS及其配置(数据库上隔离级别的配置)

  2. # 2 楼答案

    @Transactional默认情况下不会使代码同步。两个单独的线程可以同时进入同一块并导致插入。同步方法也不是一个很好的答案,因为这会极大地影响应用程序的性能。如果您的问题是两个不同的线程正在创建两个相同的记录,那么您可能希望在数据库上添加一些具有唯一约束的索引,以便重复插入将失败

  3. # 3 楼答案

    事务对数据库的真正意义取决于隔离级别。wikipdia关于Isolation (database systems)的文章很好地解释了这一点

    通常使用不太高的隔离级别,例如:Read committed。这意味着在提交另一个事务之前,可以从另一个事务读取数据。 在你的情况下,这是不够的,因为这与你想要的正好相反因此,显而易见的解决方案是使用更严格、更慢的隔离级别:Repeatable reads


    但老实说,我会使用另一种方法:使相关列唯一(但不要删除if (!fooExists(fooValue))-check)。因此,在99%的支票工作。在剩余的1%中,您将得到一个异常,因为您试图违反唯一约束