我得到以下hibernate错误.我能够识别导致问题的功能.不幸的是,函数中有几个DB调用.我无法找到导致问题的行,因为hibernate会在事务结束时刷新会话.下面提到的hibernate错误看起来像是一般错误.它甚至没有提到哪个Bean导致了这个问题.有谁熟悉这个hibernate错误?
org.hibernate.StaleStateException: Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
        at org.hibernate.jdbc.BatchingBatcher.checkRowCount(BatchingBatcher.java:93)
        at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:79)
        at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:58)
        at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:195)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
        at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
        at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:297)
        at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
        at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:985)
        at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:333)
        at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
        at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:584)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransacti
onManager.java:500)
        at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManag
er.java:473)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.doCommitTransactionAfterReturning(Transaction
AspectSupport.java:267)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:106)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
shr*_*yas 62
我删除了一个根本不存在的记录时遇到了同样的异常.因此,检查您正在更新的记录/删除实际存在于DB中
ben*_*y23 54
如果没有代码和映射进行交易,那么几乎不可能调查问题.
但是,要更好地处理导致问题的原因,请尝试以下操作:
希望有所帮助.
小智 49
解决方案:在对id属性的Hibernate映射文件,如果你使用任何发生器类,该属性你不应该使用setter方法设置的值作了明确规定.
如果明确设置Id属性的值,则会导致上述错误.检查这一点以避免此错误.或者在映射文件中提到字段生成器="native"或"incremental"并且在DATABASE中映射的表不是auto_incremented时显示错误解决方法:转到数据库并更新表以设置auto_increment
Chr*_*dam 17
当我为某些对象分配特定ID(测试)时,偶然发生了这种情况,然后我试图将它们保存在数据库中.问题是在数据库中有一个特定的策略来设置对象的ID.只是不,如果你有在休眠水平的策略分配一个ID.
Ser*_*ema 11
就我而言,我在两个类似的案例中遇到了这个例外:
@Transactional我注释的方法中,我调用了另一个服务(响应时间很长).该方法更新实体的某些属性(在方法之后,实体仍然存在于数据库中).如果用户第二次从事务方法退出时请求方法的两次(因为他认为第一次不起作用),Hibernate会尝试更新已经从事务开始时改变其状态的实体.由于Hibernate在状态中搜索实体,并且找到了相同的实体但已经被第一个请求更改,因此它会抛出异常,因为它无法更新实体.这就像GIT中的冲突.结论:就我而言,这不是代码中可以找到的问题.当Hibernate发现在当前事务期间首次从数据库中获取的实体发生更改时抛出此异常,因此它无法将其刷新到数据库,因为Hibernate不知道哪个是实体的正确版本:当前版本事务提取开始; 或者已经存储在数据库中的那个.
解决方案:要解决问题,您必须使用Hibernate LockMode来找到最符合您要求的那个.
Pet*_*ler 10
我的两分钱。
问题:OptimisticLockException在 Spring Boot 2.7.1 中,h2 数据库版本已更改为 v2.1.214,这可能会导致在使用 Id 列生成的 UUID 时抛出异常,请参阅https://hibernate.atlassian.net/browse/HHH-15373。
解决办法:添加columnDefinition="UUID"注释@Column
例如,实体的主键定义如下:
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
@Column(name = COLUMN_UUID, updatable = false, nullable = false)
UUID uUID;
将列注释更改为:
@Column(name = COLUMN_UUID, updatable = false, nullable = false, columnDefinition="UUID")
当触发器执行影响行计数的其他DML(数据修改)查询时,可能会发生这种情况.我的解决方案是在触发器的顶部添加以下内容:
SET NOCOUNT ON;
在 Hibernate 5.4.1 之前,乐观锁定失败异常(例如,StaleStateExceptionor OptimisticLockException)不包括失败语句。
该HHH-12878的创建问题,以提高休眠,从而引发乐观锁定异常的情况下,JDBCPreparedStatement实现登录,以及:
if ( expectedRowCount > rowCount ) {
    throw new StaleStateException(
            "Batch update returned unexpected row count from update ["
                    + batchPosition + "]; actual row count: " + rowCount
                    + "; expected: " + expectedRowCount + "; statement executed: "
                    + statement
    );
}
我
BatchingOptimisticLockingTest在我的高性能 Java 持久性 GitHub 存储库中创建了来演示新行为的工作原理。
首先,我们将定义一个Post定义@Version属性的实体,从而启用隐式乐观锁定机制:
@Entity(name = "Post")
@Table(name = "post")
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Long id;
    private String title;
    @Version
    private short version;
    public Long getId() {
        return id;
    }
    public Post setId(Long id) {
        this.id = id;
        return this;
    }
    public String getTitle() {
        return title;
    }
    public Post setTitle(String title) {
        this.title = title;
        return this;
    }
    public short getVersion() {
        return version;
    }
}
我们将使用以下 3 个配置属性启用 JDBC 批处理:
properties.put("hibernate.jdbc.batch_size", "5");
properties.put("hibernate.order_inserts", "true");
properties.put("hibernate.order_updates", "true");
我们将创建 3 个Post实体:
doInJPA(entityManager -> {
    for (int i = 1; i <= 3; i++) {
        entityManager.persist(
            new Post()
                .setTitle(String.format("Post no. %d", i))
        );
    }
});
并且 Hibernate 会执行一次 JDBC 批量插入:
SELECT nextval ('hibernate_sequence')
SELECT nextval ('hibernate_sequence')
SELECT nextval ('hibernate_sequence')
Query: [
    INSERT INTO post (title, version, id) 
    VALUES (?, ?, ?)
], 
Params:[
    (Post no. 1, 0, 1), 
    (Post no. 2, 0, 2), 
    (Post no. 3, 0, 3)
]
所以,我们知道 JDBC 批处理工作得很好。
现在,让我们复制乐观锁问题:
doInJPA(entityManager -> {
    List<Post> posts = entityManager.createQuery("""
        select p 
        from Post p
        """, Post.class)
    .getResultList();
    posts.forEach(
        post -> post.setTitle(
            post.getTitle() + " - 2nd edition"
        )
    );
    executeSync(
        () -> doInJPA(_entityManager -> {
            Post post = _entityManager.createQuery("""
                select p 
                from Post p
                order by p.id
                """, Post.class)
            .setMaxResults(1)
            .getSingleResult();
            post.setTitle(post.getTitle() + " - corrected");
        })
    );
});
第一个事务选择所有Post实体并修改title属性。
然而,在第一个EntityManager被刷新之前,我们将使用该executeSync方法执行第二个转换。
第二个事务修改了第一个Post,所以它version会增加:
Query:[
    UPDATE 
        post 
    SET 
        title = ?, 
        version = ? 
    WHERE 
        id = ? AND 
        version = ?
], 
Params:[
    ('Post no. 1 - corrected', 1, 1, 0)
]
现在,当第一个事务尝试刷新 时EntityManager,我们将得到OptimisticLockException:
Query:[
    UPDATE 
        post 
    SET 
        title = ?, 
        version = ? 
    WHERE 
        id = ? AND 
        version = ?
], 
Params:[
    ('Post no. 1 - 2nd edition', 1, 1, 0), 
    ('Post no. 2 - 2nd edition', 1, 2, 0), 
    ('Post no. 3 - 2nd edition', 1, 3, 0)
]
o.h.e.j.b.i.AbstractBatchImpl - HHH000010: On release of batch it still contained JDBC statements
o.h.e.j.b.i.BatchingBatch - HHH000315: Exception executing batch [
    org.hibernate.StaleStateException: 
    Batch update returned unexpected row count from update [0]; 
    actual row count: 0; 
    expected: 1; 
    statement executed: 
        PgPreparedStatement [
            update post set title='Post no. 3 - 2nd edition', version=1 where id=3 and version=0
        ]
], 
SQL: update post set title=?, version=? where id=? and version=?
因此,您需要升级到 Hibernate 5.4.1 或更新版本才能从这项改进中受益。
我面临同样的问题.代码在测试环境中工作.但它不适用于临时环境.
org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1
问题是表在测试DB表中的每个主键都有单个条目.但是在暂存数据库中,同一个主键有多个条目.(问题是在暂存数据库中,表没有任何主键约束,也有多个条目.)
所以每次更新操作都会失败.它尝试更新单个记录并期望将更新计数设置为1.但由于表中有3条记录用于相同的主键,结果更新计数找到3.因为预期的更新计数和实际结果更新计数不匹配,它抛出异常并回滚.
在我删除了所有具有重复主键并添加了主键约束的记录之后.它工作正常.
Hibernate - Batch update returned unexpected row count from update: 0 actual row count: 0 expected: 1
实际行数:0 //表示没有找到更新
更新的记录:0 //表示没有找到记录,因此没有
预期的更新:1 //表示预期至少有1条带有db表中的键的记录.  
这里的问题是查询试图更新一些密钥的记录,但是hibernate没有找到任何带密钥的记录.
正如朱利叶斯所说,当更新发生在其子项被删除的对象上时,就会发生这种情况。(可能是因为需要更新整个父对象,有时我们更喜欢删除子对象并将它们重新插入父对象(新的、旧的无关紧要)以及父对象可能对任何对象进行的任何其他更新它的其他普通字段)所以......为了使其工作通过调用删除子项(在事务内)childrenList.clear()(不要循环遍历子项并使用一些childDAO.delete(childrenList.get(i).delete()))和设置 
删除每个子项@OneToMany(cascade = CascadeType.XXX ,orphanRemoval=true)在父对象的一侧。然后更新父亲(fatherDAO.update(father))。(对每个父亲对象重复)结果是孩子们与父亲的联系被剥夺,然后他们作为孤儿被框架移除。
小智 5
我遇到了这个问题,我们有一对多的关系.
在master的hibernate hbm映射文件中,对于具有set类型排列的对象,添加cascade="save-update"并且它工作正常.
如果没有这个,默认情况下,hibernate会尝试更新不存在的记录,并通过这样做来插入.