1

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

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

在假代码中:

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() 仍然包含在同一个对象中交易。

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

4

3 回答 3

1

事务对数据库的真正意义取决于隔离级别。关于隔离(数据库系统)的维基百科文章很好地解释了这一点。

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


但老实说,我会使用另一种方式:使相关列唯一(但不要删除您的if (!fooExists(fooValue))-check)。所以在 99% 的情况下,您的检查工作。在剩下的 1% 中,你会得到一个异常,因为你试图违反唯一性约束。

于 2013-08-07T16:19:20.663 回答
0

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

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

于 2013-08-07T16:22:46.397 回答
0

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

于 2013-08-07T17:54:10.820 回答