完全通过FIFO附加到MySQL客户端

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中运行双重操作.

Hav*_*ard 5

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)


sol*_*ack 0

这是一个简单的示例,重现您描述的锁定行为:

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 的正确性却出人意料地困难。