我正在经历一种似乎是连续(而不是并发)数据库操作之间的记录锁定的情况,我无法解释。
情况
方法 saveRegistrationToken
从rest控制器调用。我通过postman(http客户机)测试对方法的调用;方法不会在其他任何地方调用,这是唯一执行的操作。
方法执行的行为应该如下所示:
以字符串(注册令牌)和用户id(也是字符串)作为输入
它应该首先更新一个users表,将registration\u token列的值设置为null,以便该列的值与输入的registration token的值相同
然后,它应该用指定的用户id更新该行的users表,将registration\u token列的值设置为input registration token。
问题
该方法的每次第一次执行都将按预期进行:将db column registration\u token(table user)的值设置为null(无论指定值在哪里),然后将registration token设置为具有输入用户id的行的输入值。因此,所讨论行的注册令牌的值是方法执行结束时的输入值。
每第二次执行将正确地执行第一步(“作废”注册令牌,无论其存在何处),但不会使用指定的用户id更新行的值。因此,在方法执行结束时,所讨论行的注册令牌的值为null。
defaultuserservice.java文件
@Override
public void saveRegistrationToken(String userId, String registrationToken) {
usersRepository.voidRegistrationToken(registrationToken);
User u = usersRepository.findById(userId).get();
u.setRegistrationToken(registrationToken);
usersRepository.save(u);
}
usersrepository.java文件
@Repository
public interface UsersRepository extends JpaRepository<User, String> {
@Modifying
@Transactional
@Query(value = "UPDATE USERS " +
"SET registration_token = null " +
"WHERE registration_token = :registration_token",
nativeQuery = true)
void voidRegistrationToken(@Param("registration_token") String registrationToken);
}
用户.java
@Entity(name = "users")
@AllArgsConstructor //lombok
@Data
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class User {
@Id
private String id;
private String registrationToken;
private String email;
}
我试过的
我最初认为这将是一个刷新问题:一旦注册令牌被设置为空,事务将不会被刷新,直到注册令牌被再次设置为用户id之后,导致两个db操作之间的行为冲突。我反驳了 usersRepository.flush();
第一次手术后,观察相同的行为。
我在存储库操作上尝试了不同的传播和隔离级别: @Transactional(propagation = Propagation.SUPPORTS, isolation = Isolation.READ_UNCOMMITTED)
,这没用。
我尝试在存储库操作上显式设置刷新模式: @QueryHints(value = { @QueryHint(name = org.hibernate.annotations.QueryHints.FLUSH_MODE, value = "ALWAYS") })
,这并没有改变什么。
在我看来,第一个操作“锁定”了更新后的记录,这会阻止第二个操作更新它,但我不明白怎么做。
显式指定auto commit true: spring.datasource.auto-commit=true
依赖项: compile("org.springframework.boot:spring-boot-starter-data-jpa")
有效版本2.1.1.1发布
任何想法,解释,链接到文件将不胜感激-我已经尝试了一切我能想到的。
非常感谢,克里斯
暂无答案!
目前还没有任何答案,快来回答吧!