是否可以使用特定值插入PostgreSQL锁?
是否可以在PostgreSQL的INSERT语句中为特定值创建锁 比如说,我有一张桌子:是否可以使用特定值插入PostgreSQL锁?,sql,postgresql,sql-insert,Sql,Postgresql,Sql Insert,是否可以在PostgreSQL的INSERT语句中为特定值创建锁 比如说,我有一张桌子: CREATE TABLE IF NOT EXISTS bookings ( bookingID SERIAL PRIMARY KEY, tableID integer REFERENCES tables ON DELETE CASCADE, startTime timestamp NOT NULL, endTime timestamp NOT NULL, ); 现在,如果启动了一个
CREATE TABLE IF NOT EXISTS bookings (
bookingID SERIAL PRIMARY KEY,
tableID integer REFERENCES tables ON DELETE CASCADE,
startTime timestamp NOT NULL,
endTime timestamp NOT NULL,
);
现在,如果启动了一个带有INSERT的事务块,我可以为事务期间具有相同tableID和相同日期的所有其他INSERT创建一个锁吗
因此,同一tableID的第二次预订必须等待第一次预订完成。然后可以再次检查,是否仍然可以插入。
因此,它基本上是插入中特定值的行锁
该程序是用Java编写的,但由于瓶颈,我不想使用同步块
谢谢你的帮助同意。当然,同步块是更好的解决方案
但是如果您坚持使用数据库锁,那么()可以帮助您
例如:
begin; -- we will use transaction level lock but there is an option with session level locks
select pg_advisory_xact_lock(123); -- 123 is a tableID you need to lock
insert into bookings(tableID, ...) values(123, ...); -- or/and other queries
commit;
同意。当然,同步块是更好的解决方案
但是如果您坚持使用数据库锁,那么()可以帮助您
例如:
begin; -- we will use transaction level lock but there is an option with session level locks
select pg_advisory_xact_lock(123); -- 123 is a tableID you need to lock
insert into bookings(tableID, ...) values(123, ...); -- or/and other queries
commit;
问题是,为什么要阻止此表的其他插入 对我来说,看起来您希望确保同一个tableID没有相交间隔。可能您在Java代码中检查了这一点,并且不希望其他插入干扰检查 如果是这样,则根本不需要锁:使用约束 为此,您需要:
timestamp
字段更改为一个tsrange
字段CREATE TABLE IF NOT EXISTS bookings (
bookingID SERIAL PRIMARY KEY,
tableID integer REFERENCES tables ON DELETE CASCADE,
during tsrange NOT NULL,
EXCLUDE using gist(during with &&, tableID with =)
);
将自动创建特殊的GIST索引,以确保相同的tableID(=
运算符)没有相交间隔(&&&
运算符)
一些例子:
-- interval for tableID=10
test=# insert into bookings values (1, 10, '[2015-11-17 10:00, 2015-11-17 12:00)');
INSERT 0 1
-- interval for tableID=11
test=# insert into bookings values (2, 11, '[2015-11-17 10:00, 2015-11-17 12:00)');
INSERT 0 1
-- can't create intersecting interval for tableID=10
test=# insert into bookings values (3, 10, '[2015-11-17 11:00, 2015-11-17 13:00)');
ERROR: conflicting key value violates exclusion constraint "bookings_during_tableid_excl"
DETAIL: Key (during, tableid)=(["2015-11-17 11:00:00","2015-11-17 13:00:00"), 10) conflicts with existing key (during, tableid)=(["2015-11-17 10:00:00","2015-11-17 12:00:00"), 10).
-- ok to create non-intersecting interval
test=# insert into bookings values (4, 10, '[2015-11-17 12:00, 2015-11-17 13:00)');
INSERT 0 1
问题是,为什么要阻止此表的其他插入 对我来说,看起来您希望确保同一个tableID没有相交间隔。可能您在Java代码中检查了这一点,并且不希望其他插入干扰检查 如果是这样,则根本不需要锁:使用约束 为此,您需要:
timestamp
字段更改为一个tsrange
字段CREATE TABLE IF NOT EXISTS bookings (
bookingID SERIAL PRIMARY KEY,
tableID integer REFERENCES tables ON DELETE CASCADE,
during tsrange NOT NULL,
EXCLUDE using gist(during with &&, tableID with =)
);
将自动创建特殊的GIST索引,以确保相同的tableID(=
运算符)没有相交间隔(&&&
运算符)
一些例子:
-- interval for tableID=10
test=# insert into bookings values (1, 10, '[2015-11-17 10:00, 2015-11-17 12:00)');
INSERT 0 1
-- interval for tableID=11
test=# insert into bookings values (2, 11, '[2015-11-17 10:00, 2015-11-17 12:00)');
INSERT 0 1
-- can't create intersecting interval for tableID=10
test=# insert into bookings values (3, 10, '[2015-11-17 11:00, 2015-11-17 13:00)');
ERROR: conflicting key value violates exclusion constraint "bookings_during_tableid_excl"
DETAIL: Key (during, tableid)=(["2015-11-17 11:00:00","2015-11-17 13:00:00"), 10) conflicts with existing key (during, tableid)=(["2015-11-17 10:00:00","2015-11-17 12:00:00"), 10).
-- ok to create non-intersecting interval
test=# insert into bookings values (4, 10, '[2015-11-17 12:00, 2015-11-17 13:00)');
INSERT 0 1
您需要的是谓词锁定。PostgreSQL不直接支持它,但@stas.yaranov描述的建议锁定是一种很好的解决方法。正如@EgorRogov所指出的,如果可能的话,您应该通过使用适当的约束来完全消除锁定的需要 另一个无人提及的选项是在PostgreSQL 9.1或更新版本中使用
SERIALIZABLE
事务隔离。这使用了一种非常类似于乐观锁定的并发控制方法,其中每个事务都在不锁定的情况下进行,但如果其中一个事务与另一个事务冲突,则其中一个事务可能会中止。这意味着您的应用程序必须准备好捕获序列化失败错误并重试事务,但这通常是一种非常有效且非常简单的处理此类问题的方法,尤其是在排除约束对您没有帮助的情况下
如果可以的话,我建议在这种特殊情况下使用排除约束,因为这正是它们的设计目的。但是您可以使用serializable
隔离,而无需更改模式或添加新索引,这是一种更通用的解决方案
(顺便说一句,在9.0或更高版本中,您不能使用
SERIALIZABLE
,因为在这些版本中它不够智能)您需要的是谓词锁定。PostgreSQL不直接支持它,但@stas.yaranov描述的建议锁定是一种很好的解决方法。正如@EgorRogov所指出的,如果可能的话,您应该通过使用适当的约束来完全消除锁定的需要
另一个无人提及的选项是在PostgreSQL 9.1或更新版本中使用SERIALIZABLE
事务隔离。这使用了一种非常类似于乐观锁定的并发控制方法,其中每个事务都在不锁定的情况下进行,但如果其中一个事务与另一个事务冲突,则其中一个事务可能会中止。这意味着您的应用程序必须准备好捕获序列化失败错误并重试事务,但这通常是一种非常有效且非常简单的处理此类问题的方法,尤其是在排除约束对您没有帮助的情况下
如果可以的话,我建议在这种特殊情况下使用排除约束,因为这正是它们的设计目的。但是您可以使用serializable
隔离,而无需更改模式或添加新索引,这是一种更通用的解决方案
(顺便说一句,在9.0或更高版本中,您不能使用
可序列化的,因为在这些版本中它不够智能)“我不想使用同步块”-为什么您认为在数据库资源上同步比在Java代码中同步更有效?据我所知,如果我使用已同步的,整个表被“锁定”,因此其他事务必须等待。但如果可能的话,我只想锁定部分表以提高效率。另一个选项是可序列化
隔离,但@EgorRogov建议使用排除约束是这种情况下更好的解决方案。“我不想使用同步块”-为什么您认为在数据库资源上进行同步比在Java代码中进行同步更有效?据我所知,如果使用synchronized
,整个表都被“锁定”,因此其他事务必须等待。但如果可能的话,我只想锁定部分表以提高效率。另一个选项是SERIALIZABLE
isolation,但是@EgorRogov的sugge