简体   繁体   English

在 H2 中切换同一事务中的两个唯一字段时违反唯一约束

[英]Unique constraint violation when switching two unique fields in the same transaction in H2

I have a Spring Boot application using Spring Data repositories with entities mapped with JPA.我有一个 Spring 引导应用程序,它使用 Spring 数据存储库,其实体映射为 JPA。 The database is H2.数据库是H2。 The table is auto-generated.该表是自动生成的。 I'm doing two updates in the same transaction.我在同一个事务中进行两次更新。 Each of them would on its own would violate a unique constraint, but when both are applied together, the result should be fine.它们中的每一个都会单独违反唯一约束,但是当两者一起应用时,结果应该没问题。 However, I'm still getting an exception.但是,我仍然遇到一个例外。

I tried to do the same update with a DB tool (Database view in IntelliJ IDEA) to try to see if that would work, getting this error:我尝试使用数据库工具(IntelliJ IDEA 中的数据库视图)进行相同的更新,以尝试查看是否可行,但出现此错误:

Unexpected update count received (Actual: 0, Expected: 1). All changes will be rolled back.

This is my entity in question:这是我有问题的实体:

@Entity
@Table(
        name = "DATA_SET_COLUMN",
        uniqueConstraints = {
                @UniqueConstraint(columnNames = {"DATA_SET_ID", "ORDER_INDEX"})
        }
)
@Data
@EqualsAndHashCode(callSuper=true)
@NoArgsConstructor
@ToString(exclude = {"dataSet", "elements"})
public class DataSetColumn extends UniteFlowEntity {
    @Column(name = "ORDER_INDEX", nullable = false)
    private int order;

    @Column(name = "DATA_SET_ID", nullable = false)
    private String dataSetId;

    @ManyToOne(fetch= FetchType.LAZY)
    @JoinColumn(name="DATA_SET_ID", nullable = false, insertable = false, updatable = false)
    @JsonIgnore
    private DataSet dataSet;

    @OneToMany(mappedBy = "column", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JsonIgnore
    List<DataSetElement> elements;
}

Note the unique constraint on DATA_SET_ID and ORDER_INDEX .请注意对DATA_SET_IDORDER_INDEX的唯一约束。

I'm using a Spring Data repository for access:我正在使用 Spring 数据存储库进行访问:

@Repository
public interface DataSetColumnRepository extends JpaRepository<DataSetColumn, String> {}

Saving the entities looks something like this:保存实体如下所示:

        repository.save(entity1);
        repository.save(entity2);

I have two DataSetColumns stored with the same DATA_SET_ID and want to switch the ORDER_INDEX (the one which has 0 gets 1 and vice versa).我有两个存储有相同DATA_SET_ID的 DataSetColumns 并且想要切换ORDER_INDEX (具有 0 的那个得到 1,反之亦然)。 This happens in the same transaction (managed by Spring, as set up by Spring Boot).这发生在同一事务中(由 Spring 管理,由 Spring 引导设置)。

My expectation was that the unique constraint would not be violated since after both updates the table should be valid.我的期望是不会违反唯一约束,因为在两次更新之后表应该是有效的。 However, I'm getting this:但是,我得到了这个:

update unitelabs.data_set_column set creation_date=?, modification_date=?, data_set_id=?, order_index=? where id=? [23505-197]
    at org.h2.message.DbException.getJdbcSQLException(DbException.java:357)
    at org.h2.message.DbException.get(DbException.java:179)
    at org.h2.message.DbException.get(DbException.java:155)
    at org.h2.index.BaseIndex.getDuplicateKeyException(BaseIndex.java:101)
    at org.h2.mvstore.db.MVSecondaryIndex.requireUnique(MVSecondaryIndex.java:236)
    at org.h2.mvstore.db.MVSecondaryIndex.add(MVSecondaryIndex.java:202)
    at org.h2.mvstore.db.MVTable.addRow(MVTable.java:732)
    at org.h2.table.Table.updateRows(Table.java:509)
    at org.h2.command.dml.Update.update(Update.java:177)
    at org.h2.command.CommandContainer.update(CommandContainer.java:102)
    at org.h2.command.Command.executeUpdate(Command.java:261)
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:199)
    at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:153)
    at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
    at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
    at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3356)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3229)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3630)
    at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:146)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98)
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:532)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at uniteflow.dataset.api.rest.DataSetApi$$EnhancerBySpringCGLIB$$839b47f6.saveColumns(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:189)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:800)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1038)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908)

Is my expectation wrong and this doesn't work in principle?我的期望是错误的吗?这在原则上是行不通的? Or could there be something wrong in my code?还是我的代码有问题?

Your expectation is wrong, to allow such modification the unique constraint should be explicitly defined as deferred (in databases that support optional feature F721) and H2 currently (as of 1.4.199) does not support this feature, there is a feature request for it: https://github.com/h2database/h2database/issues/223您的期望是错误的,为了允许这样的修改,唯一约束应该明确定义为延迟(在支持可选功能 F721 的数据库中)并且 H2 当前(截至 1.4.199)不支持此功能,有一个功能请求: https://github.com/h2database/h2database/issues/223

The typical workaround is to assign a some fake value to the first row, then change the second row to its new value and finally change the first row to its new value.典型的解决方法是为第一行分配一个假值,然后将第二行更改为其新值,最后将第一行更改为其新值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 带有H2数据库的JUnit:为多个数据添加多语言服务时的唯一索引或主键冲突 - JUnit with H2 Database : Unique index or primary key violation when adding multilingual services for multiple data 在两个非空字段上添加唯一约束 - Add unique constraint on two not null fields H2参照完整性约束违反 - H2 Referential integrity constraint violation 违反UNIQUE KEY约束的休眠状态 - Hibernate Violation of UNIQUE KEY constraint 在Hibernate中使用SEQUENCE时,是什么导致唯一约束冲突? - What is causing a unique constraint violation when using a SEQUENCE in Hibernate? 使用JPA唯一约束丢失交易? - Lost transaction with JPA unique constraint? 违反参照完整性约束:删除 Hibernate 中的实体时(memory DBMS 中的 H2) - Referential integrity constraint violation: when deleting Entity in Hibernate (H2 in memory DBMS) 完整性约束违规:唯一约束或索引违规 HSQLDB - Integrity constraint violation: unique constraint or index violation HSQLDB 更新和/或删除时违反 Hibernate H2 参照完整性约束 - Hibernate H2 Referential Integrity Constraint Violation on Update and/or Remove Hibernate / H2 @OneToMany移除子代时违反“参照完整性约束”? - Hibernate/H2 @OneToMany “Referential integrity constraint violation” on remove of child?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM