【问题标题】:SQLite query problem, and atomicity of transactionsSQLite 查询问题,以及事务的原子性
【发布时间】:2021-09-14 18:42:46
【问题描述】:

问题:我有两个表(members1members2),它们只是用户名列表。我需要更改 members1 中的用户名,但前提是新用户名尚未出现在任一表中(换句话说,用户名在两个表中必须是唯一的)。

SQL 超出了我的舒适范围,但经过几个小时的谷歌搜索后,我想出了下面的查询。我实际上使用的是 SQLite 的 C API,所以这只是一个用于检查语法的测试 shell 脚本。该脚本将旧名称更改为新名称,其中$1 是旧名称,$2 是新名称:

#!/usr/bin/env bash
sqlite3 test.db <<EOF

update members1 set uname=
  case 
    exists(select 1 from members1 where uname='$2') or
    exists(select 1 from members2 where uname='$2')
  when 1 then '$1'
  else '$2'
  end
where uname='$1';

EOF

问题:

  1. 这似乎可行,但它有意义吗?似乎很啰嗦。有一个更好的方法吗?特别是如果出现名称冲突,是否真的需要更新members1才能将旧名称改回原来的名称?
  2. 如果多个进程同时执行相同的操作,这有多安全?进程 A 是否可以将 'john' 更改为 'jim',而进程 B 同时将 'jo' 更改为 'jim',从而使 'jim' 在数据库中出现两次?
  3. 实际上大写/小写的协议是什么?上面的代码运行没有问题,但网络上的所有内容都是大写的。

谢谢。

【问题讨论】:

  • 将用户名存储在一个带有主键的表中,以便从其他表中访问它们!然后,您可以用最少的麻烦来保证唯一性。如有必要,您可以将其他列放在单独的表中。
  • @GordonLinoff - 不幸的是,在现实生活中,数据库更加复杂并且已经有不相关的主键......

标签: sql sqlite atomic


【解决方案1】:

如果我是你。我制作了一个独特的“umembers”表。

我用触发器填充它。 (members1 和 members2 也是)你可以找出更新触发器。

CREATE TRIGGER IF NOT EXISTS members1trigger
BEFORE INSERT ON members1 
BEGIN
    INSERT INTO umembers VALUES(new.uname, other properties);
END;

那么你的更新太棒了

#!/usr/bin/env bash
sqlite3 test.db <<EOF

update members1 set uname=$2
where uname='$1' and not exists (select 1 from umembers where uname= $2);

EOF
  1. 当然,您应该对 umembers 创建唯一约束。 如果有并行更新,那么第二个可能会抛出异常。 但我认为索引会锁定它,并且不会发生。

  2. 安全性表示使用不区分大小写的登录。

https://security.stackexchange.com/questions/241701/case-sensitive-logins

【讨论】:

  • 关于不区分大小写的名称的要点;谢谢,但我实际上是指 SQL 关键字。在表格上,我可以看到拥有一个单独的用户名/密码表格并让其他表格引用它可能是有意义的......我需要考虑一下。删除 CASE 语句 - 看起来不错;我试试看。
  • 我认为它是平等的。我更喜欢小写存储。但是 store (lower or upper) 不会通过查询来转换列。
猜你喜欢
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
  • 2018-05-08
  • 1970-01-01
  • 1970-01-01
  • 2011-06-19
相关资源
最近更新 更多