最近对存储过程那一佗东西,总感到有点不踏实。总感觉容易导致脏数据出现,但又苦于自己是新手,刚开始学数据库,连一个insert语句都写不好,又怎么好去提解决方法呢?
幸好逮到一个机会,有较多时间去验证存储过程的数据安全性问题。
测试例子,随意写的,只说明情况。
CREATE FUNCTION `func_set_top_score`(t_appid INT,t_user_id INT, t_score DOUBLE) RETURNS INT(11)
BEGIN
DECLARE m_exists_score DOUBLE DEFAULT 0;
DECLARE m_id BIGINT DEFAULT 0;
SELECT `score` ,`id` INTO m_exists_score,m_id FROM `user_score` WHERE `appid`=t_appid;
SLEEP(10);//增加该值,以提升脏数据的几率
IF m_exists_score <> 0 THEN
IF m_exists_score < t_score THEN
UPDATE `user_score` SET `score`=t_score,’id’=user_id WHERE `appid`=t_appid;
END IF;
ELSE
INSERT IGNORE INTO `user_score` (`id`, `score`, `appid `) VALUES (t_user_id, t_score,t_appid);
END IF;
RETURN @errno_success;
END$$
由于多进程的抢夺CPU,会导致某APP存放的分数,不一定是最高分。
解决办法是琐表:lock table和 unlock table;
为了更好的使用该琐表功能,进行以下测试,分别创建A终端和B终端,并连接上相同的数据。
1.A终端上,执行表的读琐,并依次执行insert和update动作。
2.B终端上执行select\insert\update动作。
3.A终端上再执行unlock动作。
4.B终端的数据更新成功。
5.A终端在琐表情况下,能否访问其它表?
读琐总结:
1.所有线程或进程都可以Select该琐定的数据表,但所有线程包括琐表的线程或进程,都不能够更新数据,直到琐表的线程调用unlock tables为止。
2.在lock tables和unlock tables之间,发生的更新操作,都会被挂起且进入阻塞队列,等待解琐和完成操作。
3.在lock tables和unlock tables之间,琐表的线程,不能访问其它表,包括select\update\insert操作。
1.表的写琐。
1.A终端发起写琐表,它的select/update/delete/insert操作均正常
2.B终端数据
3.A终端解琐
4.B终端返回数据。
写琐总结:
1.写琐触发后,只有琐表线程可以执行select/update/insert动作,其它线程或进程的所有动作都会被挂起,直到解琐为止。
2.在lock tables和unlock tables之间,琐表的线程,不能访问其它表,包括select\update\insert操作,这点与读琐一致。
如果我们要求某些表执行读操作,某些表执行写操作呢?答案是可以的,但写操作只能对写琐的表进行。
读写琐是否为递归琐?
答案:不是,连续两次调用lock table的效果是和lock table->unlock table->lock table的效果是一样的,如下。
琐表和解琐之间,为什么不能操作其它表?
个人猜测,主要是防止死琐问题,其次是避免操作其它表所造成的无谓性能浪费。