我想替换一个表的全部内容,而不影响过程中任何传入的SELECT语句。
用例是有一个表,用于存储定期提取的邮箱信息,并且需要存储在 PostgreSQL 表中。有许多客户端使用不断查询同一张表的应用程序。
通常,我会做类似(伪代码传入)...
BEGIN TRANSACTION
TRUNCATE TABLE
INSERT INTO
COMMIT
Run Code Online (Sandbox Code Playgroud)
但不幸的是,在此过程中无法读取该表;由于INSERT INTO完成需要时间。桌子被锁上了。
在 MySQL 中,我会使用他们的原子RENAME TABLE命令来避免这些问题......
CREATE TABLE table_new LIKE table;
INSERT INTO table_new;
RENAME TABLE table TO table_old, table_new TO table; *atomic operation*
DROP TABLE table_old;
Run Code Online (Sandbox Code Playgroud)
我如何在 PostgreSQL 中实现这一点?
对于这个问题,您可以假设我没有使用外键。
我正在使用 Postgres 9.3,我需要根据表中已有的特定行数来防止插入到表中。这是表:
Table "public.team_joins"
Column | Type | Modifiers
-----------------+--------------------------+---------------------------------------------------------
id | integer | not null default nextval('team_joins_id_seq'::regclass)
team_id | integer | not null
Indexes:
"team_joins_pkey" PRIMARY KEY, btree (id)
"team_joins_team_id" btree (team_id)
Foreign-key constraints:
"team_id_refs_teams_id" FOREIGN KEY (team_id) REFERENCES teams(id) DEFERRABLE INITIALLY DEFERRED
Run Code Online (Sandbox Code Playgroud)
因此,例如,如果一个 id 为 3 的团队只允许 20 名玩家,并且SELECT COUNT(*) FROM team_joins WHERE team_id = 3等于 20,那么没有玩家应该能够加入团队 3。处理这种情况并避免并发问题的最佳方法是什么?我应该使用SERIALIZABLE事务来插入,还是可以WHERE在插入语句中使用这样的子句?
INSERT INTO team_joins (team_id)
VALUES (3)
WHERE (
SELECT COUNT(*) FROM team_joins WHERE …Run Code Online (Sandbox Code Playgroud) 假设我有一个像这样的数据库模式
user_id text
photo_id text
date_created timestamp
Run Code Online (Sandbox Code Playgroud)
我想强制执行“一个用户只能拥有 30 张照片”的约束。实现这一点的一个天真的方法是
SELECT COUNT(*) FROM user_photos WHERE user_id='usr_123'
Run Code Online (Sandbox Code Playgroud)
将结果与 30 进行比较,如果较低,则进行插入。天真,因为如果您可以在短时间内触发多个请求,您就可以赢得一场比赛并最终写入 30 多个记录。
有没有办法在数据库中强制执行此约束?例如创建某种索引“只能插入 30 行”,或者什么?有没有办法让一个count列为每个 userId 单独递增,并且可以将其范围限制为0-29?
如果您使用事务,会锁定您读取的行吗?