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"

等其他方言时,它被选为默认选择