1

假设我有一个依赖于 SQL 'users' 表的应用程序,并希望避免使用多个同名用户:

当我在我的表中插入一个新用户时,我必须确保已经没有类似的行。所以这是 2 个查询,第二个查询仅在第一个查询没有返回时发生:

-query1: select * from users where username='Marie-Antoinette'
-query2: insert into users ('','Marie-Antoinette','37')             

多个应用实例同时访问共享数据库,如何确保query1和query2之间没有插入查询?它是作为数据库中的原子操作完成的,中间没有任何内容?


可能有一种方法,一种进行条件插入的语法,但我的问题更多是关于“如何确保我可以进行 N 个查询,并保证不会在我的批处理中交错来自其他客户端的查询”?

假设我在我的应用程序中有一个需要 4 个查询的操作:

我的操作包括:

-query1: insert stuff in table 1
-query2: select stuff from table 2
-query3: insert stuff in table 3
-query4: update stuff in table 4

那些应该被视为原子操作,要么全有,要么全无,但不仅如此,在那个序列中,必须保证不会有任何交错的东西(因为在这些查询之间,数据库没有完整性,并且那些发生此操作时必须冻结 4 个表)并且多个客户端可以触发该操作,并且多个调用将以某种方式排队而不是失败。

随着时间的推移,这将是:

-client #1 query 1
-client #1 query 2
-client #1 query 3
-client #1 query 4

-client #2 query 1
-client #2 query 2
-client #2 query 3
-client #2 query 4

-client #1 query 1
-client #1 query 2
-client #1 query 3
-client #1 query 4

实现这一目标的推荐方法是什么?

4

2 回答 2

2

推荐的方法是在表上添加唯一索引(或等效的唯一约束),以便在插入时重复用户名失败:

create unique index users_username on users(username);
于 2013-08-24T14:38:25.107 回答
1

经过进一步研究,似乎我必须使用必须具有所有“ACID”属性的“事务”(对于我问题的第二部分,一般情况)。

http://en.wikipedia.org/wiki/Database_transaction

http://en.wikipedia.org/wiki/ACID

但是,单独使用交易并不能提供我在问题中提到的所有保证。特别是“隔离”保证可能是有问题的。

http://en.wikipedia.org/wiki/Isolation_(database_systems)

SQL 数据库具有可以检查的“事务隔离级别”属性,并且必须设置为“可序列化”

例如,在我的 MySQL 数据库中:

SELECT @@global.tx_isolation; 

>> REPEATABLE-READ

SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE

>> OK

SELECT @@global.tx_isolation; 

>> SERIALIZABLE
于 2013-08-24T17:13:50.993 回答