Java -分布式JPA锁定预留

d7v8vwbk  于 2023-10-19  发布在  Java
关注(0)|答案(3)|浏览(127)

我正在使用一个允许预订计划的遗留系统。该应用程序是无状态的REST,并被设计为水平扩展。但是,数据库在所有示例之间共享。在我得到一个关于设计和规模的讲座之前,它不是我的-必须充分利用一个糟糕的情况(或代码库)。最近我们看到一个问题,有重复的保留。我相信这是因为请求响应线程的性质。当前的流程是,接收请求,检查数据库是否有冲突的时间预留,如果没有,插入。根据读取和插入之间的时间,可能两者都被插入。场景看起来像这样:

|------|-------|-------|
R1     C1      I1     RSP

-|--------|-------|---------|
R2       C2     I2   RSP

其中R =请求,C = DB检查,I =插入。
所以我相信我可以使用@Synchronized注解来强制所有线程都是有序的。问题是,有多个示例正在运行,所以不能工作的整体示例。悲观或乐观的读和写似乎不适用,因为我们正试图做一个读和写组合,除非我完全误解。有什么想法来解决这个问题的规模?我更喜欢用java通过表锁或类似的东西来处理它,而不是添加额外的服务(Kafka,redis等)。

编辑:数据库看起来像这样,在dev中使用h2,在生产中使用mysql。

id |  start_time  | locationid | postingid | userid | duration
fdx2calv

fdx2calv1#

从头开始实现这样的东西并不是火箭科学,但也许你可能想看看这个GitHub项目:https://github.com/alturkovic/distributed-lock
我既没有参与这个项目,也没有使用它,但它看起来很有前途。您只需使用EnableJdbcDistributedLock创建Spring配置:

@Configuration
@EnableJdbcDistributedLock
public class LockConfiguration {
}

然后创建所需的数据库表:

create table lock (
  id int not null auto_increment primary key,
  lock_key varchar(255) unique,
  token varchar(255),
  expireAt timestamp,
);

一旦这一点到位,你就可以通过一个简单的注解(取自项目的示例)在分布式环境中同步方法调用:

@JdbcLocked(expression = "#name")
public String sayHello(final String name) {
  return "Hello " + name + "!";
}
1tu0hz3e

1tu0hz3e2#

数据库应该会处理这个。您可以:

您可以使用命令行SQL客户端在本地测试更改:打开两个并发事务,并尝试不同的方式交错SELECTINSERT

68bkxrlz

68bkxrlz3#

我认为合理的做法是锁定地点。如果我理解正确的域,你是保留一个特定的位置(如一个房间)的时间槽给定的开始时间和持续时间?在这种情况下,您可能已经有了一个位置实体。如果没有,您可以创建一个并添加一个匹配的表。代码将很简单:
1.使用JPA从请求中获取位置上的悲观锁
1.检查数据库是否存在冲突
1.插入新的预订
1.承诺
表锁确实会损害可伸缩性,但锁定特定位置应该可以工作。

相关问题