我之前没有尝试过使用 MySQL 事务,我只是想澄清一些事情。
如果两个用户在非常准确的时间执行查询,MySQL 将如何处理?例如,用户正在尝试更新记录。
user1:更新表集 column = column - 4 where column_id = 1;
user2:更新表集 column = column - 7 where column_id = 1;
现在,如果我使用事务,MySQL 是否会选择首先执行哪个查询并锁定第二个用户,直到提交第一个查询?那是表锁还是行锁?
如果第三个用户将发出 select 语句怎么办?MySQL 将返回的值是什么?
PS 这将在 Innodb 上。
查询sys.dm_tran_locksDMV 会向我们显示哪些会话 (SPID) 持有表、页和行等资源的锁。
对于获取的每个锁,是否有任何方法可以确定导致该锁的 SQL 语句(删除、插入、更新或选择)?
我知道,most_recent_query_handle在列sys.dm_exec_connectionsDMV给了我们执行的最后一个查询的文本,而是多次其他查询同一个会话(SPID)在跑前和仍持有锁。
我已经使用了这个sp_whoisactive过程(来自 Adam Machanic),它只显示了此时输入缓冲区上的查询(想想DBCC INPUTBUFFER @spid),这并不总是(在我的情况下通常永远不会)是获取锁的查询。
例如:
该sp_whoisactive过程将指出第 3 步中的语句,该语句不是锁的负责人,因此没有用。
这个问题来自使用Blocked Process Reports功能进行分析,以找出生产中阻塞场景的根本原因。每个事务运行多个查询,并且大多数时候最后一个(显示在 BPR 的输入缓冲区中)很少是持有锁的那个。
我有一个后续问题:有效识别阻塞查询的框架
我一直在环顾四周,阅读 mysql 站点,但仍然无法确切了解它是如何工作的。
我想选择并行锁定写入结果,写入更改并释放锁定。audocommit 已开启。
方案
id (int)
name (varchar50)
status (enum 'pending', 'working', 'complete')
created (datetime)
updated (datetime)
Run Code Online (Sandbox Code Playgroud)
选择状态为待处理的项目,并将其更新为工作状态。使用独占写入来确保同一项目不会被捡起两次。
所以;
"SELECT id FROM `items` WHERE `status`='pending' LIMIT 1 FOR WRITE"
Run Code Online (Sandbox Code Playgroud)
从结果中获取 id
"UPDATE `items` SET `status`='working', `updated`=NOW() WHERE `id`=<selected id>
Run Code Online (Sandbox Code Playgroud)
我是否需要做任何事情来释放锁,它是否像我上面所做的那样工作?
我对 SQL Server 很陌生,想了解以下非常简单的select语句是否需要任何锁。
Select * from Student;
Run Code Online (Sandbox Code Playgroud)
请考虑语句不会在begin tran块内运行的情况。
我有两张桌子。一个是日志表;另一个本质上包含只能使用一次的优惠券代码。
用户需要能够兑换优惠券,这将在日志表中插入一行并将优惠券标记为已使用(通过将used列更新为true)。
当然,这里存在明显的竞争条件/安全问题。
我过去在 mySQL 的世界里做过类似的事情。在那个世界中,我会全局锁定两个表,在知道这一次只能发生一次的情况下执行逻辑安全,然后在我完成后解锁表。
Postgres 有没有更好的方法来做到这一点?特别是,我担心锁是全局的,但不是必须的——我真的只需要确保没有其他人试图输入那个特定的代码,所以也许一些行级锁会起作用?
我遇到了大量阻止我的 SELECT 操作的 INSERT 的问题。
我有一张这样的表:
CREATE TABLE [InverterData](
[InverterID] [bigint] NOT NULL,
[TimeStamp] [datetime] NOT NULL,
[ValueA] [decimal](18, 2) NULL,
[ValueB] [decimal](18, 2) NULL
CONSTRAINT [PrimaryKey_e149e28f-5754-4229-be01-65fafeebce16] PRIMARY KEY CLUSTERED
(
[TimeStamp] DESC,
[InverterID] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF
, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON
, ALLOW_PAGE_LOCKS = ON)
)
Run Code Online (Sandbox Code Playgroud)
我还有这个小助手程序,它允许我使用 MERGE 命令插入或更新(冲突时更新):
CREATE PROCEDURE [InsertOrUpdateInverterData]
@InverterID bigint, @TimeStamp datetime
, @ValueA decimal(18,2), @ValueB decimal(18,2)
AS
BEGIN
MERGE [InverterData] AS TARGET
USING (VALUES (@InverterID, …Run Code Online (Sandbox Code Playgroud) DB 工作的新手,所以感谢您对基本问题的耐心。我在本地机器上运行 SQL Server 2014,我有一个小表和一个基本的客户端应用程序来测试不同的方法。我在INSERT INTOandUPDATE语句中都得到了一个表锁。客户端是具有以下代码的 ASP.NET 应用程序:
OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn; …Run Code Online (Sandbox Code Playgroud) 从 SQLite FAQ 我知道:
多个进程可以同时打开同一个数据库。多个进程可以
SELECT同时进行。但是,任何时候只有一个进程可以对数据库进行更改。
所以,据我所知,我可以:1) 从多个线程 ( SELECT) 读取数据库 2) 从多个线程 ( SELECT)读取数据库并从单线程 ( CREATE, INSERT, DELETE)写入
但是,我读到了Write-Ahead Logging,它提供了更多的并发性,因为reader do not block writers and a writer do not block readings。读和写可以同时进行。
以下是出现 SQLITE_LOCKED 错误的其他原因:
- 试图
CREATE或DROP表或索引而SELECT声明仍悬而未决。- 当 a
SELECT在同一张表上处于活动状态时尝试写入表。- 尝试
SELECT在多线程应用程序中同时在同一张表上执行两个操作,如果 sqlite 未设置为这样做。- fcntl(3,F_SETLK 对 DB 文件的调用失败。例如,这可能是由 NFS 锁定问题引起的。此问题的一种解决方案是将 DB 移走,然后将其复制回来,使其具有新的 Inode 值
所以,我想为自己澄清一下,有必要避免锁吗?我可以从两个不同的线程同时读取和写入吗?谢谢。
在我们的数据库中存在一个大表,或多或少是这样的:
CREATE TABLE dbo.production_data
(
pd_id BIGINT PRIMARY KEY,
serial NVARCHAR(16) NOT NULL UNIQUE,
...
);
Run Code Online (Sandbox Code Playgroud)
但是现在串行字段的大小变得很小,所以我想将其更改为 32。Visual Studio 模式比较工具建议通过以下方式执行此操作:
DROP INDEX ux_production_data_serial ON dbo.production_data;
GO
ALTER TABLE dbo.production_data ALTER COLUMN serial NVARCHAR(32) NOT NULL;
GO
CREATE INDEX ux_production_data_serial ON dbo.production_data(serial ASC);
Run Code Online (Sandbox Code Playgroud)
这真的需要吗?或者更像是这样做的超级保存方式?
另外在重新创建唯一索引时,我的表会被锁定吗?因为这将是一个大问题(因为该表有 3000 万行,我猜重新创建索引需要相当长的时间),因为下一个维护窗口是未来几个月。我的选择是什么?
在每行有一个计数器(只是一个整数值)的表,我需要的电流值,并增加它在同一时间。
实际上,我想这样做:
SELECT counter FROM table WHERE id=123
UPDATE table SET counter=counter+1 WHERE id=123
Run Code Online (Sandbox Code Playgroud)
但是这样做作为两个查询显然不是线程安全的:多个进程做同样的事情(在同一行)可能会得到相同的计数器值。我需要它们都是独一无二的,所以每个过程都会获得实际的当前值并将其增加一。
我可以想到一种结构,在其中我对每行实施手动锁定,但我想知道是否有更简单的方法来做到这一点?
locking ×10
sql-server ×5
mysql ×3
innodb ×2
alter-table ×1
blocking ×1
concurrency ×1
index ×1
postgresql ×1
sqlite ×1
transaction ×1
update ×1