您好我已经创建了一个实现版本概念的示例程序。当我通过方法1更新记录时工作正常意味着首先从DB加载记录然后使用transaction.commit()更新记录(不调用update( )) 但是当我尝试通过手动调用update()更新记录时,我得到了上述错误。意味着创建了同样的bean对象,其id已经存在于DB中
以下是我的代码
在这种情况下,版本正常更新,没有问题 。
Student s = (Student) session.load(Student.class, new Integer(101));
System.out.println("Db has not touched yet");
s.setName("rakesh update11");
transaction.commit();
System.out.println("record updated successfully")
在这种情况下,它的投掷错误
Student student = new Student();
student.setRollNo(101);
student.setName("rakesh updated");
student.setEmail("rkbnew@gmail.com");
session.update(student);
transaction.commit();
答案 0 :(得分:1)
Hibernate通过更新版本列(递增编号或时间戳)并将该列的预期当前值添加到语句的WHERE子句来实现optimistic locking。
等同于以下内容:
UPDATE student
SET name = 'rakesh updated',
version = version + 1,
... other columns omitted
WHERE roll_no = 101
AND version = 1;
Hibernate希望在这种情况下更新1行。如果更新的行数不是1,则会推断该行(特别是版本)已被另一个事务更新并抛出StaleObjectStateException。
在您给出的第一个示例中,将从数据库加载Student,以便使用数据库中的当前值填充版本列。该值将添加到update语句的WHERE
子句中。
但是,在第二个示例中,创建了一个新的Student实例,但未显式设置版本列,因此它将是该字段的默认值,大概为0或null(取决于您实现它的方式)
例如,如果数据库中版本列的当前值为1,但新创建的Student实例中的默认值为0,则生成的sql将实际为
UPDATE student
SET name = 'rakesh updated',
version = version + 1,
... other columns omitted
WHERE roll_no = 101
AND version = 0; -- <-- doesn't match the current version in the db!!
因此不会更新任何行并抛出StaleObjectStateException。
为了解决这个问题,你需要
对于选项2,在尝试对新实例执行更新之前,您需要使用session.evict()
从会话中删除托管实体,否则您可能会获得NonUniqueObjectException。