当前位置: 首页 > 知识库问答 >
问题:

悲观锁不工作Spring引导数据JPA

万选
2023-03-14

我使用的是Spring Boot 2和Spring数据JPA。

我有一个带有@Transactional annotation的服务,它从存储库中读取记录,如果记录不存在,则添加记录并保存所有记录。我创建了一个测试方法,并行执行服务方法5次。由于我使用的是@Lock(LockModeType.悲观写入),我希望其中一个线程在读取可用性时会得到锁,而其他4个线程必须等待事务(createReservation)完成,但相反,该方法运行了5次,并且没有返回任何记录,因此,所有线程都尝试插入一条新记录,但都失败了(第一条除外),导致唯一索引或主键冲突。对于测试,我使用H2数据库。

预订服务:

@Service
public class ReservationService {

  @Autowired
  private AvailabilityService availabilityService;
  @Autowired
  private ReservationRepository repository;

  @Transactional
  public Reservation createReservation(Reservation r) {
    availabilityService.updateAvailability( r);
    return reservationRepository.save( r);
  }
}

可用性服务:

@Service
public class DayAvailabilityService {

  @Autowired
  private AvailabilityRepository availabilityRepository;

  public List<Availability> updateAvailability(Reservation reservation) {
    List<LocalDate> dates = reservation.getStart().datesUntil(reservation.getEnd()).collect(Collectors.toList());
    List<Availability> availabilities = availabilityRepository.findAllById(dates);
    // check availability, add records to this list if a record does not exist
    /// ...
    return availabilityRepository.saveAll(availabilities);
  }

}

public interface AvailabilityRepository extends JpaRepository<Availability, LocalDate> {

@Override
@Lock(LockModeType.PESSIMISTIC_WRITE)
List<Availability> findAllById(Iterable<LocalDate> iterable);

}

可用性实体:

@Entity
@Table(name = "Availability")
public class Availability {

  @Column(name = "Date")
  @Id
  @NotNull
  private LocalDate date;
  @Column(name = "Availability")
  private int availability;
  @Column(name = "MaxAvailability")
  private int maxAvailability;
}

这是测试类:

@SpringBootTest
@RunWith(SpringRunner.class)
public class ReservationServiceIntegrationTest {

  @Autowired
  private ReservationService service;
  @Autowired
  private ReservationRepository repository;

  @Test
  public void testConcurrentCreateReservation() throws InterruptedException {
    Reservation reservation = new Reservation("John", "Doe", "johndoe@mail.com",
            LocalDate.now().plusDays(4), LocalDate.now().plusDays(6), 30);
    runMultithreaded(() -> {
        try {
            service.createReservation(reservation);
        } catch (NoAvailabilityException e) {
            System.out.println("no availability.");
        }
    }, 5);

    long count = repository.count();
    assertEquals(3, count);

  }

  public static void runMultithreaded(Runnable  runnable, int threadCount) throws InterruptedException {
    List<Thread> threadList = new LinkedList<>();

    for(int i = 0 ; i < threadCount; i++) {
        threadList.add(new Thread(runnable));
    }

    for( Thread t :  threadList) {
        t.start();
    }

    for( Thread t :  threadList) {
        t.join();
    }
  }
}

在日志中,我看到为每个createReservation方法创建了一个事务。

Getting transaction for [com.company.app.service.ReservationService.createReservation]

然后我看到了5个类似这样的日志:

Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAllById]

然后我看到select查询执行了5次,最后是“for update”。所以锁应该可以工作,但我没有看到我预期的结果。

我的代码有什么问题?

谢谢

共有1个答案

范凡
2023-03-14

我认为问题是您想在每个线程中插入具有相同ID的记录。

// check availability, add records to this list if a record does not exist

锁对新记录不起作用。你得设法把整张桌子都锁上。如果您完全确定服务器将只运行一个实例,则可以同步您的方法,或者您可以使用“锁定记录”创建一个特殊表,并在实际表中创建新记录之前使用锁读取该记录,然后释放该锁。

第一种方法非常简单,但第二种方法更容易防故障。

 类似资料:
  • 问题内容: 我在java下有spring项目,使用hibernate查询,我喜欢使用悲观锁定。 在Spring + Hibernate中如何进行悲观锁定? 编辑: 问题: 我想在一个方法中使用悲观锁定,并且我将此方法称为从不同的方法。当我从第一个方法调用它时,悲观的工作效果很好,但是当我从第二个方法调用它时,它给出了(无法提交事务) 例外: 问题答案: http://www.amicabile.c

  • 我正在使用Spring Boot、JPA、Oracle 12C和下面的类型化查询来选择要处理的“新”项目。一旦我选择了“新”项目,我就会更新其状态,使其不再符合选择条件,但我看到一个并发问题,相同的项目被选中。 我在这里读到,我需要设置一个'LockModeType.PESSIMISTIC_WRITE'的查询,以防止其他线程选择相同的行,但它似乎不起作用。 我是否遗漏了下面的内容,或者我是否需要另

  • 我在用 Spring Boot 1.4.2 Spring Data JPA 1.10.5 PostgreSQL 9.5数据库 不幸的是,这不会刷新实体管理器缓存中我的实体的上一个实例。我有两个同时更新注册状态的请求 第二个等待第一个事务的事务提交 第二个不考虑第一个所做的更改。 从而破坏行为。 下面是请求的示例代码:

  • 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。 乐观锁与悲观锁的具体区别: http://www.cnblogs.com/Bob-FD/p/3352216.html

  • 我遵循grails文档,它说要做悲观锁定,我可以这样做: 所以这会锁定计划实例,直到保存完成。现在在我的例子中,我想一次锁定多个计划,如下所示: 我在默认情况下是事务性的 grails 服务中执行此操作,但上述行没有按预期工作。它不会锁定所有行,并在执行并发事务时引发。 如何在阅读时锁定多行? 有关更多信息,请参见相关问题:grails中的并发事务导致数据库陈旧状态异常

  • 我没有成功地将Spring数据发送给postgres a以进行NoWait更新。 我已经在存储库中尝试过了: 配置(代码段) 我甚至将EntityManager注入到服务中,结果返回0: info(em.getproperties().get(“javax.persistence.lock.timeout”)); 但是上面只给了我“用于更新”,没有设置NOWAIT部分。我设置的事情是正确的(从另一