Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用springjpa/Hibernate进行条件插入_Java_Hibernate_Jpa_Orm_Spring Data Jpa - Fatal编程技术网

Java 使用springjpa/Hibernate进行条件插入

Java 使用springjpa/Hibernate进行条件插入,java,hibernate,jpa,orm,spring-data-jpa,Java,Hibernate,Jpa,Orm,Spring Data Jpa,我正在从事一个在集群环境中运行的项目,其中有许多节点和一个数据库。该项目使用Spring数据JPA1.9.0和Hibernate 5.0.1。我在解决如何防止重复行问题时遇到问题 举个例子,这里有一个简单的表 @Entity @Table(name = "scheduled_updates") public class ScheduledUpdateData { public enum UpdateType { TYPE_A, TYPE_B }

我正在从事一个在集群环境中运行的项目,其中有许多节点和一个数据库。该项目使用Spring数据JPA1.9.0和Hibernate 5.0.1。我在解决如何防止重复行问题时遇到问题

举个例子,这里有一个简单的表

@Entity
@Table(name = "scheduled_updates")
public class ScheduledUpdateData {
    public enum UpdateType {
        TYPE_A,
        TYPE_B
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private UUID id;

    @Column(name = "type", nullable = false)
    @Enumerated(EnumType.STRING)
    private UpdateType type;

    @Column(name = "source", nullable = false)
    private UUID source;
}
重要的一点是,存在一个唯一类型的源约束

当然,匹配示例存储库:

@Repository
public class ScheduledUpdateRepository implements JpaRepository<ScheduledUpdateData, UUID> {
    ScheduledUpdateData findOneByTypeAndSource(final UpdateType type, final UUID source);

    //...
}
本例的思想是,系统的某些部分可以插入行,以便为周期性运行的内容进行调度,在所述运行之间可以进行任意次数的调度。当某个东西实际运行时,它不必担心在同一个东西上运行两次

如何编写将有条件地插入此表的服务方法?我尝试过的一些不起作用的事情是:

Find>Act-服务方法将使用存储库查看条目是否已经存在,然后根据需要更新找到的条目或保存新条目。这是行不通的。 如果失败,请尝试插入>更新-服务方法将尝试插入,捕获由于唯一约束导致的异常,然后执行更新。这不起作用,因为事务将已经处于回滚状态,并且无法在其中执行进一步的操作。 插入到的本机查询。。。如果不存在…*-存储库有一个新的本机查询:

@Repository
public class ScheduledUpdateRepository implements JpaRepository<ScheduledUpdateData, UUID> {
    // ...

    @Modifying
    @Query(nativeQuery = true, value = "INSERT INTO scheduled_updates (type, source)" +
                                       " SELECT :type, :src" +
                                       " WHERE NOT EXISTS (SELECT * FROM scheduled_updates WHERE type = :type AND source = :src)")
    void insertUniquely(@Param("type") final String type, @Param("src") final UUID source);
}
不幸的是,这也不起作用,因为Hibernate似乎首先自己执行WHERE子句使用的SELECT,这意味着最终会尝试多个插入,从而导致唯一的约束冲突

我肯定不知道JTA、JPA或Hibernate有多少更好的优点。关于如何在多个JVM中插入具有唯一约束的表(不仅仅是主键)有什么建议吗

编辑2016-02-02
使用Postgres 2.3作为数据库,尝试使用隔离级别可序列化-遗憾的是,这本身仍然会导致违反约束的异常。

Hibernate及其查询语言支持insert语句。因此,您实际上可以使用HQL编写该查询。有关更多信息,请参见此处

这听起来像是一个突发事件,可以按建议处理

Find>Act-服务方法将使用存储库查看条目是否已经存在,然后根据需要更新找到的条目或保存新条目。这是行不通的

为什么这不起作用

你考虑过乐观锁定吗

这两个职位可能会有所帮助:


您正在尝试确保一次只能有一个节点执行此操作。 实现这一点的最好或至少最不依赖DB的方法是使用“锁”表。 此表将有一行,并将充当信号量以确保串行访问

确保此方法包装在事务中

// this line will block if any other thread already has a lock
// until that thread's transaction commits
Lock lock = entityManager.find(Lock.class, Lock.ID, LockModeType.PESSIMISTIC_WRITE);

// just some change to the row, it doesn't matter what
lock.setDateUpdated(new Timestamp(System.currentTimeMillis()));  
entityManager.merge(lock);
entityManager.flush();

// find your entity by unique constraint
// if it exists, update it
// if it doesn't, insert it

尝试将@version注释添加到实体中,将version字段添加到表中。第二次重试整个事务,并进行更新,而不是插入。@sky\u light遗憾的是@version没有帮助,由于错误发生在两个事务认为行不存在时。@DraganBozanovic在整个项目中,一个事务可能正在更新多个表,其中任何一个或所有表都可能有唯一的约束,因此,重试整个事务听起来需要在现有@Services之上引入一个全新的框架层-这似乎不正确如果serviceA在事务中运行,并调用在其自身事务中运行的serviceB,即use REQUIRES_new,那么您可以在serviceA中捕获serviceB引发的异常,这不会回滚服务A。虽然这在理论上可以回答问题,但在此处包含答案的基本部分,并提供链接以供参考。如果存在,所有这些都无法解决更新问题。锁定仅对单个记录有效。如果在初始查询时记录还不存在,则没有要锁定的内容。可以锁定整个表,但这会造成严重的性能瓶颈。更好的方法是在数据库中创建一个单记录锁表,并将其用作信号量。详情请参阅我的答复。