我正在使用mysql
命令行程序执行与MySQL数据库交互的bash脚本。我想在我的SQL中使用表锁。我可以这样做吗?
mysql -e "LOCK TABLES mytable"
# do some bash stuff
mysql -u "UNLOCK TABLES"
我问的原因是因为只为会话保留了表锁,所以一旦mysql程序完成就不会释放锁吗?
答案 0 :(得分:8)
[编辑]
nos 有一个基本的想法 - 只运行一次“mysql”,并且提供的解决方案nos应该可以工作,但它将FIFO保留在磁盘上。
nos 也是正确的,我搞砸了:一个简单的“echo X >FIFO
”将关闭FIFO;我记错了。我的(删除)评论w.r.t.时间不适用,抱歉。
那就是说,你不需要FIFO,你可以使用进程间管道。通过我的旧MySQL脚本查看,有些工作类似于此,但你不能让任何命令写入stdout(没有一些“exec”技巧)。
#!/bin/bash
(
echo "LOCK TABLES mytable READ ;"
echo "Doing something..." >&2
echo "describe mytable;"
sleep 5
echo "UNLOCK tables;"
) | mysql ${ARGUMENTS}
另一种选择可能是将文件描述符分配给FIFO,然后让它在后台运行。这非常与 nos 类似,但“exec”选项不需要子shell来运行bash命令;因此可以让你在“其他东西”中设置“RC”:
#!/bin/bash
# Use the PID ($$) in the FIFO and remove it on exit:
FIFO="/tmp/mysql-pipe.$$"
mkfifo ${FIFO} || exit $?
RC=0
# Tie FD3 to the FIFO (only for writing), then start MySQL in the u
# background with its input from the FIFO:
exec 3<>${FIFO}
mysql ${ARGUMENTS} <${FIFO} &
MYSQL=$!
trap "rm -f ${FIFO};kill -1 ${MYSQL} 2>&-" 0
# Now lock the table...
echo "LOCK TABLES mytable WRITE;" >&3
# ... do your other stuff here, set RC ...
echo "DESCRIBE mytable;" >&3
sleep 5
RC=3
# ...
echo "UNLOCK TABLES;" >&3
exec 3>&-
# You probably wish to sleep for a bit, or wait on ${MYSQL} before you exit
exit ${RC}
请注意,存在一些控制问题:
答案 1 :(得分:4)
这是一种方式,我确信有一种更简单的方法..
mkfifo /tmp/mysql-pipe
mysql mydb </tmp/mysql-pipe &
(
echo "LOCK TABLES mytable READ ;" 1>&6
echo "Doing something "
echo "UNLOCK tables;" 1>&6
) 6> /tmp/mysql-pipe
答案 2 :(得分:2)
我在研究这个问题时发现的一个非常有趣的方法是使用MySQL的SYSTEM
命令。我不确定究竟有什么缺点,如果有的话,但它肯定会适用于很多情况:
示例:
mysql <<END_HEREDOC
LOCK TABLES mytable;
SYSTEM /path/to/script.sh
UNLOCK TABLES;
END_HEREDOC
值得注意的是,这只适用于* nix,显然是as does the SYSTEM
command。
感谢Daniel Kadosh:http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html#c10447
答案 3 :(得分:0)
没有mkfifo
命令的另一种方法:
cat <(echo "LOCK TABLES mytable;") <(sleep 3600) | mysql &
LOCK_PID=$!
# BASH STUFF
kill $LOCK_PID
我认为Amr的答案是最简单的。但是我想分享这个,因为其他人可能也需要稍微不同的答案。
sleep 3600
暂停输入1小时。您可以在此处找到其他命令以暂停:https://unix.stackexchange.com/questions/42901/how-to-do-nothing-forever-in-an-elegant-way
lock tables
SQL立即运行,然后等待睡眠计时器。
答案 4 :(得分:0)
如果LOCK TABLES
和UNLOCK TABLES
之间的命令都是SQL查询,则应该没问题。
但是,在这种情况下,为什么不简单地构造一个SQL文件并将其通过管道传递到mysql
命令呢?
如果关键部分中除了发出SQL查询外还有其他命令,则可能会遇到麻烦。
将lock语句发送到文件描述符的echo
命令不会阻塞,并等待mysql
响应。
因此,可以在实际获得锁定之前执行后续命令。无法保证同步。
由Amr Mostafa回答
SYSTEM
命令在MySQL服务器上执行。因此,要执行的脚本或命令必须存在于同一MySQL服务器上。
您将需要终端访问托管服务器的机器/ VM /容器(或者至少是一种将脚本传输到服务器主机的方法)。
SYSTEM
命令also works on Windows as of MySQL 8.0.19,但是在Windows服务器上运行它当然意味着您将运行Windows命令(例如批处理文件或PowerShell脚本)。
以下是基于NVRAM和否的答案的示例解决方案,但需要等待锁定:
#!/bin/bash
# creates named pipes for attaching to stdin and stdout of mysql
mkfifo /tmp/mysql.stdin.pipe /tmp/mysql.stdout.pipe
# unbuffered option to ensure mysql doesn't buffer the output, so we can read immediately
# batch and skip-column-names options are for ease of parsing the output
mysql --unbuffered --batch --skip-column-names $OTHER_MYSQL_OPTIONS < /tmp/mysql.stdin.pipe > /tmp/mysql.stdout.pipe &
PID_MYSQL=$!
# make sure to stop mysql and remove the pipes before leaving
cleanup_proc_pipe() {
kill $PID_MYSQL
rm -rf /tmp/mysql.stdin.pipe /tmp/mysql.stdout.pipe
}
trap cleanup_proc_pipe EXIT
# open file descriptors for writing and reading
exec 10>/tmp/mysql.stdin.pipe
exec 11</tmp/mysql.stdout.pipe
# update the cleanup procedure to close the file descriptors
cleanup_fd() {
exec 10>&-
exec 11>&-
cleanup_proc_pipe
}
trap cleanup_fd EXIT
# try to obtain lock with 5 seconds of timeout
echo 'SELECT GET_LOCK("my_lock", 5);' >&10
# read stdout of mysql with 6 seconds of timeout
if ! read -t 6 line <&11; then
echo "Timeout reading from mysql"
elif [[ $line == 1 ]]; then
echo "Lock acquired successfully"
echo "Doing some critical stuff..."
echo 'DO RELEASE_LOCK("my_lock");' >&10
else
echo "Timeout waiting for lock"
fi
以上示例使用SELECT GET_LOCK()
进入关键部分。它为我们产生输出以分析结果并决定下一步要做什么。
如果您需要执行不会产生输出的语句(例如LOCK TABLES
和START TRANSACTION
),则可以在该语句之后执行伪SELECT 1;
并以合理的超时时间从标准输出中读取。例如:
# ...
echo 'LOCK TABLES my_table WRITE;' >&10
echo 'SELECT 1;' >&10
if ! read -t 10 line <&11; then
echo "Timeout reading from mysql"
elif [[ $line == 1 ]]; then
echo "Table lock acquired"
# ...
else
echo "Unexpected output?!"
fi
您可能还想将第三个命名管道附加到mysql
的stderr上,以处理不同的错误情况。