2

在 Java DAO 中的方法上使用“同步”关键字是否会在 Web 应用程序使用时引起问题?

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

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。

4

2 回答 2

3

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

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

于 2009-07-10T17:34:15.413 回答
1

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

  • 保持原样,因为当没有对锁的争用时对性能的影响可以忽略不计,如果考虑到访问数据库的费用,则微不足道。
  • 重新设计它,以便为独立应用程序添加一个同步层,以保护底层未同步的 DAO。

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

于 2009-07-10T16:18:50.573 回答