mysql - mysql中同步存储过程执行

标签 mysql stored-procedures synchronization locking boost-interprocess

我在 mysql 中有一个存储过程,用于执行需要同步的任务,这样如果两个应用程序调用存储过程,只有一个可以访问一段代码来执行任务,保持另一个被阻止,直到第一个完成任务。

DELIMITER $$
CREATE PROCEDURE SP_GEN_ID(IN NAME VARCHAR(20))

BEGIN 
  DECLARE maxLen int default 0;
START TRANSACTION;
   #the section of code that needs to be synchronized
COMMIT
END;
$$

DELIMITER ;

因此,如果两个应用程序同时调用存储过程,则任务必须同步。

一个。但是 Start TRANSACTIONCOMMIT 没有同步执行。

而LOCK TABLES tableA也不能在存储过程中使用来保证同步。

我试图在应用程序级别同步存储过程调用。我用过

boost_interprocess scoped_lock lock();

它在 boost 1.41 中运行得非常好

但是 boost 1.34 库不支持进程间锁定互斥锁,而我的情况是可用的。

有没有办法同步代码的存储过程部分,以便在同时进行两个调用时,一个在另一个调用执行之前被阻塞?

(添加了以下内容) 编辑后的代码:了解我在存储过程的同步块(synchronized block)中尝试执行的操作。

它获取最后分配的 id,并将其递增 1 并检查它是否未用于其他“名称”记录。 找到有效 ID 后,更新最后分配的 ID 记录表,然后将其与给定的“名称”相关联。

DELIMITER $$
CREATE PROCEDURE SP_GEN_ID(IN NAME VARCHAR(20))

BEGIN 
  DECLARE maxLen int default 0;
START TRANSACTION;
   #the section of code that needs to be synchronized
    SELECT lastid into lastgenerated FROM DB_last_id WHERE key = 'NAME_ID';    
findid_loop:
    LOOP
    set lastid = lastid + 1;
    #this is to check whether it was assigned with someother name before.
    IF not EXISTS (SELECT 1 FROM user_name_id WHERE name_id = lastgenerated) then
                     set nameid = lastgenerated;
                     set found = true;
                     LEAVE findid_loop;
            END IF;

            #for loop limit check
            IF (counter < loopLimit) then
                    set counter = counter + 1;
                    ITERATE findid_loop;
            ELSE
                    #reached the limit and not found.
                    LEAVE findid_loop;
            END IF;
    END LOOP findid_loop;

     #if a valid id, update last id and assign to name.
     IF (found) THEN
            #update the id.
            update DB_last_id  set lastid = nameid where key = 'NAME_ID';
            insert into user_name_id values (nameid ,name);
     ELSE
            #return an empty string for the application to take action on the failure.
            set nameid = '';
    END IF;
#end transaction here.
COMMIT

END;
$$

DELIMITER ;

最佳答案

正如我在上面的评论中提到的,您应该发现事务足以满足大多数需求;但是,如果您需要显式等待另一个调用完成,请使用 GET_LOCK(str,timeout) :

Tries to obtain a lock with a name given by the string str, using a timeout of timeout seconds. Returns 1 if the lock was obtained successfully, 0 if the attempt timed out (for example, because another client has previously locked the name), or NULL if an error occurred (such as running out of memory or the thread was killed with mysqladmin kill). If you have a lock obtained with GET_LOCK(), it is released when you execute RELEASE_LOCK(), execute a new GET_LOCK(), or your connection terminates (either normally or abnormally). Locks obtained with GET_LOCK() do not interact with transactions. That is, committing a transaction does not release any such locks obtained during the transaction.

This function can be used to implement application locks or to simulate record locks. Names are locked on a server-wide basis. If a name has been locked by one client, GET_LOCK() blocks any request by another client for a lock with the same name. This enables clients that agree on a given lock name to use the name to perform cooperative advisory locking. But be aware that it also enables a client that is not among the set of cooperating clients to lock a name, either inadvertently or deliberately, and thus prevent any of the cooperating clients from locking that name. One way to reduce the likelihood of this is to use lock names that are database-specific or application-specific. For example, use lock names of the form db_name.str or app_name.str.

mysql> SELECT GET_LOCK('lock1',10);
        -> 1
mysql> SELECT IS_FREE_LOCK('lock2');
        -> 1
mysql> SELECT GET_LOCK('lock2',10);
        -> 1
mysql> SELECT RELEASE_LOCK('lock2');
        -> 1
mysql> SELECT RELEASE_LOCK('lock1');
        -> NULL

The second RELEASE_LOCK() call returns NULL because the lock 'lock1' was automatically released by the second GET_LOCK() call.

If multiple clients are waiting for a lock, the order in which they will acquire it is undefined and depends on factors such as the thread library in use. In particular, applications should not assume that clients will acquire the lock in the same order that they issued the lock requests.

Note
Before MySQL 5.5.3, if a client attempts to acquire a lock that is already held by another client, it blocks according to the timeout argument. If the blocked client terminates, its thread does not die until the lock request times out.

此函数对于基于语句的复制是不安全的。从 MySQL 5.5.1 开始,如果您在 binlog_format 时使用此函数,则会记录一条警告设置为 STATEMENT。 (漏洞 #47995)

关于mysql - mysql中同步存储过程执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21325873/

相关文章:

sql-server - SQL Server SELECT INTO 和临时表阻塞

sql - 为什么不能在另一个存储过程调用的存储过程中使用 INSERT EXEC 语句?

用于更改可见性的 Javascript 和 PHP 单选按钮

mysql - mysql用逗号分割字符串

php - 如何使用ajax或jquery验证类型radio的答案

stored-procedures - 将值列表作为输入参数传递给PL/SQL过程

java - 实现同步以获得正确的线程输出

java - AtomicInteger 类中 addAndGet 的实现

c++ - 使用 Erlang 消息传递在模拟中表示并发电梯

mysql - 如何使用redshift查询S3公共(public)数据集