在 Java DAO 中的方法上使用“synchronized”关键字是否会在 Web 应用程序使用时导致问题?
我问这个问题是因为我有一个多线程独立应用程序,需要同步方法以避免资源冲突,如此处所示。
java.util.concurrent.ExecutionException: javax.persistence.PersistenceException: org.hibernate.HibernateException: Found shared references to a collection: com.replaced.orm.jpa.Entity.stuffCollection
我担心的是,当大量人尝试使用该应用程序时,同步方法将阻塞并减慢整个应用程序的速度。
我正在使用 Spring 注入(inject)的 JPA 实体管理器工厂,它为 DAO 提供实体管理器。从技术上讲,我可以删除 DAO 层并让类直接调用实体管理器工厂,但我喜欢 DAO 提供的分离。
我还应该注意,我非常小心,不要在线程之间传递连接的实体 ORM 对象。我推测是访问DAO时出现资源冲突错误。我认为多个线程同时进行,并尝试以非原子方式持久保存或从数据库中读取。
在这种情况下,使用 DAO 是否弊大于利?
我在问题中遗漏的一大信息是 DAO 不是单例。如果我的思考足够清晰,能够包含这些细节,我可能一开始就不会问这个问题。
如果我理解正确的话,Spring 会为每个使用 DAO 类的类创建一个新实例。因此,每个线程的支持实体管理器应该是唯一的。正如 Rob H 回答的那样,不共享实体管理器是这里的关键。
但是,现在我不明白为什么在删除同步时会出现错误。
根据这个thread ,@PersistenceContext注释创建一个线程安全的SharedEntityManager。所以您应该能够创建一个单例 DAO。
最佳答案
您说您没有跨线程共享实体对象。那挺好的。但您还应该确保您没有跨线程共享 EntityManager 对象(或 Hibernate 中的 Session 对象)。像 Spring 这样的框架通过将 session 存储在线程局部变量中来自动为您管理此操作。如果您在没有框架帮助的情况下编写自己的 DAO,则需要自己采取预防措施以避免共享它们。
一旦执行此操作,就没有理由同步 DAO 方法,因为任何 session 状态都不会跨线程共享。这对于高度并发的 Web 应用程序至关重要。另一种方法是,假设它们都共享同一个 DAO 实例,则一次只有一个线程能够访问 DAO。对于吞吐量来说一点也不好。
关于java - 在 Java DAO 上使用同步是否会导致问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1110328/