我正在使用允许预定计划的旧系统。该应用程序是无状态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 | durration
---------------------------------------------------------------
答案 0 :(得分:3)
从头开始实现这样的东西并不是火箭科学,但也许您可能想看看这个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 + "!";
}
答案 1 :(得分:1)
数据库应处理此问题。您可以:
df=pd.DataFrame(dict(Type='A B B C'.split(), Set='Z Z X Y'.split()))
df['Color'] = "red"
df.loc[(df['Set']=="Z"), 'Color'] = "green"
print(df)
# result:
Type Set Color
0 A Z green
1 B Z green
2 B X red
3 C Y red
将阻止您正在读取的任何行(例如,在SELECT FOR UPDATE
查询中)被写入。参见https://dev.mysql.com/doc/refman/8.0/en/innodb-locking-reads.html 您可以使用命令行SQL客户端在本地测试您的更改:打开两个并发事务,并尝试以不同方式交错COUNT(*)
和SELECT
。
答案 2 :(得分:0)
我认为合乎逻辑的事情是锁定位置。如果我对域的理解正确,那么您是在为开始时间和持续时间指定的时隙保留特定位置(例如房间)吗?在这种情况下,您可能已经有一个位置实体。如果没有,您也许可以创建一个并添加一个匹配表。这样的代码将很简单:
表锁确实会损害可伸缩性,但是锁定特定位置应该可以。