在 Java DAO 上使用同步是否会导致问题?

发布于 2024-07-26 10:36:39 字数 1063 浏览 7 评论 0原文

当 Web 应用程序使用 Java DAO 中的方法时,使用“synchronized”关键字是否会导致问题?

我问这个问题是因为我有一个多线程独立应用程序,需要同步方法以避免资源冲突,如此处所示。

java.util.concurrent.ExecutionException: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: com.replaced.orm.jpa.Entity.stuffCollection

我担心的是,当大量的人尝试使用该应用程序时,同步方法将阻塞并减慢整个应用程序的速度。

我正在使用 Spring 注入的 JPA 实体管理器工厂,它为 DAO 提供实体管理器。 从技术上讲,我可以删除 DAO 层并让类直接调用实体管理器工厂,但我喜欢 DAO 提供的分离。

我还应该注意到,我非常小心,不要在线程之间传递连接的实体 ORM 对象。 我推测是访问DAO时出现资源冲突错误。 我认为多个线程同时进行,并尝试以非原子方式持久保存或从数据库中读取。

在这种情况下,使用 DAO 是否弊大于利?


我在问题中遗漏的一大信息是 DAO 不是单例。 如果我的思考足够清晰,能够包含这个细节,我可能一开始就不会问这个问题。

如果我理解正确的话,Spring 会为每个使用 DAO 类的类创建一个新实例。 因此,每个线程的支持实体管理器应该是唯一的。 正如 Rob H 回答的那样,不共享实体管理器是这里的关键。

但是,现在我不明白为什么在删除同步时会出现错误。


根据这个线程,@PersistenceContext注释创建了一个线程安全的SharedEntityManager。 所以你应该能够创建一个单例 DAO。

Is using the 'synchronized' keyword on methods in a Java DAO going to cause issues when used by a web application?

I ask because I have a multi-threaded stand alone application that needs the methods to by synchronized to avoid resource conflict, as seen here.

java.util.concurrent.ExecutionException: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: com.replaced.orm.jpa.Entity.stuffCollection

What I am concerned about is that when a significant number of people try and use the application that the synchronized methods will block and slow the entire application down.

I am using a Spring injected JPA entity manager factory, which provides an entity manager to the DAO. I could technically remove the DAO layer and have the classes call the entity manager factory directly, but I enjoy the separation the DAO provides.

I should also note that I am being very careful not to pass around connected entity ORM objects between threads. I speculate that the resource conflict error comes about when accessing the DAO. I think multiple threads are going at the same time and try to persist or read from the database in non-atomic ways.

In this case is using a DAO going to do more harm then help?


A big piece of information I left out of the question is that the DAO is not a singleton. If I had been thinking lucidly enough to include that detail I probably wouldn't have asked the question in the first place.

If I understand correctly, Spring creates a new instance of the DAO class for each class that uses it. So the backing entity manager should be unique to each thread. Not sharing the entity manager is, as Rob H answered, the key thing here.

However, now I don't understand why I get errors when I remove synchronized.


According to this thread, the @PersistenceContext annotation creates a thread-safe SharedEntityManager. So you should be able to create a singleton DAO.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

勿忘初心 2024-08-02 10:36:39

您说您没有跨线程共享实体对象。 那挺好的。 但您还应该确保您没有跨线程共享 EntityManager 对象(或 Hibernate 中的 Session 对象)。 像 Spring 这样的框架通过将会话存储在线程局部变量中来自动为您管理此操作。 如果您在没有框架帮助的情况下编写自己的 DAO,则需要自己采取预防措施以避免共享它们。

一旦执行此操作,就没有理由同步 DAO 方法,因为任何会话状态都不会跨线程共享。 这对于高度并发的 Web 应用程序至关重要。 另一种方法是,假设它们都共享同一个 DAO 实例,那么一次只有一个线程能够访问 DAO。 对于吞吐量来说一点也不好。

You say you are not sharing entity objects across threads. That's good. But you should also make sure you're not sharing EntityManager objects (or Session objects in Hibernate) across threads either. Frameworks like Spring manage this for you automatically by storing the session in a thread-local variable. If you're coding your own DAOs without the help of a framework, you need to take precautions yourself to avoid sharing them.

Once you do this, there should be no reason to synchronize DAO methods because none of the conversational state will be shared across threads. This is critical for a highly concurrent web application. The alternative is that only one thread will be able to access the DAO at one time, assuming they all share the same DAO instance. Not good at all for throughput.

无语# 2024-08-02 10:36:39

如果为了线程安全需要同步,那么就将它们留在那里。 在这种情况下无论如何都需要阻止。 如果 Web 应用程序案例不需要阻止,您可以:

  • 保持原样,因为性能
    当没有争用时命中
    锁可以忽略不计,并且
    考虑在内时微不足道
    访问数据库的费用。
  • 重新设计它,以便您添加一个
    同步层为
    独立应用案例
    保护底层
    不同步的 DAO。

就我个人而言,我会保持原样并对其进行分析以查看是否需要重构。 在那之前,您只是在进行过早的优化。

If it needs to be synchronized for thread safety, then leave them there. The blocking is required anyway in that case. If the blocking is not required for the web application case, you can either:

  • leave it as is, since the performance
    hit when there is no contention on
    the lock is negligible, and
    insignificant when taken into account
    the expense of hitting the database.
  • Redesign it so that you add a
    synchronization layer for the
    standalone application case which
    protects the underlying
    unsynchronized DAO.

Personally, I would leave it as is and profile it to see if you need to refactor. Until then you are simply doing premature optimization.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文