【问题标题】:Is using synchronized on a Java DAO going to cause issues?在 Java DAO 上使用同步会导致问题吗?
【发布时间】:2009-07-10 15:42:04
【问题描述】:

在 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 回答的那样,不共享实体管理器是这里的关键。

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


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

【问题讨论】:

  • 您能否详细说明使用同步的原因,以及您指的是哪种“资源冲突”?

标签: java multithreading web-applications dao synchronized


【解决方案1】:

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

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

【讨论】:

  • 你认为直接访问实体管理器是否更好,这些实体管理器由 Spring 注入到需要它们的类中,让框架完成工作?
  • 不确定“直接访问实体管理器”是什么意思。通常,您只能访问 DAO 中的实体管理器。通过让 DAO 子类化 JpaDaoSupport,您可以轻松访问线程本地实体管理器。 (有关详细信息,请参阅 Spring 文档。)然后您使用 Spring 将您的 DAO 注入您的业务服务对象。因此,业务服务从不直接与 EM 合作。
  • 我会调查 JpaDaoSupport。我所说的直接访问的意思是在每个需要数据库访问的类中都有一个弹簧注入的实体管理器。用注解来做这件事相当简单。
  • 另外一点澄清:Spring 不会将 EntityManager 注入 DAO 或其他任何东西。它注入 EntityManagerFactory,它是线程安全的,并允许您(和 Spring)为当前线程动态获取 EntityManager。
  • 其实,再看Spring doc,我觉得你说得对! ;-) 显然,Spring 支持“共享”实体管理器,它们是实际事务性 EntityManager 的线程安全代理,可以注入。我没有意识到这一点,因为我使用的是本机 Hibernate——而不是 JPA。无论如何,重要的是确保持久性上下文状态不会跨线程共享,这可能是导致您看到的异常的原因。
【解决方案2】:

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

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

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

【讨论】:

  • 罗宾说得好。我可能陷入了试图解决我还没有遇到的问题的陷阱。我只是想确保我的方法不会对其他人造成严重错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-20
  • 1970-01-01
相关资源
最近更新 更多