简体   繁体   English

如何在多线程环境中处理JPA OneToMany关系

[英]How to handle JPA OneToMany relations in a multi-threaded environment

I'm having two JPA entities which are linked to each other. 我有两个相互链接的JPA实体。 A person can be member of zero or one groups. 一个人可以是零个或一个组的成员。 A group can have zero or more members. 一个组可以有零个或多个成员。

@Entity
public class PersonEntity {

    @ManyToOne
    @JoinColumn(name = "GROUP_ID")
    private GroupEntity group;
}

@Entity
public class GroupEntity {

    @OneToMany(mappedBy = "group", cascade = { CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH })
    private Collection<PersonEntity> persons;

}

The problem I'm having is that multiple threads can remove/add persons to a group. 我遇到的问题是多个线程可以将人员删除/添加到组中。 So when two threads remove a person from the same group, each of them is unaware of what happened in the other thread. 因此,当两个线程从同一组中删除一个人时,每个线程都不知道另一线程中发生了什么。

  1. personA and personB belong to group1 personA和personB属于组1
  2. Thread1 removes personA from group1 线程1从组1中删除人员A
  3. Thread2 removes personB from group1 线程2从group1中删除personB
  4. Thread1 does some post-processing with personB Thread1对personB进行一些后处理
  5. Thread2 does some post-processing with personA Thread2对personA进行一些后处理

I know I can wrap this all in a synchronized block, but that would not help me if the application is running on multiple machines that share a database. 我知道我可以将所有这些都包装在一个同步块中,但是如果应用程序在共享数据库的多台计算机上运行,​​那将无济于事。

How could JPA be aware that the collection on GroupEntity has been changed by another thread? JPA如何知道GroupEntity上的集合已被另一个线程更改?

You are right about the synchronized block: that will not apply across JVMs 您对同步块是正确的:这不适用于JVM

Use a database locking strategy to handle concurrent updates to an entity 使用数据库锁定策略来处理对实体的并发更新

Instead, you want to consider a database locking strategy and using database transactions. 相反,您要考虑数据库锁定策略并使用数据库事务。 JPA supports both optimistic and pessimistic locking . JPA支持乐观锁定和悲观锁定 You can typically achieve better performance with optimistic locking which uses a version field to track updates to each of your entities. 通常,您可以通过使用版本字段来跟踪对每个实体的更新的乐观锁定来获得更好的性能。

In your scenario, if the threads each perform their remove and update in operations in one database with optimistic locking, one thread will succeed and the other will throw a locking exception because it tried to update an entity which has been removed 在您的方案中,如果每个线程都使用乐观锁定在一个数据库中执行其删除和更新操作,则一个线程将成功,而另一个线程将抛出锁定异常,因为它试图更新已删除的实体

Use a join table to eliminate contention between modifications to Group membership and Person attributes 使用联接表来消除对组成员资格和Person属性的修改之间的争用

Assuming that removing the Person from the group does not delete the person, there may be another way to remove contention in this scenario. 假设从该组中删除该人员不会删除该人员,则在这种情况下可能存在另一种方法来删除竞争。 Typically, in a one-to-many relationship, the Person row will hold a reference to the group ID to which it belongs. 通常,在一对多关系中,“人员”行将保留对其所属组ID的引用。 This causes Thread 1 and Thread 2 to compete for updates to a Person row. 这将导致线程1和线程2竞争对“个人”行的更新。 Instead, you could move the one-to-many relationship to a separate join table so that Thread 1 can remove PersonA from Group1 at the same time that Thread2 does post processing with PersonA 相反,您可以将一对多关系移动到单独的联接表,以便线程1可以在线程2对PersonA进行后期处理的同时将PersonA从Group1中删除。

On synchronizing relationship collections between JVMs 关于在JVM之间同步关系集合

JPA implements several persistence patterns Martin Fowler details in Patterns of Enterprise Application Architecture . JPA在企业应用程序体系结构模式中实现了几种持久性模式Martin Fowler细节。 One of these patterns is the Unit of Work which tracks changes made during a "session". 这些模式之一是工作单元,它跟踪“会话”期间所做的更改。 I believe Thread1 and Thread2 are working in separate units of work and therefore they should avoid trying to synchronize their in-memory caches of data retrieved from the database. 我认为Thread1和Thread2在不同的工作单元中工作,因此它们应避免尝试同步其从数据库中检索的数据的内存中缓存。 Instead, Thread1 will get Thread2's changes the next time it queries the database. 取而代之的是,Thread1在下一次查询数据库时将获取Thread2的更改。 Let the database own the concern of synchronizing state across the distributed system. 让数据库拥有跨分布式系统同步状态的关注。

If you need to manage distributed transactions, look into JTA ; 如果您需要管理分布式事务,请查看JTA however, I'm not sure which JPA providers are able to distribute their unit of work's in-memory state within a distributed transaction. 但是,我不确定哪个JPA提供程序能够在分布式事务中分配其工作单元的内存状态。 This is situation I would try to avoid instead of handle 我会尝试避免这种情况,而不是处理

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM