使用实体的version属性进行乐观锁定工作正常并且易于实现:
<version property="VERSION" type="int" column="EX_VERSION" />
Run Code Online (Sandbox Code Playgroud)
该实体具有以下类型的属性:
private int VERSION;
public int getVERSION() { return VERSION; }
public void setVERSION(int VERSION) { this.VERSION = VERSION; }
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.现在,服务方法返回上面实体的数据传输对象(DTO),视图以HTML格式显示.对于更新页面,VERSION属性存储在HTML隐藏字段中并随表单一起提交.
目的是使用version属性来确保如果显示的信息附带旧版本,则用户的更新将失败.
控制器通过调用包含更新信息(包括版本属性)的DTO的服务方法来响应用户更新请求,并且服务方法依次使用数据访问对象(DAO)来持久化更改:
public void update(SimpleDTO dto) {
SimplyEntity entity = getSimpleDao().load(dto.getId());
copyProperties(dto, entity); // all properties, including VERSION copied to entity
getSimpleDao().update(entity);
}
Run Code Online (Sandbox Code Playgroud)
问题是Hibernate不遵守copyProperties(...)复制到实体中的版本属性.我在下面的论坛中找到了原因:https://forum.hibernate.org/viewtopic.php?f = 1&t = 955893&p = 2418068
简而言之,当调用load()时,Hibernate会在会话缓存中缓存version属性,并且随后更改为它的值无关紧要.我同意这是正确的行为,但我已经被老板指示通过HTML表单属性传递版本(如果有更好的模式,我很乐意听到它).
我现在正在探索的一个解决方案是在更新发生之前使用hibernateTemplate.evict(simpleEntity)设置版本之后将实体从会话中逐出.我希望这有效,但它看起来效率不高.
我想请Hibernate检查实例本身的version属性,而不是仅查看会话缓存.
提前谢谢你的答案!
- LES
所以,我正在开发一个简单的Spring MVC + JPA(hibernate)项目,其中有用户可以制作帖子并在他们的朋友帖子上发表评论(有点像一个小社交网络).使用JPA Hibernate我还是比较新的.因此,当我尝试从浏览器中测试一些任务(包含事务)的多个请求时,在处理上一个请求时非常快2-3次,我得到一个OptimisticLockException.这是堆栈跟踪..
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [org.facebookjpa.persistance.entity.Post] with identifier [19]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [org.facebookjpa.persistance.entity.Post#19]
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:973)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:852)
javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
Run Code Online (Sandbox Code Playgroud)
现在,我该如何解决这个问题?当多个事务请求同时发生时,如何正确处理此ObjectOptimisticLockException?我应该遵循哪些好的模式?我需要使用某种悲观锁定机制吗?
这是我目前正在使用的DAO ..提前感谢.:)
@Repository
@Transactional
public class PostDAOImpl implements PostDAO {
@Autowired
UserDAO userDAO;
@Autowired
CommentDAO commentDAO;
@Autowired
LikeDAO likeDAO;
@PersistenceContext
private EntityManager entityManager;
public PostDAOImpl() {
}
@Override
public boolean insertPost(Post post) …Run Code Online (Sandbox Code Playgroud) 我怀疑哪个是用@Version注释的字段的最佳类型,用于JPA中的乐观锁定.
API javadoc(http://docs.oracle.com/javaee/7/api/javax/persistence/Version.html)说:
"版本属性支持以下类型:int,Integer,short,Short,long,Long,java.sql.Timestamp."
在其他页面(http://en.wikibooks.org/wiki/Java_Persistence/Locking#Optimistic_Locking)中说:
"JPA支持使用乐观锁定版本字段,该字段在每次更新时都会更新.字段可以是数字或时间戳值.建议使用数值,因为数值更精确,可移植,高性能且更易于处理时间戳".
"如果表已经有最后更新的时间戳列,则经常使用时间戳锁定.这也是自动更新上次更新列的便捷方式.时间戳版本值比数字版本更有用,因为它包含相关信息关于对象上次更新的时间."
我的问题是:
如果您要使用lastUpdated字段或者更好地拥有数字版本字段和其他字段中的时间戳,那么更好的是Timestamp类型吗?
在数值类型(int,Integer,short,Short,long,Long)之间最好选择(考虑每种类型的长度)?我的意思是,我认为最好的是Long,但每行需要很多空间.
当版本字段到达数字类型的最后一个数字时会发生什么(例如,短字段中的32,767)?它会在下一次增量中从1开始吗?
我想运行模拟用户在同一时间Grails应用程序修改某些数据进行测试.
是否有任何插件/工具/机制可以用来有效地完成这项工作?它们不一定是特定的grails.应该可以并行触发多个动作.
我更喜欢在功能级别上运行测试(到目前为止,我正在使用Selenium进行其他测试)以从用户角度查看结果.当然,这除了可以集成测试完成,如果你会推荐上运行集成度并发修改测试以及.
testing grails functional-testing optimistic-locking concurrentmodification
我们正在尝试在抛出StaleObjectStateException之后组合对象以保存合并副本.
这是我们的环境状况:
使用案例:
我们希望优雅地处理异常.由于用户共享父级的所有权,因此用户1应该能够成功保存,并使用他的新孩子和用户2的孩子保存父级.
根据Ayende(http://msdn.microsoft.com/en-us/magazine/ee819139.aspx),当SOSE被抛出时:
您的会话及其加载的实体是toast,因为使用NHibernate时,会话抛出的异常会将该会话移动到未定义状态.您无法再使用该会话或任何已加载的实体
已经为现在没有用的会话分配了一个ID和版本号.(我希望它没有.)
我们如何结合使用ISession.Merge()和ISession.Refresh()来获得一个同时具有C1和C2的新保存的Parent?
我们已经尝试了许多奥术排列,其中没有一个完全奏效.通常,"行已被另一个事务更新或删除(或未保存的值映射不正确")或ODBC级别的实际ID冲突.
我们的理论,目前:
但是,所有文档都表明newSession.Merge 应该足够了.
用作研究的其他帖子:
Fluent NHibernate Newbie:Row被另一个事务更新或删除
是否有使用乐观锁定时不会抛出的ISession.Merge()的替代方法?
StaleObjectstateException行已更新或删除
如何告诉NHibernate只保存已更改的属性
Hibernate(JPA):如何在修改和提交多个对象时处理StaleObjectStateException(java,但相关,我认为)
nhibernate fluent-nhibernate optimistic-locking staleobjectstate
环境:
我有那个User实体:
@Entity
public class User implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userId;
@Version
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "VERSION", length = 19)
private Date version;
@Column(nullable = false, length = 20)
private String login;
// Getters and Setters
}
Run Code Online (Sandbox Code Playgroud)
我有一个列出用户的搜索页面,然后我点击一个用户进行编辑(userId在URL中给出).
在编辑表单中,我在服务器上存储该实体的字段,当我保存我的用户时,我这样做:
User user = entityManager.find(User.class, userId)
user.setLogin(form.getLogin());
user.setVersion(form.getVersion());
user.setUserId(form.getUserId());
entityManager.merge(user);
Run Code Online (Sandbox Code Playgroud)
题:
因此,如果我正确理解使用Hibernate的乐观锁定,如果我在浏览器中打开2个选项卡来编辑同一个用户,那么在第一个选项卡上更新登录,然后在第二个选项卡上登录,我应该有一个OptimisticLockException不应该?
实际上,这不是我的应用程序的情况...我验证,form.getVersion()在这两种情况下返回相同的值,即使在第二次更新中,user.version已经由第一次编辑更新.
我错过了什么吗?
该EntityManager生产 …
有一个实体:
@Entity
class A {
...
@Version
int version;
}
Run Code Online (Sandbox Code Playgroud)
A 实例更新以乐观的方式实现:
@Transactional(rollbackFor = {StaleStateException.class})
@Retryable(value = {StaleStateException.class})
public void updateA() {
A a = findA();
B b = new B();
// Update "a" somehow
a.update();
// "b" is saved on each retry!
save(b);
}
Run Code Online (Sandbox Code Playgroud)
如注释中所述,似乎事务在StaleStateException发生时不会回滚,因此B每次重试时都会保存实例.
是否可以在重试时回滚事务?
所需的行为b仅在成功a更新时保存.
我正在查看dynamo文档,看起来他们很乐观。我想知道这是否默认使用。从文档中看来,您需要编写Java应用程序才能使用@DynamoDBVersionAttribute批注并获取和设置版本。无需执行此操作,看起来您无需任何锁定即可写入dynamoDB。
那是对的吗?
附带一提,我对没有某种锁定的数据库不太熟悉,因此,如果2个人在DynamoDB中同时写入同一项目而没有任何锁定怎么办?假设我们要写入的项目有4个字段,一个写入会完全失败,还是dynamodb用1个写入更新2/4个字段,而用另外2个写入更新另外2个字段?
我们决定在我们的Web应用程序中使用乐观锁定,以便增加并发性,而不使用悲观锁定.
我们现在正在寻找重试解决方案.
我们希望对我们当前的代码库产生尽可能小的影响.
我们在网上看到的解决方案之一是使用带注释的重试拦截器将方法标记为可重试.
问题是我们想要注释对它们有@Transactional注释的方法,但拦截器由于某种原因无法重试它们.(拦截器完美地重试非事务方法.)
所以:
1)是否有任何替代重试对我们的代码影响最小?
2)该解决方案是否有任何文档\教程?
3)是否可以重试@Transactional注释方法?
干杯!
我正在使用乐观锁定来防止人们在比赛条件变化方面相互覆盖。
自从我将Rails从升级5.1到以来5.2,我的规范就失效了,我一直追踪到以下事实:在changes数组中,与文件上载相关的更改不再是任何Uploader元素,而是裸露的字符串。
之前:
[1] pry(#<User>)> change
=> [
[0] #<AvatarUploader:0x007fcc7117bc00 # Value before
[1] #<AvatarUploader:17bc0cc7100x997f # Current value
Run Code Online (Sandbox Code Playgroud)
现在:
[1] pry(#<User>)> change
=> [
[0] "image.jpg", # Value before
[1] "avatar.png" # Current value
]
Run Code Online (Sandbox Code Playgroud)
我怎样才能解决这个问题?
hibernate ×5
java ×4
jpa ×3
grails ×1
jboss7.x ×1
jpa-2.0 ×1
locking ×1
nhibernate ×1
spring ×1
spring-boot ×1
spring-data ×1
testing ×1
transactions ×1