【问题标题】:Logical comparison of Java synchronized keyword and Spring @Transactional annotationJava synchronized 关键字与 Spring @Transactional 注解的逻辑比较
【发布时间】:2011-09-22 16:25:51
【问题描述】:

在一次关于 Spring/Hibernate 事务的演讲中,我提出了一个观点,即方法上的 synchronized 关键字和 @Transactional 在逻辑上具有许多相似之处。果然,它们是完全不同的野兽,但它们都作为方法的方面应用,并且都通过某种共享监视器(例如,记录在 db 中)控制对某些资源的访问。

人群中有几个人立即反对并声称我的比较是致命的错误。我不记得具体的论点,但我也可以在这里看到一些观点。例如,synchronized 从一开始就适用于整个方法,事务只有在到达访问数据库的语句时才会生效。另外synchronized 不提供任何读/写锁定模式。

所以问题是,我的比较完全错误,我永远不应该使用它,或者,用适当的措辞,将它展示给熟悉synchronized 工作原理但仍在努力学习的经验丰富的工程师是否有意义关于 AOP 事务?这个措辞应该是什么?


一点更新。

显然我的问题听起来像是比较 DB 事务与在 Java 中输入 synchronized 方法。事实并非如此。我的想法更多是比较@Transactionalsynchronized 语义上的相似性。

我提出它的一个原因也是为了说明传播行为。例如,如果@Transactional 是 PROPAGATION_REQUIRED,那么它与进入synchronized 块有很多相似之处。对于交易:如果存在交易,我们就继续使用它,如果不存在,我们将创建一个。对于synchronized,如果我们已经有监视器,我们继续处理它,如果没有,我们将尝试获取它。当然对于@Transactional,我们不会锁定方法边界。

【问题讨论】:

  • 它们是完全不同的野兽,我认为继续使用这种比较只会给你的观众带来混乱。
  • 只是指出非常明显的一点:事务可以提交和回滚,同步确保只有独占访问。没有任何共同点,因为甚至不需要事务来锁定对象。
  • 请注意,我不是在比较 DB 事务与 JVM 监视器操作,而只是在 synchronized@Transactional 语义上的相似之处
  • 对于同步,如果我们已经有监视器,我们继续它,如果没有,我们将尝试获取它。实际上它确实增加了获取的计数,因此您应该考虑它Int,没有类似于传播类型的布尔值。在这种情况下,当计数达到零时释放锁,这与由容器定义的提交或回滚的事务传播不同。旁注是,您应该避免同步。在整个方法 b/c 上,大多数时候不应该锁定整个代码路径。

标签: java multithreading hibernate spring transactions


【解决方案1】:

如果我们将@Transactional 视为锁定数据库资源的方法(因为它在事务中使用) - 那么比较是有道理的。

然而,这就是他们的共同点。 synchronized 在对象监视器上定义(并且只保护它),这在使用关键字时是已知的,而事务可能会锁定多个资源(在事务开始时不知道),或者可能不锁定任何资源完全没有(乐观锁定、只读事务)。

所以最终 - 不要使用这种比较,它们的不同之处比它们的共同点要多得多。

【讨论】:

    【解决方案2】:

    @Transactional 注释中体现的概念比synchronized 关键字中体现的概念要复杂得多。我同意 JB Nizet 的评论,即您的比较是违反直觉的,会让您的听众感到困惑。

    使用 Java 同步,您始终可以准确地知道被锁定的内容、代码中的哪一点以及到哪一点。您已经内置了线程的概念和竞争相同资源的线程队列。此外,您实际上是在锁定代码,而不是锁定数据。这可能看起来有些细微差别,但差异可能很大。

    使用@Transactional,首先你有事务分界的问题。您不知道事务何时开始的确切时间,因为您可能在已经打开事务之后才使用此方法。同理,退出方法时不知道事务是否会结束。

    其次,事务隔离语义比同步(只读、读写等)复杂得多。很多时候,隔离解决了对数据完整性的担忧,而不是本质上对排队访问资源的担忧。有时只有一条记录被锁定,有时是整个表(同样,这是数据,而不是代码)。此外,事务可以回滚,这一概念对数据完整性很重要,synchronized 不存在。

    【讨论】:

    • You don't know exactly when a transaction begins, since you might reach this method after already having opened a transaction.synchronized 差别不大,你可以输入synchronized 方法已经拥有监视器,所以你不知道方法边界是否会抢/释放监视器。
    • @Alex,您原则上是正确的,但在实践中,就代码可读性而言,它是不一样的。我认为,当使用嵌套同步时,它通常对读者来说是相当明显的(而且通常在同一个类中)。在我看来,当你只看方法时,事务分界就不那么明显了。
    猜你喜欢
    • 2017-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-24
    • 1970-01-01
    • 1970-01-01
    • 2019-02-18
    相关资源
    最近更新 更多