MySQL如何实现互斥访问

小灰狼 2015-06-29 03:28:30
由于在MySQL中没有类似Oracle的序列的概念,因此决定通过一个表和两个存储过程来模拟这个功能。
我希望来自不同服务器的连接调用时,会有同步功能。


Create Table tbSequence(Id Int Unsigned Not Null Auto_Increment Primary Key, SequenceName Varchar(50) Not Null, SequenceValue Bigint Not Null);

Delimiter ;
Drop Function If Exists `fnNextSequence`;
Delimiter ;;
Create Function `fnNextSequence`(
p_SequenceName Varchar(50)
) Returns Bigint
Begin

Declare v_Result Bigint Default Null;

-- Lock Tables tbSequence Write;
-- Set Autocommit = 0;
-- Start Transaction;
Select SequenceValue Into v_Result From tbSequence Where SequenceName = p_SequenceName;
If v_Result Is Not Null Then
Set v_Result = v_Result + 1;
Update tbSequence Set SequenceValue = v_Result Where SequenceName = p_SequenceName;
Else
Set v_Result = 1;
Insert Into tbSequence(SequenceName, SequenceValue) Values(p_SequenceName, v_Result);
End If;

-- Unlock Tables tbSequence;
-- Commit;

Return v_Result;
End;;

Delimiter ;
Drop Function If Exists `fnCurrentSequence`;
Delimiter ;;
Create Function `fnCurrentSequence` (
p_SequenceName Varchar(50)
) Returns Bigint
Begin
Declare v_Result Bigint Default Null;

-- Lock Tables tbSequence Write;
-- Set AutoCommit = 0;
-- Start Transaction;
Select SequenceValue Into v_Result From tbSequence Where SequenceName = p_SequenceName;

-- Unlock Tables tbSequence;
-- Commit;

Return v_Result;
End;;


但是MySQL提示在存储过程中不允许锁表,也不允许启动事务。
该如何解决啊?
...全文
697 22 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
WWWWA 2015-07-20
  • 打赏
  • 举报
回复
别人的回复不看看吗? 是CREATE PROCEDURE 不是FUNCTION
小灰狼 2015-07-20
  • 打赏
  • 举报
回复
我的版本是 mysql5.6.25 社区版,在CentOS 7上运行

小灰狼 2015-07-20
  • 打赏
  • 举报
回复
引用 21 楼 WWWWA 的回复:
别人的回复不看看吗? 是CREATE PROCEDURE 不是FUNCTION
Function和Procedure 都试过了 只要里面出现 begin work, begin transaction 就是编译不过 算了,其实办法已经找到,就不纠结这个问题了,通过调用 mysql 的函数 Get_Lock 和 RELEASE_LOCK 即可:
Delimiter ;
Drop Function If Exists `fnNextSequence`;
Delimiter ;;
Create Function `fnNextSequence`(
	p_SequenceName Varchar(50)
) Returns Bigint
Begin 
	
	Declare v_Result Bigint Default Null;
	Declare v_MaxValue Bigint Default Null;
	Declare v_Lock Int Unsigned;
	
	Select Get_Lock(p_SequenceName, 1) Into v_Lock;
	
	Select `SequenceValue`, `MaxValue` Into v_Result, v_MaxValue From tbSequence Where SequenceName = p_SequenceName;
	
	If v_Result Is Not Null Then 
		Set v_Result = v_Result + 1;
		if (v_MaxValue Is Not Null) And (v_Result > v_MaxValue) THEN
			 Set v_Result = 1;
		END IF;
		Update tbSequence Set SequenceValue = v_Result Where SequenceName = p_SequenceName;
	Else 
		Set v_Result = 1;
		Insert Into tbSequence(SequenceName, SequenceValue) Values(p_SequenceName, v_Result);
	End If;
	
	Select RELEASE_LOCK(p_SequenceName) Into v_Lock;
	
	Return v_Result;
End;;

wwwwb 2015-07-17
  • 打赏
  • 举报
回复
在SP中没有问题上述代码在MYSQL5。.中测试通过,加入 SELECT SequenceValue FROM tbSequence WHERE SequenceName = p_name FOR UPDATE;是锁 表
小灰狼 2015-07-17
  • 打赏
  • 举报
回复
引用 17 楼 WWWWA 的回复:
DELIMITER ; DROP PROCEDURE IF EXISTS `spNextSequence3`; DELIMITER ;; CREATE PROCEDURE `spNextSequence3`(p_name VARCHAR(50),OUT p_result BIGINT) BEGIN START TRANSACTION ; SELECT SequenceValue FROM tbSequence WHERE SequenceName = p_name FOR UPDATE; UPDATE tbSequence SET SequenceValue=SequenceValue+1 WHERE SequenceName = p_name; COMMIT ; END;; DELIMITER ; 还少了1句 SELECT SequenceValue FROM tbSequence WHERE SequenceName = p_name FOR UPDATE;
不是多了条语句还是少了条语句的问题了 问题是,加了 begin work, begin transaction, start work, start transaction 之类的语句之后,mysql 说你有语法错误了
WWWWA 2015-07-16
  • 打赏
  • 举报
回复
DELIMITER ; DROP PROCEDURE IF EXISTS `spNextSequence3`; DELIMITER ;; CREATE PROCEDURE `spNextSequence3`(p_name VARCHAR(50),OUT p_result BIGINT) BEGIN START TRANSACTION ; SELECT SequenceValue FROM tbSequence WHERE SequenceName = p_name FOR UPDATE; UPDATE tbSequence SET SequenceValue=SequenceValue+1 WHERE SequenceName = p_name; COMMIT ; END;; DELIMITER ; 还少了1句 SELECT SequenceValue FROM tbSequence WHERE SequenceName = p_name FOR UPDATE;
小灰狼 2015-07-15
  • 打赏
  • 举报
