是否可以在不使用hibernate修改实体版本的情况下在数据库中更新实体?
使用我的Web应用程序,用户可以创建或更新实体.另外一个异步过程在任何用户操作之后"处理"这些实体.如果用户在"处理"实体之前打开实体进行更新,但在"处理"实体后尝试保存,则用户将获得"OptimisticLockException",并且所有输入的数据都将丢失.但我想用用户提供的数据覆盖异步过程中更新的数据.
代码snipet来演示为什么我需要这样的行为(JPA + Hibernate):
//user creates entity by filling form in web application
Entity entity = new Entity ();
entity.setValue("some value");
entity.setProcessed (false);
em.persist(entity);
em.flush();
em.clear();
//but after short period of time user changes his mind and again opens entity for update
entity = em.find(Entity.class, entity.getId());
em.clear(); //em.clear just for test purposes
//another application asynchronously updates entities
List entities = em.createQuery(
"select e from Entity e where e.processed = false")
.getResultList();
for (Object o: entities){
Entity entityDb = (Entity)o;
someTimeConsumingProcessingOfEntityFields(entityDb); //update lots of diferent entity fields
entityDb.setProcessed(true);
em.persist(entityDb);
}
em.flush(); //version of all processed entities are incremented.
//Is it possible to prevent version increment?
em.clear();
//user modifies entity in web application and again press "save" button
em.merge(entity); //em.merge just for test purposes
entity.setValue("some other value");
entity.setProcessed (false);
em.persist(entityDb);
em.flush(); //OptimisticLockException will occur.
//Is it possible to prevent this exception from happening?
//I would like to overwrite data updated in asynchronous process
//with user provided data.
Run Code Online (Sandbox Code Playgroud)
而我的实体:
@Entity
@Table(name = "enities")
public class Entity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private int versionNum;
@Column
private String value
@Column
private boolean processed;
//… and so on (lots other properties)
}
Run Code Online (Sandbox Code Playgroud)
实际上我有更多类似问题的类 - 所以我正在寻找一些优雅的非侵入式解决方案.
在我看来,这是很常见的情况.但我找不到任何有关如何实现此类功能的信息.
可以使用 hibernate Session ( http://docs.jboss.org/hibernate/orm/5.0/javadocs/org/hibernate/Session.html ) replicate(...)方法绕过 Hibernate 乐观锁定。
不增加版本的代码示例:
//Detaching to prevent hibernate to spot dirty fields.
//Otherwise if entity exists in hibernate session replication will be skipped
//and on flush entity will be updated with version increment.
em.detach(entityDb);
someTimeConsumingProcessingOfEntityFields(entityDb);
//Telling hibernate to save without any version modifications.
//Update hapends only if no newer version exists.
//Executes additional query DB to get current version of entity.
hibernateSession.replicate(entity, ReplicationMode.LATEST_VERSION);
Run Code Online (Sandbox Code Playgroud)
我认为这个解决方案比原生 SQL 更新更好,因为:
| 归档时间: |
|
| 查看次数: |
2586 次 |
| 最近记录: |