dav*_*ide 5 mysql bash pipe fifo
在Bash脚本上,我想让MySQL会话在多个顺序访问中保持开放状态; 访问MySQL的常用方法是为每个SQL命令或一组命令打开一个单独的会话,例如
mysql -u user -e "show tables;"
Run Code Online (Sandbox Code Playgroud)
此方法的限制是需要双重的那些事务的原子性和锁定状态的丢失:例如,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);"
Run Code Online (Sandbox Code Playgroud)
我的解决方案是使用两个FIFO在多个访问中保持MySQL会话开放,并在后台挂起进程.
建议的解决方案:
创建一对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 &
Run Code Online (Sandbox Code Playgroud)
然后测试一下:
echo "show tables;" >OUT
read <IN
Run Code Online (Sandbox Code Playgroud)
结果:
它不起作用.该echo命令完成并对其执行bash步骤,这意味着MySQL接收输入,但read永远挂起,因此不会产生任何输出.
我发现消除INFIFO整个任务不会挂起:
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
Run Code Online (Sandbox Code Playgroud)
这种行为有望吗?另外我想知道是否可以在没有自定义自制程序的情况下在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
Run Code Online (Sandbox Code Playgroud)
最后,我们终止sleep进程以完全释放FIFO输入.它将发出信号mysql表明输入已经结束,因此它将自动死亡.
还有一种不需要FIFO的替代方案,但是您需要两个脚本:
run.sh:
#!/bin/sh
./querygenerator.sh | mysql -B -uUSER -pPASSWORD
Run Code Online (Sandbox Code Playgroud)
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 ...;"
Run Code Online (Sandbox Code Playgroud)
这是一个简单的示例,重现您描述的锁定行为:
while :; do sleep 1; done <IN >OUT
sed s/^/::/ >IN <OUT
cat IN
echo x > OUT
Run Code Online (Sandbox Code Playgroud)
命令echo完成,但既不完成cat也不sed完成。也许玩这个例子会产生一些结果。
不过,我不确定您是否需要这样做。也许最好有一个通过管道传输到 MySQL 的控制脚本,并让 MySQL 将其输出写入文件。
#!/bin/bash
set -o errexit -o nounset -o pipefail
# Setup variables, hostname, names of files...
{
echo 'BEGIN PROGRAM' >&2
cat <<MYSQL
# Do something to set the output file, maybe \t?
lock table T write;
select col from T;
# Run a shell command to create a mysql.done file from MySQL
MYSQL
while [[ ! -f mysql.done ]]
do sleep 1
done
# Create rows to insert from MySQL output file.
echo 'load data infile input.tsv into table T'
} | mysql --xml --batch --raw --skip-column-names -h "$hostname" -u "$username" "$db"
Run Code Online (Sandbox Code Playgroud)
通过 FIFO 进行控制流比循环等待文件显示更有吸引力while;但 FIFO 的正确性却出人意料地困难。