mysql - 完全通过 FIFO 连接到 MySQL 客户端

标签 mysql bash pipe fifo

在 Bash 脚本上,我想在多个顺序访问中保持 MySQL session 打开;访问 MySQL 的常用方法是为每个 SQL 命令或命令集打开一个单独的 session ,例如

mysql -u user -e "show tables;"

这种方法的局限性是那些需要双重事务的原子性和锁定状态的丢失:例如,不可能在整个表 T 上保留锁定状态以下双重操作的长度:

### Minimalistic example
data=$(mysql -e "\
    lock table T write;
    select col from T;
")
# ...
# parse 'data' and compute 'output' variable
# ...
mysql -e "insert into T values ($output);"

我的解决方案是使用两个 FIFO 使 MySQL session 在多次访问中保持打开状态,并将进程卡在后台。


建议的解决方案:
创建一对 FIFO:mkfifo IN OUT
将 MySQL 客户端实例设置到位,并设置一个虚拟 while 以保持管道打开并阻止 SIGPIPE 信号:

mysql --xml --batch --raw --skip-column-names \
    -h "$hostname" -u "$username" "$db" >IN <OUT &
while :; do sleep 1; done               <IN >OUT &

然后测试一下:

echo "show tables;" >OUT
read <IN

结果:
这没用。 echo 命令完成并且 bash 跳过它,这意味着 MySQL 接收到输入,但是 read 永远挂起,所以没有输出产生。
我发现消除 IN FIFO 整个任务不会挂起:

mysql --xml --batch --raw --skip-column-names \
    -h "$hostname" -u "$username" "$db" <OUT &
while :; do sleep 1; done               >OUT &

echo "show tables;" >OUT  # this produces the expected output

这种行为是预期的吗?另外我想知道是否可以在没有自定义自制程序的情况下在 Bash 中运行双重操作。

最佳答案

FIFO 的问题在于,当每个输入数据的进程终止时,它会向正在读取数据的进程(在本例中为 mysql)发出信号,表明数据已结束,因此它会终止。

诀窍是确保有一个进程始终保持 FIFO 输入处于事件状态。您可以通过在后台运行 sleep 999999999 > fifofile 来做到这一点。

例子:

#!/bin/sh

mkfifo /tmp/sqlpipe

sleep 2147483647 > /tmp/sqlpipe &
PID=$!

mysql -B -uUSER -pPASSWORD < /tmp/sqlpipe &

# all set up, now just push the SQL queries to the pipe, exemple:
echo "INSERT INTO table VALUES (...);" > /tmp/sqlpipe
echo "INSERT INTO table VALUES (...);" > /tmp/sqlpipe
echo "INSERT INTO table VALUES (...);" > /tmp/sqlpipe
cat "mysqldump.sql" > /tmp/sqlpipe
echo "DELETE FROM table WHERE ...;" > /tmp/sqlpipe

# done! terminate pipe
kill -s SIGINT $PID
rm /tmp/sqlpipe

最后我们终止sleep 进程以完全释放FIFO 输入。它会向 mysql 发出输入已结束的信号,并因此自动死亡。

还有一个不需要 FIFO 的替代方案,但您需要两个脚本:

运行.sh:

#!/bin/sh
./querygenerator.sh | mysql -B -uUSER -pPASSWORD

querygenerator.sh:

#!/bin/sh
echo "INSERT INTO table VALUES (...);"
echo "INSERT INTO table VALUES (...);"
echo "INSERT INTO table VALUES (...);"
cat "mysqldump.sql"
echo "DELETE FROM table WHERE ...;"

关于mysql - 完全通过 FIFO 连接到 MySQL 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20025209/

相关文章:

mysql - mysql跨表删除

bash - 为什么这个脚本不改变目录

c - C语言中的多管道( children 不停读)

macos - 如何在 OSX 中使用 sed 将每个单词的首字母大写

mysql - 返回表sql的函数

Mysql - 替换文本的最佳方法

sql - 需要帮助将条件 COUNT() 添加到已使用 JOIN 的查询

android - bash/mksh 的 Android 实现中此处文档/字符串的问题

Bash 参数扩展 ${parameter/pattern/string} 带引号

javascript - Angular 2 Pipe 参数失败