PESSIMISTIC LOCK 不适用于 Spring 数据访问 MySQL
PESSIMESTIC LOCK is not working with Spring Data accessing MySQL
我正在使用 Spring Boot 构建计划作业数据处理应用程序。主要逻辑将在一个计划的作业中,该作业获取一批记录并处理它们。我应该是 运行 2 个应用程序实例,不应该两次选择相同的记录。我尝试使用 PESSIMISTIC LOCK with NO WAIT 来解决任何记录选择冲突。
事情没有按预期工作。两个实例都选择了相同的记录,尽管我期望只有一个实例锁定并处理一些记录,而另一个实例跳过第一个实例锁定的记录。
Spring启动版本:2.2.4.RELEASE
数据库:MySQl
首先我尝试使用@Lock 和@QueryHint 注释:
@Lock(value = LockModeType.PESSIMISTIC_WRITE) // adds 'FOR UPDATE' statement
@QueryHints(value={@QueryHint(name = "javax.persistence.lock.timeout", value = LockOptions.SKIP_LOCKED+"")})
Page<Transaction> findByStatus(String status, Pageable pageable);
即使使用 WAIT_FOREVER,行为也没有变化,就好像 @QueryHints 被完全忽略了一样。
我尝试的另一个选项是使用 NativeQuery:
@Query(value ="select * from transaction t where t.status = ?1 limit ?2 for update SKIP LOCKED",
countQuery="select count(*) from transaction t where t.status = ?1",
nativeQuery = true)
List<Transaction> findByStatusNQ(String status, Integer pageSize);
同样的行为。没有锁定,两个应用程序实例都在选择同一组数据
这是定义的实体:
@Entity
public class Transaction {
@Id
private Long id;
private String description;
private String status;
private String managedBy;
@Temporal(TemporalType.TIMESTAMP)
private Date manageDate;
...
}
调用方服务组件使用@Transactional 注释以强制为每次执行创建新事务:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public List<Transaction> updateTrxStatus(String oldStatus,String newStatus){
List<Transaction> trxs = this.executeUsingNQ(oldStatus);
if(trxs.size()>0) {
logger.info( "Start updating Data");
trxs.forEach(transaction -> {
transaction.setStatus(newStatus);
transaction.setManagedBy(instanceName);
transaction.setManageDate(new Date(System.currentTimeMillis()));
});
}else{
logger.info(" Nothing to process");
}
return trxs;
}
@Transactional(propagation = Propagation.REQUIRED)
public List<Transaction> executeUsingNQ(String oldStatus){
List<Transaction> trxs = trxRepo.findByStatusNQ(oldStatus,2);
return trxs;
}
@Transactional(propagation = Propagation.REQUIRED)
public List<Transaction> executeWithPage(String oldStatus){
Pageable firstPageWithTwoElements = PageRequest.of(0, 2);
Page<Transaction> trxs = trxRepo.findByStatus(oldStatus, firstPageWithTwoElements);
return trxs.getContent();
}
希望有人能帮助确定是否存在编码问题或缺少配置!!!!
据说这个问题是由于 MySql 使用不正确的方言引起的。该版本的 Dialect "MySQLDialect" 在创建表时假定 "MyISAMStorageEngine" 作为默认存储引擎。该引擎不支持任何类型的交易。
唯一支持事务的存储引擎是 "InnoDB",当使用 "MySQL55Dialect"、"MySQL57Dialect" 或 "MySQL8Dialect"
等其他方言时,它被选为默认选择
我正在使用 Spring Boot 构建计划作业数据处理应用程序。主要逻辑将在一个计划的作业中,该作业获取一批记录并处理它们。我应该是 运行 2 个应用程序实例,不应该两次选择相同的记录。我尝试使用 PESSIMISTIC LOCK with NO WAIT 来解决任何记录选择冲突。 事情没有按预期工作。两个实例都选择了相同的记录,尽管我期望只有一个实例锁定并处理一些记录,而另一个实例跳过第一个实例锁定的记录。 Spring启动版本:2.2.4.RELEASE
数据库:MySQl
首先我尝试使用@Lock 和@QueryHint 注释:
@Lock(value = LockModeType.PESSIMISTIC_WRITE) // adds 'FOR UPDATE' statement
@QueryHints(value={@QueryHint(name = "javax.persistence.lock.timeout", value = LockOptions.SKIP_LOCKED+"")})
Page<Transaction> findByStatus(String status, Pageable pageable);
即使使用 WAIT_FOREVER,行为也没有变化,就好像 @QueryHints 被完全忽略了一样。 我尝试的另一个选项是使用 NativeQuery:
@Query(value ="select * from transaction t where t.status = ?1 limit ?2 for update SKIP LOCKED",
countQuery="select count(*) from transaction t where t.status = ?1",
nativeQuery = true)
List<Transaction> findByStatusNQ(String status, Integer pageSize);
同样的行为。没有锁定,两个应用程序实例都在选择同一组数据 这是定义的实体:
@Entity
public class Transaction {
@Id
private Long id;
private String description;
private String status;
private String managedBy;
@Temporal(TemporalType.TIMESTAMP)
private Date manageDate;
...
}
调用方服务组件使用@Transactional 注释以强制为每次执行创建新事务:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public List<Transaction> updateTrxStatus(String oldStatus,String newStatus){
List<Transaction> trxs = this.executeUsingNQ(oldStatus);
if(trxs.size()>0) {
logger.info( "Start updating Data");
trxs.forEach(transaction -> {
transaction.setStatus(newStatus);
transaction.setManagedBy(instanceName);
transaction.setManageDate(new Date(System.currentTimeMillis()));
});
}else{
logger.info(" Nothing to process");
}
return trxs;
}
@Transactional(propagation = Propagation.REQUIRED)
public List<Transaction> executeUsingNQ(String oldStatus){
List<Transaction> trxs = trxRepo.findByStatusNQ(oldStatus,2);
return trxs;
}
@Transactional(propagation = Propagation.REQUIRED)
public List<Transaction> executeWithPage(String oldStatus){
Pageable firstPageWithTwoElements = PageRequest.of(0, 2);
Page<Transaction> trxs = trxRepo.findByStatus(oldStatus, firstPageWithTwoElements);
return trxs.getContent();
}
希望有人能帮助确定是否存在编码问题或缺少配置!!!!
据说这个问题是由于 MySql 使用不正确的方言引起的。该版本的 Dialect "MySQLDialect" 在创建表时假定 "MyISAMStorageEngine" 作为默认存储引擎。该引擎不支持任何类型的交易。 唯一支持事务的存储引擎是 "InnoDB",当使用 "MySQL55Dialect"、"MySQL57Dialect" 或 "MySQL8Dialect"
等其他方言时,它被选为默认选择