java - Spring Data 未更新最新数据

标签 java mysql sql spring spring-data-jpa

我的 SQL 表中有一个字段需要更新 1 并返回一个唯一的 ID。但看起来它没有更新最新数据,特别是当我发出很多请求时。

@Transactional
public interface CompanyRepository extends CrudRepository<Company, Integer> {    
    @Modifying(clearAutomatically = true, flushAutomatically = true)
    @Query(value = "update Company c set c.accessId = :accessId WHERE c.id = :companyId AND c.accessId = :oldAccessId", nativeQuery = true)
    int updateAccessId(@Param("companyId") Integer companyId, @Param("accessId") Integer accessId, @Param("oldAccessId") Integer oldAccessId);
}

即使将clearAutomatically 和flushAutomatically 设置为true,它也无法处理最新数据。

我可以看到两个更新查询都成功,并且 oldAccessId 相同。

表格设计是否应该改变?

PS:我也尝试过不使用nativeQuery = true。

最佳答案

这里是一个经典的竞争条件。

两个线程读取具有相同 accessId 的同一实体,将其加一,然后使用您在问题中显示的方法写入结果。结果实际上只有一次更新。

有多种方法可以解决此问题。

  1. 使用 JPA 和乐观锁定。

    假设您有一个带有 @Version 注释的属性,您可以执行以下操作 以下为单一交易方法:

    1. 加载实体。
    2. 增加accessId
    3. 保留实体。

    如果另一个事务尝试在同一实体上执行相同的操作,则两者之一将出现异常。在这种情况下,请重试,直到更新完成。

  2. 使用数据库。

    使数据库中的读取和更新成为原子操作。不要将新值作为参数传递,而是使用如下查询:

    update Company c 
    set c.accessId = c.accessId + 1 
    WHERE c.id = :companyId 
    
  3. 将其设为版本属性。

    如上所述,JPA 已经具有 @Version 属性,这些属性会在每次更改时更新。根据具体要求,您可以将 accessId 设置为该属性并自动更新。

  4. 检查是否有任何行已更新。

    根据您的评论,您的意图是基本上重新实现 JPA 对版本属性的操作。如果您这样做,您就会错过一个关键部分:通过将返回值与 1 进行比较来检查更新是否实际更新了任何内容。

关于java - Spring Data 未更新最新数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53274785/

相关文章:

java - 无法使用 Rome API 从提要中读取图像 URL

java - 如何将 Java 桌面应用程序连接到在线数据库

查询 IS NULL 时 MySQL 返回最后插入

mysql - SQL查询比较一列中的多个数据

java - Jooq 在 sqlite 上存储后不返回主键

mysql - SQL:创建多列搜索查询

java - 我可以在 OrientDB 上查询期间访问对象的集群名称吗?

java - 如何使用 32 位 Java 8 嵌入式 JRE 访问 64 位 JNI 库

php - 列 'custID' 不能为空

java - 如何解码 Java 中的 logonHours 属性