我的sql表中有一个字段,需要更新一个字段并返回一个唯一的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都是相同的。
table的设计应该改变吗?
ps:我也尝试过没有nativequery=true。
1条答案
按热度按时间kh212irz1#
这里有一个经典的竞赛条件。
两个线程读取相同的实体,具有相同的
accessId
,将其增量为1,然后使用问题中显示的方法编写结果。结果实际上只有一个更新。有多种方法可以解决这个问题。
使用jpa和乐观锁。
假设你有一个属性
@Version
注解:您可以在单个事务方法中执行以下操作:加载实体。
增加
accessId
.持久化实体。
如果另一个事务试图对同一个实体执行相同的操作,那么这两个事务中的一个将得到异常。在这种情况下,请重试,直到更新完成。
使用数据库。
使数据库中的读取和更新成为原子的。不要将新值作为参数传递,而是使用如下查询:
使其成为版本属性。
如上所述,jpa已经
@Version
每次更改都会更新的属性。取决于您可能提出的确切要求accessId
只需输入该属性并自动更新即可。检查是否更新了任何行。
根据您的评论,您的意图是基本上重新实现jpa对版本属性的处理。如果您这样做,您将缺少一个关键部分:通过比较返回值和1,检查更新是否实际更新了任何内容。