Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL from the command line - can I practically use LOCKs?

I'm doing a bash script that interacts with a MySQL datatabase using the mysql command line programme. I want to use table locks in my SQL. Can I do this?

mysql -e "LOCK TABLES mytable"
# do some bash stuff
mysql -u "UNLOCK TABLES"

The reason I ask, is because table locks are only kept for the session, so wouldn't the lock be released as soon as that mysql programme finishes?

like image 351
Amandasaurus Avatar asked Aug 24 '09 20:08

Amandasaurus


People also ask

How can you implement locks in MySQL?

To lock a table using the MySQL LOCK TABLES Statement you need have the TABLE LOCK and SELECT privileges. READ LOCK − If you apply this lock on a table the write operations on it are restricted. i.e., only the sessions that holds the lock can write into this table.

Can we lock database in MySQL?

MySQL enables client sessions to acquire table locks explicitly for the purpose of cooperating with other sessions for access to tables, or to prevent other sessions from modifying tables during periods when a session requires exclusive access to them. A session can acquire or release locks only for itself.

Does update query locks the table MySQL?

A locking read, an UPDATE , or a DELETE generally set record locks on every index record that is scanned in the processing of an SQL statement. It does not matter whether there are WHERE conditions in the statement that would exclude the row.

How does MySQL read locks and write locks?

MySQL provides two types of locks onto the table, which are: READ LOCK: This lock allows a user to only read the data from a table. WRITE LOCK: This lock allows a user to do both reading and writing into a table. It is to note that the default storage engine used in MySQL is InnoDB.


3 Answers

[EDIT]

nos had the basic idea -- only run "mysql" once, and the solution nos provided should work, but it left the FIFO on disk.

nos was also correct that I screwed up: a simple "echo X >FIFO" will close the FIFO; I remembered wrongly. And my (removed) comments w.r.t. timing don't apply, sorry.

That said, you don't need a FIFO, you could use an inter-process pipe. And looking through my old MySQL scripts, some worked akin to this, but you cannot let any commands write to stdout (without some "exec" tricks).

#!/bin/bash
(
  echo "LOCK TABLES mytable READ ;"
  echo "Doing something..." >&2
  echo "describe mytable;" 
  sleep 5
  echo "UNLOCK  tables;" 
) | mysql ${ARGUMENTS}

Another option might be to assign a file descriptor to the FIFO, then have it run in the background. This is very similar to what nos did, but the "exec" option wouldn't require a subshell to run the bash commands; hence would allow you to set "RC" in the "other stuff":

#!/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}

Note that there are a few control issues:

  • This code has NO ERROR CHECKING for failure to lock (or any SQL commands within the "other stuff"). And that's definitely non-trivial.
  • Since in the first example, the "other stuff" is within a subshell, you cannot easily set the return code of the script from that context.
like image 178
NVRAM Avatar answered Oct 15 '22 02:10

NVRAM


Here's one way, I'm sure there's an easier way though..

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
like image 30
nos Avatar answered Oct 15 '22 01:10

nos


A very interesting approach I found out while looking into this issue for my own, is by using MySQL's SYSTEM command. I'm not still sure what exactly are the drawbacks, if any, but it will certainly work for a lot of cases:

Example:

mysql <<END_HEREDOC
LOCK TABLES mytable;
SYSTEM /path/to/script.sh
UNLOCK TABLES;
END_HEREDOC

It's worth noting that this only works on *nix, obviously, as does the SYSTEM command.

Credit goes to Daniel Kadosh: http://dev.mysql.com/doc/refman/5.5/en/lock-tables.html#c10447

like image 34
Amr Mostafa Avatar answered Oct 15 '22 01:10

Amr Mostafa