简体   繁体   English

JPA / Hibernate实体类和同步的最佳实践是什么?

[英]What is the best practice for JPA/Hibernate entity classes and synchronization?

It seems like most examples of JPA/Hibernate entity bean classes I've seen do no explicit synchronization. 似乎我所见过的大多数JPA / Hibernate实体Bean类示例都没有显式同步。 Yet, it is possible to call getters/setters on those objects in the context of building up a transaction. 但是,可以在建立事务的上下文中调用这些对象的getter / setter。 And it's possible for those methods to be called across multiple threads (although maybe that's unusual and weird). 而且有可能在多个线程中调用这些方法(尽管这可能是异常且怪异的)。

It seems like if it is built up across multiple threads then it's possible for changes to object state to be lost, which would be sad. 似乎如果跨多个线程构建了对象,那么可能会丢失对对象状态的更改,这将是令人遗憾的。

So, is leaving out synchronization best practice? 那么,是否遗漏了同步的最佳实践? Is the Hibernate instrumented code taking care of proper synchronization for me? Hibernate插桩代码是否为我做好了适当的同步?

As an example: 举个例子:

@Entity
public class Ninja {
  @Id @GeneratedValue
  private Long id;

  @Column 
  private String name;

  @Column
  private int throwingStars;

  public Ninja() {}
  public int getThrowingStars() { return throwingStars; } 
  public void addThrowingStar() { throwingStars += 1; }
}

Do the throwing star methods need synchronization? 抛星方法需要同步吗? I sure don't want my ninja to lose any throwing stars. 我当然不希望我的忍者失去任何投掷的星星。

In my opinion you should NEVER share domains objects across threads. 我认为您永远不要跨线程共享域对象。 In fact I typically share very little between threads as such data must be protected. 实际上,由于必须保护此类数据,因此我通常在线程之间很少共享。 I have built some large/high performance systems and have never had to break this rule. 我已经构建了一些大型/高性能系统,并且从未违反过此规则。 If you need to parallelize work then do so but NOT by sharing instances of domain objects. 如果您需要并行化工作,则可以这样做,但不必共享域对象的实例。 Each thread should read data from the database, operate on it by mutating/creating objects and then commit/rollback the transaction. 每个线程应从数据库读取数据,通过更改/创建对象对其进行操作,然后提交/回滚事务。 Work pass in/out should be value/readonly objects generally. 工作输入/输出通常应该是值/只读对象。

"And it's possible for those methods to be called across multiple threads (although maybe that's unusual and weird)." “而且有可能在多个线程中调用这些方法(尽管这可能是异常和怪异的)。”

I can speak for hibernate ONLY since I don't have much experience with JPA. 因为我对JPA的经验不足,所以我只能代表休眠。 The object on which you call set is NOT always the same object on which you call get. 您调用的对象并不总是与调用get的对象相同。 When Hibernate is loading the Object for you, it gets to call the set* methods and then you're(and your threads) calling get the rest of the time. 当Hibernate为您加载对象时,它会调用set *方法,然后您(和您的线程)将剩下的时间用于调用。

Again, when you're(ie, your writer threads) modifying an existing Object and then saving it again, you need to protect access to the object(so that other reader/writer threads don't read dirty data). 同样,当您(即您的编写器线程)修改现有对象然后再次保存时,您需要保护对对象的访问(以便其他读取器/编写器线程不会读取脏数据)。

The object probably is not the same for the 2 threads. 这两个线程的对象可能不相同。 Supposing your threads use a session factory to access the db, the objects you get from the session should be viewed as 'independent' (I believe hibernate creates 'fresh' objects for each get(), unless they are in the session). 假设您的线程使用会话工厂访问数据库,那么从会话中获取的对象应被视为“独立”(我相信休眠状态会为每个get()创建“新”对象,除非它们在会话中)。

As for your stars question, it's the same when two persons fetch the same row from a DB, the DB 'ACID' properties will make sure that each operation is atomic, so if you remove a star from a ninja in Thread t1 and commit , Thread t2 will read the committed values of t1. 至于您的星星问题,当两个人从数据库中获取同一行时,这是相同的,数据库的“ ACID”属性将确保每个操作都是原子的,因此如果您从线程t1中的忍者中删除星星并进行提交 ,线程t2将读取t1的提交值。

Alternatively, you can ask hibernate to lock the row of the relevant ninja in T1, so that even if T2 asks for the row it will have to wait until T1 commits or aborts. 另外,您可以要求休眠状态将相关忍者的行锁定在T1中,这样,即使T2请求该行,它也必须等待,直到T1提交或中止。

JPA/Hibernate entities are POJOs. JPA /休眠实体是POJO。 Hibernate and any JPA-Provider does not change runtime sematics. Hibernate和任何JPA-Provider都不会更改运行时语义。

So if you would have concurrency issues with a simple POJO, you will also have them with your entity! 因此,如果您在使用简单的POJO时遇到并发问题,那么您的实体也会遇到这些问题!

In all the Systems I have seen the domain model is not threadsave, entity instances are not accessed by several threads. 在所有我看到的系统中,域模型不是threadave,实体实例不能被多个线程访问。

However you can have several instances of the same entities concurrently. 但是,您可以同时具有同一实体的多个实例。 In this case synchronization is done over the DB. 在这种情况下,同步是通过数据库完成的。 The patterns here are Optimistic and Pessimistic Locking. 这里的模式是乐观锁定和悲观锁定。 Hibernate and JPA can help you with the realization of these patterns. Hibernate和JPA可以帮助您实现这些模式。

The best practice for your problem is Optimistic Locking: 解决问题的最佳实践是乐观锁定:

From the Java Persistence API (JPA) specification (Chapter 3.4.1): 根据Java Persistence API(JPA)规范(第3.4.1章):

Optimistic locking is a technique that is used to insure that updates to the database data corresponding to the state of an entity are made only when no intervening transaction has updated that data for the entity state since the entity state was read. 乐观锁定是一种技术,用于确保仅在自从读取实体状态以来没有中间事务更新实体状态的数据时,才对与实体状态相对应的数据库数据进行更新。 This insures that updates or deletes to that data are consistent with the current state of the database and that intervening updates are not lost. 这样可确保对该数据的更新或删除与数据库的当前状态一致,并且不会丢失中间的更新。

You need to add an @Version annotation to your class and a column in the DB table. 您需要在类中添加@Version批注,并在数据库表中添加一列。

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

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