hibernate中的事务提交

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hibernate中的事务提交相关的知识,希望对你有一定的参考价值。

请问各位为什么我的事务commit的时候就报错 identifier of an instance of....,我查了网上的一些信息,说是更新的时候出了不同的id。但我这是查询语句,并没有保存更新啊。
userName不是主键。

以下是部分代码:
tx = session.beginTransaction();
Query query = session.createQuery("from Player p where p.userName=?");
query.setString(0, name);
playerlist = query.list();

if (playerlist.size()>0)
for (int i = 0; i < playerlist.size(); i++)
player = (Player)playerlist.get(i);


tx.commit();
谢谢你的回答,player 确实有值,是从数据库读出来的。我试过把player = (Player)playerlist.get(i)去掉,只留下i如下代码:tx = session.beginTransaction();
Query query = session.createQuery("from Player p where p.userName=?");
query.setString(0, name);
playerlist = query.list();
tx.commit();

但同样报这个错误,不知为什么。好像我只要掉用query的方法就出错。

查看该部分代码,推测可能是player = (Player)playerlist.get(i); 出现了问题;
如果player在上面的代码中是不为null,并且该对象的数据是保存到数据库过的,也就是进行了持久化的。由于hibernate使用缓存,player = (Player)playerlist.get(i);也就是重新给之前持久化过的实例player进行了赋值,player进行了更新,更新操作会在事务中提交。而此处多次循环赋值,并且都是已经保存过的数据,所以id肯定是重复的,也就报错了。

针对调用Query方法出错,是不是可能导包的时候弄错了,请确认导入的Query类是否为org.hibernate.Query;追问

导入的确实是org.hibernate.Query类。不过,现在我把它改成不用事务提交的了,直接查询,不用事务了。

追答

如果导包正确了,还出错比较奇怪。
查询,不用事务控制,不影响使用,因为不涉及数据库数据修改,不需要在错误时回滚数据。

参考技术A hibernate在进行事物持久化时候,你要使用sesison.close();在确定你是单表的查询时候,要在每次查询sql语句时候,将sql关闭,这样在缓存才能类似,数据库使用(oracle中)commit;sqlserver中使用执行一样,这样才能将数据库和你页面调用同步!

Hibernate 如何在提交事务之前对 Optimistic Locking 进行行版本检查

【中文标题】Hibernate 如何在提交事务之前对 Optimistic Locking 进行行版本检查【英文标题】:How does Hibernate do row version check for Optimistic Locking before committing the transaction 【发布时间】:2019-03-30 00:11:37 【问题描述】:

当在提交当前事务之前休眠检查行的版本,它应该发出一个 sql select 语句来获取它。

假设在发出select 语句后休眠发现行版本没有改变,因此它应该继续提交事务。

我想知道 hibernate 如何确保在选择行和提交当前事务之间的时间段内没有任何其他事务会更新该行以更改其版本号? hibernate 唯一可能做的事情似乎是使用Select ... For Update 进行悲观锁定的行版本选择或具有这样一个隔离级别的事务,它将锁定正在读取的行。

如果我的想法是真的:

那么休眠乐观锁确实使用悲观锁来进行操作,尽管该悲观锁的持有时间很短,因为此后事务将立即提交。

否则,我们在行版本检查和提交之间的时间间隔很短,可能会出现竞争条件。

请分享你的想法。

【问题讨论】:

【参考方案1】:

对于默认的乐观锁机制,@Version 注解给出的机制,没有这种风险。

乐观锁定不需要任何额外的 SELECT 来获取和检查实体修改后的版本。因此,涉及两个步骤:

    从数据库中获取实体及其版本:

     SELECT * FROM PRODUCT WHERE ID = 1;
    

    UPDATE 或 DELETE 将使用获取实体的同一 SELECT 获取的版本:

     UPDATE PRODUCT SET (LIKES, QUANTITY, VERSION) = (5, 10, 3) 
     WHERE ID = 1 AND VERSION = 2;
    

因此,Hibernate 不会检查实体版本。数据库使用 WHERE 子句对其进行检查。

Hibernate 只检查PreparedStatement.executeUpdate 方法调用的updateCount 结果。如果计数不是updateCount,则表示该行已被删除或版本已更改,这意味着我们使用的是陈旧数据,因此将抛出OptimisticLockException

因此,默认的基于@Version 的乐观锁定不会发生冲突,因为一条记录一次只能被一个事务修改,并且一旦该行被修改锁定,锁定将一直保留到事务提交或回滚。

只有显式的LockModeType.OPTIMISTIC 才能导致竞争条件。不过,您可以轻松fix that using a pessimistic shared or explicit lock。

【讨论】:

以上是关于hibernate中的事务提交的主要内容,如果未能解决你的问题,请参考以下文章

无法提交 Hibernate 事务;嵌套异常是 org.hibernate.Transaction 异常:JDBC 提交失败

Hibernate 事务提交和事务回滚

Hibernate事务以及一级缓存02

Spring对Hibernate事务管理

Hibernate中的事务与并发

spring与hibernate整合事务管理的理解