根据http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html,如果我锁定一个表以在mysql中写入,则在解锁之前没有其他人可以访问它。我编写了这个脚本,根据您想要执行的操作加载为 script.php 或 script.php?l=1 :
if ($_GET['l'])
{
mysqli_query("LOCK TABLES mytable WRITE");
sleep(10);
mysqli_query("UNLOCK TABLES");
}
else
{
$res=mysqli_query("SELECT * FROM mytable");
// Print Result
}
Run Code Online (Sandbox Code Playgroud)
如果我在一个浏览器窗口中加载 script.php?l=1 ,那么当它处于睡眠状态时,我应该能够在另一个窗口中加载 script.php 并且它应该等到 script.php?l=1 完成,对吧?
问题是,即使 script.php?l=1 有写锁,script.php 也会立即加载。如果我尝试在 script.php 中插入,它会等待,但为什么允许 SELECT?
注意:我并不是在寻找关于是否使用 LOCK TABLES 的讨论。事实上,我可能会进行一笔交易,我现在正在调查,现在我只想了解为什么上述方法不起作用。
我有一个存储过程,首先检查临时表(#temp_table),如果它存在则删除它,使用该表,然后在完成时最终删除它.当用户做某事来触发它时,该SP被随机调用,并且有时SP可能会同时执行 - 或者有些重叠.
假设我的Exec1和Exec2都是相同的SP创建,更改和删除#temp表,并且它们在相隔毫秒内运行.
怎么了?在Exec1完成时,Exec1会锁定#temp_table和Exec2等待吗?在我的情况下,这显然是可取的.我不希望Exec1和2同时使用该表,也不希望Exec2失败,因为Exec1已经在使用该表.
[编辑]我应该将临时表转换为表变量吗?
我在将 Oracle 语法转换为 H2 语法时遇到问题:
例如(甲骨文):
LOCK TABLE CAR_CHIP_ID_LOCK IN EXCLUSIVE MODE
Run Code Online (Sandbox Code Playgroud)
在 H2 中,它会导致(语法错误)
如何将oracle语法改为h2?我已经尝试过 Lock_mode 但它不起作用并且 MVCC 默认为 true v1.4+
我有两个innodb表:
用品
id | title | sum_votes
------------------------------
1 | art 1 | 5
2 | art 2 | 8
3 | art 3 | 35
Run Code Online (Sandbox Code Playgroud)
票
id | article_id | vote
------------------------------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 2
4 | 2 | 10
5 | 2 | -2
6 | 3 | 10
7 | 3 | 15
8 | 3 | 12
9 | 3 | -2
Run Code Online (Sandbox Code Playgroud)
当一个新记录插入到votes …
我有一个包含21M记录的MySQL数据库,我正在尝试对大约1M记录进行更新,但查询失败了 ERROR 1206 (HY000): The total number of locks exceeds the lock table size.
是否可以在不获取锁的情况下更新表?
我没有权限更改MySQL配置参数innodb_buffer_pool_size.是否有不同的方法来实现相同的目标?
谢谢
编辑:
我需要使用表锁定(写入)并同时更新一些表,因此我同时需要事务,因为锁定不是事务安全的。
从 mysql 文档中,我阅读了以下内容 https://dev.mysql.com/doc/refman/5.6/en/lock-tables-and-transactions.html
对事务表(例如 InnoDB 表)使用 LOCK TABLES 和 UNLOCK TABLES 的正确方法是使用 SET autocommit = 0(不是 START TRANSACTION)开始事务,然后是 LOCK TABLES,并且在提交事务之前不调用 UNLOCK TABLES明确地。例如,如果您需要写入表 t1 并从表 t2 读取,您可以这样做:
Run Code Online (Sandbox Code Playgroud)SET autocommit=0; LOCK TABLES t1 WRITE, t2 READ, ...; ... do something with tables t1 and t2 here ... COMMIT; UNLOCK TABLES;当你调用 LOCK TABLES 时,InnoDB 在内部获取自己的表锁,而 MySQL 获取自己的表锁。InnoDB 在下一次提交时释放它的内部表锁,但是 MySQL 要释放它的表锁,你必须调用 UNLOCK TABLES。你不应该有 autocommit = 1,因为 InnoDB 在调用 LOCK TABLES 后立即释放它的内部表锁,很容易发生死锁。如果 autocommit = 1,InnoDB 根本不获取内部表锁,以帮助旧应用程序避免不必要的死锁。
另一方面,从这个页面我们有 https://dev.mysql.com/doc/refman/5.6/en/commit.html
要为一系列语句隐式禁用自动提交模式,请使用 START TRANSACTION 语句: …
我有menus,categories和products表.我使用的是mysql 5.5,所有表都是innoDB,在所有情况下,id都是自动增量的主键(int).
menus table
id, name, status
categories table
id, menu_id, name
products table
id, menu_id, category_id, status, name, url, content
Run Code Online (Sandbox Code Playgroud)
多个脚本可以并行运行,执行包含以下逻辑的相同php文件.
START TRANSACTION;
SET autocommit = 0;
LOCK TABLES products WRITE, categories WRITE, menus WRITE;
SELECT
p.`id`,
p.`name`,
p.`url`,
p.`status`,
c.`id` cat_id,
c.`name` cat_name,
m.`id` `menu_id`,
m.`name` menu_name
FROM
products p
LEFT JOIN categories c
ON p.`subcategory_id` = c.`id`
LEFT JOIN menus m
ON p.`menu_id` = m.`id`
WHERE p.`status` = 0 LIMIT 1 …Run Code Online (Sandbox Code Playgroud) 我们的应用程序最初是作为桌面应用程序编写的,多年前就是这样.无论何时打开编辑屏幕,它都会启动一个事务,如果单击"确定",则会提交,或者如果单击"取消",则会回滚.这适用于桌面应用程序,但现在我们正在尝试迁移到ADO.NET和SQL Server,并且长时间运行的事务是有问题的.
我发现当多个用户同时尝试编辑同一个表(不同的子集)时,我们会遇到问题.在我们的旧数据库中,每个用户的事务将获取他们在事务期间修改的每个记录的记录级锁定; 由于不同的用户正在编辑不同的记录,每个人都有自己的锁,一切正常.但是在SQL Server中,只要有一个用户在事务中编辑记录,SQL Server就会在整个表上获得锁定.当第二个用户尝试编辑同一个表中的不同记录时,第二个用户的应用程序只会锁定,因为SqlConnection会阻塞,直到第一个用户提交或回滚.
我知道长时间运行的事务很糟糕,我知道最好的解决方案是更改这些屏幕,以便它们不再能够长时间保持事务处理.但是,由于这将意味着一些侵入性和风险的变化,我还想研究是否有一种方法来使这些代码按原样运行,因此我知道我的选择是什么.
如何在SQL Server中获取两个不同用户的事务来锁定单个记录而不是整个表?
这是一个快速而肮脏的控制台应用程序,用于说明问题.我创建了一个名为"test1"的数据库,其中一个名为"Values"的表只有ID(int)和Value(nvarchar)列.如果您运行该应用程序,它会要求修改ID,启动事务,修改该记录,然后保持事务处于打开状态,直到您按Enter键.我希望能够
目前它在第4步冻结,直到我回到应用程序的第一个副本并关闭它或按ENTER键以便提交.对command.ExecuteNonQuery的调用将阻塞,直到第一个连接关闭.
public static void Main()
{
Console.Write("ID to update: ");
var id = int.Parse(Console.ReadLine());
Console.WriteLine("Starting transaction");
using (var scope = new TransactionScope())
using (var connection = new SqlConnection(@"Data Source=localhost\sqlexpress;Initial Catalog=test1;Integrated Security=True"))
{
connection.Open();
var command = connection.CreateCommand();
command.CommandText = "UPDATE [Values] SET Value = 'Value' WHERE ID = " + id;
Console.WriteLine("Updating record");
command.ExecuteNonQuery();
Console.Write("Press ENTER to end …Run Code Online (Sandbox Code Playgroud) sql-server transactions nonblocking record-locking table-locking
我有一个MySQL数据库和一个innoDB表.我有一个连接的php页面,锁定表,进行一些更新,然后解锁表.PHP页面正在通过wamp提供apache.
php页面将文件上传到数据库.我决定通过上传一个大小比分配给PHP的内存大小的文件来模拟系统崩溃.这肯定导致了这个错误:允许18874368字节的内存大小耗尽(试图分配6176754字节).之后,更新期间锁定的表仍处于锁定状态.
我在尝试访问此错误后访问表时得到的错误是:表'a'未使用LOCK TABLES锁定.我知道这是一个锁定问题,因为我将调出一个SQL提示并尝试从已锁定的表中进行选择,它只是等待,就像锁定表时一样.如果我然后杀死Apache进程,我试图在SQL提示符中运行的语句将最终通过.我的猜测是,当我杀死Apache进程时,MySQL意识到应该释放表锁,因为连接被切断了.
有任何想法吗??
我正在开发一个从 Teradata DWH 获取一些数据的应用程序。LOCK ROW FOR ACCESSDWH 开发人员告诉我在所有查询之前使用SELECT,以避免延迟对该表的写入。
由于非常熟悉 MS SQL Servers 的WITH(NOLOCK)提示,我认为LOCK ROW FOR ACCESS它是等效的。但是,INSERTorUPDATE语句不允许使用LOCK ROW FOR ACCESS(我不清楚为什么会失败,因为它应该应用于语句选择的表,而不是我插入的表):
-- this works
LOCK ROW FOR ACCESS
SELECT Cols
FROM Table
-- this does not work
LOCK ROW FOR ACCESS
INSERT INTO SomeVolatile
SELECT Cols
FROM PersistentTable
Run Code Online (Sandbox Code Playgroud)
我已经看到LOCKING TABLE ... FOR ACCESS可以使用它,但不清楚它是否符合我的需要(NOLOCK等效 - 不阻止写入)。
问题: 在语句中进行选择时,应该使用什么提示来最大程度地减少写入延迟INSERT?
table-locking ×10
mysql ×6
locking ×3
innodb ×2
php ×2
sql ×2
sql-server ×2
transactions ×2
crash ×1
h2 ×1
large-data ×1
nonblocking ×1
oracle ×1
porting ×1
rowlocking ×1
temp-tables ×1
teradata ×1
triggers ×1