如何知道未提交的事务是否尝试将特定的唯一键插入 SQL
How to know if an uncommitted transaction tries to insert a specific unique key into SQL
我正在编写一个程序,将数据插入 MariaDB-Server 并可供不同的人同时使用。事务需要一些时间,因此可能会出现以下问题:A 开始事务时使用主键 "c",事务尚未提交时,B 想使用相同的主键 "c" 插入数据.如何防止 B 使用 A 已在其未提交事务中使用的主键开始其事务?
我使用 MariaDB 作为数据库,使用 InnoDB 作为引擎。
我检查了隔离级别,但不知道如何使用它们来解决我的问题。
谢谢!
主键是确保行唯一性的内部值,并不意味着暴露给外部世界。
使用 IDENTITY
列或使用 SEQUENCE
生成主键。他们将优雅地处理多个同时插入,并将为每个分配不同的值。
使用 IDENTITY:
CREATE TABLE house (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
address VARCHAR(40) NOT NULL
);
INSERT INTO house (address) VALUES ('123 Maple Street');
使用序列:
CREATE SEQUENCE myseq1;
CREATE TABLE house (
id INTEGER NOT NULL PRIMARY KEY,
address VARCHAR(40) NOT NULL
);
INSERT INTO house (id, address) VALUES (NEXT VALUE FOR myseq1, '123 Maple Street');
每个 table 应该有一个 PRIMARY KEY
。在 MySQL 中,根据定义,PRIMARY KEY
是 UNIQUE
。
您还可以在 table 上声明 UNIQUE
个键。
每个连接都应该这样做来标记事务:
BEGIN;
various SQL statements
COMMIT;
如果这些 SQL 语句中的任何一个插入一行,它会使用唯一键来阻止其他人将相同的唯一值插入到 table 中。这将导致某种形式的错误——死锁(对事务来说是致命的),"lock wait timeout"——它可能会从中恢复,等等。
注意:如果您在交易中有任何SELECTs
,您可能需要在它们的末尾贴上FOR UPDATE
。这表明您 可能 在事务中更改哪些行,从而提醒其他连接不要挡路。
你 可以查明这是否正在发生吗?并不真地。但是为什么要打扰呢?只需努力向前,做你需要做的事。但是检查错误以查看是否有其他连接阻止您这样做。
想到是"optimistic"编码。
不用管隔离级别;它只会给 典型 任务增加混乱。
它与事务隔离级别无关。这是关于锁定。
对索引中特定条目的任何 insert/update/delete 都会锁定该条目。锁被授予先到先得。尝试对同一索引条目执行 insert/update/delete 的下一个会话将被阻止。
你可以自己演示这个。并排打开两个 MySQL 客户端 windows。
第一个window:
mysql> START TRANSACTION;
mysql> INSERT INTO mytable SET c = 42;
那就先不要提交。
第二个window:
mysql> INSERT INTO mytable SET c = 42;
注意它此时挂起,等待锁定。
第一个window:
mysql> commit;
第二个window最后returns:
ERROR 1062 (23000): Duplicate entry '42' for key 'PRIMARY'
我正在编写一个程序,将数据插入 MariaDB-Server 并可供不同的人同时使用。事务需要一些时间,因此可能会出现以下问题:A 开始事务时使用主键 "c",事务尚未提交时,B 想使用相同的主键 "c" 插入数据.如何防止 B 使用 A 已在其未提交事务中使用的主键开始其事务?
我使用 MariaDB 作为数据库,使用 InnoDB 作为引擎。
我检查了隔离级别,但不知道如何使用它们来解决我的问题。
谢谢!
主键是确保行唯一性的内部值,并不意味着暴露给外部世界。
使用 IDENTITY
列或使用 SEQUENCE
生成主键。他们将优雅地处理多个同时插入,并将为每个分配不同的值。
使用 IDENTITY:
CREATE TABLE house (
id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
address VARCHAR(40) NOT NULL
);
INSERT INTO house (address) VALUES ('123 Maple Street');
使用序列:
CREATE SEQUENCE myseq1;
CREATE TABLE house (
id INTEGER NOT NULL PRIMARY KEY,
address VARCHAR(40) NOT NULL
);
INSERT INTO house (id, address) VALUES (NEXT VALUE FOR myseq1, '123 Maple Street');
每个 table 应该有一个 PRIMARY KEY
。在 MySQL 中,根据定义,PRIMARY KEY
是 UNIQUE
。
您还可以在 table 上声明 UNIQUE
个键。
每个连接都应该这样做来标记事务:
BEGIN;
various SQL statements
COMMIT;
如果这些 SQL 语句中的任何一个插入一行,它会使用唯一键来阻止其他人将相同的唯一值插入到 table 中。这将导致某种形式的错误——死锁(对事务来说是致命的),"lock wait timeout"——它可能会从中恢复,等等。
注意:如果您在交易中有任何SELECTs
,您可能需要在它们的末尾贴上FOR UPDATE
。这表明您 可能 在事务中更改哪些行,从而提醒其他连接不要挡路。
你 可以查明这是否正在发生吗?并不真地。但是为什么要打扰呢?只需努力向前,做你需要做的事。但是检查错误以查看是否有其他连接阻止您这样做。
想到是"optimistic"编码。
不用管隔离级别;它只会给 典型 任务增加混乱。
它与事务隔离级别无关。这是关于锁定。
对索引中特定条目的任何 insert/update/delete 都会锁定该条目。锁被授予先到先得。尝试对同一索引条目执行 insert/update/delete 的下一个会话将被阻止。
你可以自己演示这个。并排打开两个 MySQL 客户端 windows。
第一个window:
mysql> START TRANSACTION;
mysql> INSERT INTO mytable SET c = 42;
那就先不要提交。
第二个window:
mysql> INSERT INTO mytable SET c = 42;
注意它此时挂起,等待锁定。
第一个window:
mysql> commit;
第二个window最后returns:
ERROR 1062 (23000): Duplicate entry '42' for key 'PRIMARY'