回复
引用 15 楼 wwwwb 的回复:
你没有仔细看看别给的代码吗? 假设AA1保存最后1个ID 在SP中 BEGIN WORK; SELECT id FROM aa1 WHERE id=(SELECT MAX(id) FROM aa1) FOR UPDATE update aa1 set id=max(id)+1; COMMIT WORK; 锁表,替换 ,释放 
在过程中似乎不允许出现 begin work; 语句,否则报语法错误,以下是简单的测试代码 delimiter ; drop procedure if exists `spNextSequence3`; delimiter ;; create procedure `spNextSequence3`( p_name varchar(50), out p_result bigint ) begin begin work; update tbSequence set SequenceValue = SequenceValue + 1 Where SequenceName = p_name; commit work; end ;; --------------- [Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; update tbSequence set SequenceValue = SequenceValue + 1 Where SequenceName ' at line 6
wwwwb 2015-07-14
  • 打赏
  • 举报
回复
你没有仔细看看别给的代码吗? 假设AA1保存最后1个ID 在SP中 BEGIN WORK; SELECT id FROM aa1 WHERE id=(SELECT MAX(id) FROM aa1) FOR UPDATE update aa1 set id=max(id)+1; COMMIT WORK; 锁表,替换 ,释放 
wwwwb 2015-07-13
  • 打赏
  • 举报
回复
declare v_result bigint default 0; select 1 into v_result bigint from tbSequence where SequenceName = p_name if v_result bigint>1 then .....
小灰狼 2015-07-13
  • 打赏
  • 举报
回复
引用 13 楼 wwwwb 的回复:
declare v_result bigint default 0; select 1 into v_result bigint from tbSequence where SequenceName = p_name if v_result bigint>1 then .....
我想知道的是:怎么实现互斥,哥哥
小灰狼 2015-07-13
  • 打赏
  • 举报
回复
引用 11 楼 WWWWA 的回复:
假设AA1保存最后1个ID 在SP中 BEGIN WORK; SELECT id FROM aa1 WHERE id=(SELECT MAX(id) FROM aa1) FOR UPDATE update aa1 set id=max(id)+1; COMMIT WORK;
delimiter ;
drop function if exists `fnNextSequence1`;

delimiter ;;
create function `fnNextSequence1` (
	p_name varchar(50)
) returns bigint 
begin 
	begin work;
		declare v_result bigint;
		if exists(select * from tbSequence where SequenceName = p_name) then 
			select SequenceValue +1 into v_result from tbSequence where SequenceName = p_name;
			update tbSequence set SequenceValue = SequenceValue + 1 where SequenceName = p_name;
		else 
			set v_result = 1;
			insert into tbSequence(SequenceName, SequenceValue) Values(p_name, 1);
		end if;
		return v_result;
	end work;
end;;
报错: [Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '; declare v_result bigint; if exists(select * from tbSequence where Sequen' at line 5
WWWWA 2015-07-03
  • 打赏
  • 举报
回复
假设AA1保存最后1个ID 在SP中 BEGIN WORK; SELECT id FROM aa1 WHERE id=(SELECT MAX(id) FROM aa1) FOR UPDATE update aa1 set id=max(id)+1; COMMIT WORK;
小灰狼 2015-07-02
  • 打赏
  • 举报
回复
引用 9 楼 wwwwb 的回复:
就是SP,多线程访问 ,必须锁表,替换后再释放,进行再一次替换
那到底要怎么做呢?
wwwwb 2015-07-01
  • 打赏
  • 举报
回复
就是SP,多线程访问 ,必须锁表,替换后再释放,进行再一次替换
小灰狼 2015-06-30
  • 打赏
  • 举报
回复
引用 6 楼 wwwwb 的回复:
自定义函数改成SPS SP也可以返回参数
什么是SPS? 过程可以返回值,但是我要求加锁,当多个线程请求获得新序列号时,不会得到同一个值
wwwwb 2015-06-30
  • 打赏
  • 举报
回复
SP中可以用事务,你的代码贴出来
ACMAIN_CHM 2015-06-30
  • 打赏
  • 举报
回复
引用 4 楼 hemowolf 的回复:
[quote=引用 2 楼 ACMAIN_CHM 的回复:] 没有序列号。也没有互斥。 可以考虑用锁。 或者创建一个表,主键为自动增长的序列号,然后每次插入一条记录,得到last_insert_id
我可能有多个序列号,这样不是每个序列要创建一个表?[/quote]是的,这是一种最简单的方法了。利用MYSQL本身的 auto_increment 类似的,在ORACLE中不也同样要创建很多 sequence 吗?
wwwwb 2015-06-30
  • 打赏
  • 举报
回复
自定义函数改成SPS SP也可以返回参数
小灰狼 2015-06-30
  • 打赏
  • 举报
回复
引用 3 楼 wwwwb 的回复:
SP中可以用事务,你的代码贴出来
代码在第一楼里就帖了啊 启用事务时,说在过程里不允许有事务 锁表的时候,也说在过程里不允许锁表 两种办法的语句都在里面被注释过了的
小灰狼 2015-06-30
  • 打赏
  • 举报
回复
引用 2 楼 ACMAIN_CHM 的回复:
没有序列号。也没有互斥。 可以考虑用锁。 或者创建一个表,主键为自动增长的序列号,然后每次插入一条记录,得到last_insert_id
我可能有多个序列号,这样不是每个序列要创建一个表?
加载更多回复(2)

56,803

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