Javasynchronized关键字与Spring@Transactional注解的逻辑比较
在一次有关 Spring/Hibernate 事务的演示中,我提出了一种观点,即方法上的 synchronized
关键字和 @Transactional
在逻辑上有许多相似之处。果然,它们是完全不同的野兽,但它们都作为方法的方面应用,并且都通过某种共享监视器(例如,记录在数据库中)控制对某些资源的访问。
人群中有几个人立即反对并声称我的比较是致命的错误。我不记得具体的论点,但我也可以在这里看到一些观点。例如,synchronized
从一开始就适用于整个方法,而事务仅在到达访问数据库的语句时才会生效。另外,synchronized
不提供任何读/写锁定模式。
所以问题是,我的比较是否完全错误,我永远不应该使用它,或者,如果措辞正确,将其呈现给经验丰富的工程师是否有意义,这些工程师非常了解 synchronized
的工作原理,但仍在尝试了解AOP事务?这个写法应该是什么?
一点更新。
显然,我的问题听起来像是比较数据库事务与在 Java 中输入同步方法。事实并非如此。我的想法更多的是比较 @Transactional
和 synchronized
语义上的相似性。
我提出它的原因之一也是为了说明传播行为。例如,如果@Transactional
是PROPAGATION_REQUIRED,它将与进入synchronized
块有很多相似之处。对于交易:如果交易存在,我们就继续使用它,如果没有,我们将创建一个。对于synchronized
,如果我们已经有了监视器,我们就继续它,如果没有,我们将尝试获取它。当然,对于@Transactional,我们不会锁定方法边界。
At one of presentations about Spring/Hibernate transactions I brought up an opinion that synchronized
keyword on a method and @Transactional
logically have many similarities. Sure enough they are totally different beasts but yet they both applied as aspects to the method and both control access to some resources via some kind of shared monitor (record in db, for example).
There were couple of people in the crowd who immediately opposed and claimed that my comparison is fatally wrong. I don't remember specific arguments but I can see some point here as well. For example, synchronized
works for the entire method from the beginning and transaction will only have effect when statement to access DB is reached. Plus synchronized
does not offer any read/write locking pattern.
So the question is, is my comparison totally wrong and I should never ever use it, or, with proper wording, would it make sense to present it to experienced engineers who know well how synchronized
works but yet trying to learn about AOP transactions? What this wording should be?
A bit of update.
Apparently my question sounded like comparing DB transactions vs entering synchronized
method in Java. That's not the case. My idea is more about comparing similarities in semantics of @Transactional
and synchronized
.
One of the reason I brought it up also was to illustrate propagation behavior. For example, if @Transactional
is PROPAGATION_REQUIRED it will have many similarities to entering synchronized
block. For transaction: if transaction is present we just continue using it and if not, we will create one. For synchronized
, if we already have monitor we proceed with it and if not we will attempt to acquire it. Of course for @Transactional
we are not going to lock on method boundary.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果我们将 @Transactional 视为表示锁定数据库资源的方法(因为它在事务中使用),那么这种比较就有意义。
然而,这就是他们的共同点。同步是在对象监视器上定义的(并且仅保护它),该监视器在使用关键字时已知,而事务可能会锁定多个资源(在事务开始时未知),或者可能不锁定任何资源根本没有(乐观锁定、只读事务)。
所以最终 - 不要使用这种比较,它们的不同之处比共同点要多得多。
If we look at
@Transactional
as denoting a method that locks a database resource (because it is used in the transaction) - then the comparison makes some sense.However this is all they have in common. synchronized is defined on an object monitor (and protects only it), which is known at the time of usage of the keyword, while a transaction may lock multiple resources (that are not known when the transaction starts), or may not lock any resources at all (optimistic locking, read-only transactions).
So ultimately - don't use that comparison, there are a lot more things that they differ in than they have in common.
@Transactional
注解所体现的概念比synchronized
关键字所体现的概念要复杂得多。我同意 JB Nizet 的评论,即你的比较是违反直觉的,会让你的观众感到困惑。通过 Java 同步,您始终可以准确地知道锁定的内容、从代码中的哪一点开始以及锁定到哪一点。您已经内置了线程和竞争同一资源的线程队列的概念。此外,您实际上是锁定代码,而不是锁定数据。这看起来似乎有细微差别,但差异可能很大。
使用@Transactional,首先会遇到事务划分的问题。您不知道事务何时开始,因为您可能在已经打开事务后到达此方法。出于同样的原因,您不知道退出该方法时事务是否会结束。
其次,事务隔离语义比同步(只读、读写等)复杂得多。很多时候,隔离解决的是对数据完整性的担忧,而不是本质上对资源访问排队的担忧。有时只有一条记录被锁定,有时整个表被锁定(再次强调,这是数据,而不是代码)。此外,事务可以回滚,这一概念对于数据完整性很重要,但
synchronized
中不存在这一概念。The concepts embodied in
@Transactional
annotation are much more complex than those embodied insynchronized
keyword. I agree with JB Nizet's comment that your comparison is counter-intuitive and would confuse your audience.With Java synchronization, you always know exactly what is being locked, from which point in the code and to which point. You have built-in the concept of threads and a queue of threads competing for the same resource. Also, you are in effect locking code, not locking data. It may seem like a nuance, but the difference could be substantial.
With @Transactional, first you have the issue of transactions demarcation. You don't know exactly when a transaction begins, since you might reach this method after already having opened a transaction. For the same reason, you don't know if the transaction will end when you exit the method.
Secondly, transaction isolation semantics are much more complex then just synchronization (read-only, read-write, etc.). Many times isolation answers a concern about data integrity, and not intrinsically a concern about queuing access to a resource. Sometimes just one record is locked, sometimes a whole table (again, this is data, not code). Further more, transactions can be rolled-back, a concept that is important for data integrity and doesn't exist with
synchronized
.