Kar*_*l S 5 mysql sql indexing mariadb
我有一个users大致像这样的MariaDB表:
id INT PRIMARY KEY AUTOINCREMENT,
email_hash INT, -- indexed
encrypted_email TEXT,
other_stuff JSON
Run Code Online (Sandbox Code Playgroud)
出于隐私原因,我无法将实际的电子邮件存储在数据库中。
用于电子邮件的加密不是一对一的,即可以将一封电子邮件加密为许多不同的加密表示形式。这使得仅仅在encrypted_email列上添加索引毫无意义,因为它永远不会捕获重复项。
数据库中已经有数据,更改加密方法或散列方法毫无疑问。
该email_hash列也不能具有唯一索引,因为它应该是一个短哈希,以加快重复检查的速度。它不能太独特,因为它将使所有隐私保证无效。
如何防止带有相同电子邮件的两个条目出现在数据库中?
另一个限制:LOCK TABLE根据文档https://mariadb.com/kb/en/library/lock-tables/,我可能无法使用,
LOCK TABLES使用Galera群集时不起作用。与Galera一起使用时,您可能会遇到崩溃或锁定的情况。
LOCK TABLES隐式提交活动事务(如果有)。另外,启动事务总是会释放通过获取的所有表锁LOCK TABLES。
(我确实使用Galera,并且确实需要事务,因为插入新用户会伴随其他一些插入和更新)
由于后端应用程序服务器(整体式)只要不存储个人信息即可(例如,用于发送电子邮件,验证登录名等)处理个人信息,因此我在应用程序中进行重复检查。
目前,我正在执行以下操作(伪代码):
perform "START TRANSACTION"
h := hash(new_user.email)
conflicts := perform "SELECT encrypted_email FROM users WHERE email_hash = ?", h
for conflict in conflicts :
if decrypt(conflict) == new_user.email :
perform "ROLLBACK"
return DUPLICATE
e := encrypt(new_user.email)
s := new_user.other_stuff
perform "INSERT INTO users (email_hash, encrypted_email, other_stuff) VALUES (?,?,?)", h, e, s
perform some other inserts as part of the transaction
perform "COMMIT"
return OK
Run Code Online (Sandbox Code Playgroud)
如果两次尝试之间有时间间隔,则可以正常工作。但是,当两个线程尝试同时添加同一用户时,则两个事务并行运行,进行选择,看到没有冲突的重复项,然后两个都继续添加用户。如何防止这种情况,或者至少是从容地立即恢复?
这是比赛的样子,简化了:
两个线程开始他们的交易
两个线程都执行选择,并且在两种情况下选择均返回零行。
两个线程都假定不会重复。
两个线程都添加用户。
两个线程都提交事务。
现在有两个用户使用相同的电子邮件。
钉FOR UPDATE在 的末端SELECT。
另外,由于您使用的是 Galera,因此必须在 后检查错误COMMIT。(即报告与其他节点发生冲突时。)
| 归档时间: |
|
| 查看次数: |
253 次 |
| 最近记录: |