該篇文章來(lái)源于線上案例結(jié)合官方文檔翻譯和自己理解。
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
這個(gè)函數(shù)定義中沒(méi)有包含deterministic,no sql或者read sql data中的一種,并且binlog是開(kāi)啟的。
很顯然是業(yè)務(wù)創(chuàng)建函數(shù)的時(shí)候觸發(fā)了該錯(cuò)誤,那為何會(huì)導(dǎo)致這種錯(cuò)誤呢,這是由于mysql復(fù)制要保證主從數(shù)據(jù)的一致決定的,這些函數(shù)創(chuàng)建語(yǔ)句會(huì)被記錄在binlog中,然后復(fù)制到slave執(zhí)行。但是這些函數(shù)在slave上執(zhí)行的時(shí)候有可能導(dǎo)致主從數(shù)據(jù)不一致,為了避免該問(wèn)題,mysql拒絕直接創(chuàng)建函數(shù),創(chuàng)建函數(shù)失敗,返回異常。那為何mysql會(huì)有這個(gè)機(jī)制,對(duì)于函數(shù)的創(chuàng)建又將如何處理?
在一些場(chǎng)景下,一條語(yǔ)句在分別在主從執(zhí)行可能導(dǎo)致不同的結(jié)果,在slave執(zhí)行復(fù)制語(yǔ)句是通過(guò)sql線程執(zhí)行的,而SQL線程是有所有的權(quán)限,因此有可能出現(xiàn)一種情況就是,函數(shù)中有危險(xiǎn)語(yǔ)句在master上執(zhí)行并不會(huì)有問(wèn)題,但是當(dāng)slave的SQL線程權(quán)限不同的時(shí)候,就會(huì)執(zhí)行到這些危險(xiǎn)語(yǔ)句,從而導(dǎo)致主從數(shù)據(jù)不一致。如果一個(gè)函數(shù)更改數(shù)據(jù)的結(jié)果是不確定的,或者是不可重復(fù)的,也會(huì)導(dǎo)致主從數(shù)據(jù)不一致,或者導(dǎo)致更改的數(shù)據(jù)和原始數(shù)據(jù)不一致(這主要在備份恢復(fù)中出現(xiàn))。
通常這些問(wèn)題出現(xiàn)在復(fù)制是語(yǔ)句模式的情況下,如果使用的行模式,binlog記錄的是執(zhí)行SQL語(yǔ)句影響到的具體的行(不是執(zhí)行的SQL語(yǔ)句),當(dāng)routines或者觸發(fā)器執(zhí)行,binlog中記錄的也是更改行信息,而不是影響行變更的SQL語(yǔ)句,對(duì)于存儲(chǔ)過(guò)程也是一樣,并不是記錄call 語(yǔ)句,也是記錄更改的行記錄。對(duì)于函數(shù),日志記錄的是函數(shù)更改的行記錄,而不是函數(shù)調(diào)用語(yǔ)句。對(duì)于觸發(fā)器,記錄的是觸發(fā)器更改之后的行記錄。因此在slave這邊,看的是變更之后的行記錄,而不是這些子程序的調(diào)用語(yǔ)句。因此在行模式則不會(huì)導(dǎo)致主從不一致。
如果復(fù)制模式是混合模式,除非行模式能保證正確的結(jié)果,不然上面的結(jié)果記錄到binlog采用的是語(yǔ)句模式。在混合模式下,當(dāng)一個(gè)存儲(chǔ)過(guò)程,函數(shù),觸發(fā)器,事件包含了對(duì)于語(yǔ)句模式不安全的SQL,這些語(yǔ)句就會(huì)標(biāo)記為不安全的并且采用行模式記錄在binlog。
在mysql中,下面有一些條件是對(duì)函數(shù)有效,對(duì)存儲(chǔ)過(guò)程或者事件無(wú)效,或者沒(méi)有開(kāi)啟binlog也是無(wú)效的:
? ? ?1.創(chuàng)建或者更改一個(gè)函數(shù)必須要有super權(quán)限
? ? ?2.創(chuàng)建一個(gè)函數(shù),必須要定義為確定結(jié)果的或者是不更改數(shù)據(jù)的。否則,就會(huì)被認(rèn)為是對(duì)復(fù)制或者數(shù)據(jù)恢復(fù)是不安全的,也就是報(bào)錯(cuò)1418
默認(rèn)情況下,要?jiǎng)?chuàng)建一個(gè)函數(shù),deterministic,no sql,reads sql data中三個(gè)屬性中的一個(gè)必須被顯示指定,這樣就能確認(rèn)函數(shù)對(duì)結(jié)果集的影響,否則就會(huì)報(bào)錯(cuò)1418,函數(shù)創(chuàng)建不成功。
下面這個(gè)函數(shù)就是確定結(jié)果的,因此是可以創(chuàng)建成功的:
CREATE FUNCTION f1(i INT)
RETURNS INT
DETERMINISTIC
READS SQL DATA
BEGIN
? RETURN i;
END;
下面函數(shù)使用了uuid(),這個(gè)函數(shù)的結(jié)果是不確定的,因此下面函數(shù)是非確定結(jié)果的,是復(fù)制不安全的,因此創(chuàng)建失敗:
CREATE FUNCTION f2()
RETURNS CHAR(36) CHARACTER SET utf8
BEGIN
? RETURN UUID();
END;
下面這個(gè)函數(shù)更改了數(shù)據(jù),也是不安全的:
CREATE FUNCTION f3(p_id INT)
RETURNS INT
BEGIN
? UPDATE t SET modtime = NOW() WHERE id = p_id;
? RETURN ROW_COUNT();
END;
評(píng)估一個(gè)函數(shù)是否安全取決于創(chuàng)建者是否清晰的知道這點(diǎn),mysql并不會(huì)檢查一個(gè)函數(shù)定義為確定結(jié)果但實(shí)際上產(chǎn)生了不確定的結(jié)果。在函數(shù)的定義中可以指定deteministic來(lái)顯示的說(shuō)明函數(shù)是安全的,但是在函數(shù)體中定義可以使用不安全的語(yǔ)句。
這種情況,mysql會(huì)認(rèn)為是安全的,可以創(chuàng)建函數(shù),但實(shí)際上這種函數(shù)調(diào)用對(duì)主從數(shù)據(jù)可能導(dǎo)致不一致。
如果試圖執(zhí)行一個(gè)函數(shù),若binlog_format 設(shè)置為statement模式,這個(gè)函數(shù)屬性必須要顯示指定為deterministic才行執(zhí)行,否則就會(huì)報(bào)錯(cuò)1418異常并且函數(shù)不會(huì)被執(zhí)行。但是設(shè)置了log_bin_trust_function_creators = 1,則可以正常執(zhí)行。
比如:
先set global log_bin_trust_function_creators =1 創(chuàng)建了一個(gè)沒(méi)有指定deterministic的函數(shù):
CREATE FUNCTION f2()
RETURNS CHAR(36) CHARACTER SET utf8
BEGIN
? RETURN UUID();
END;
再set globallog_bin_trust_function_creators? = 0;set binlog_format = statement;
然后調(diào)用該函數(shù)
mysql> ?select f2();
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
調(diào)用函數(shù)失敗,報(bào)錯(cuò)1418。
如果設(shè)置binlog_format=mixed 或者row 模式或者set globallog_bin_trust_function_creators? = 1 ,select f2()則可以正常執(zhí)行了(創(chuàng)建函數(shù)的時(shí)候沒(méi)有指定determinisric 關(guān)鍵字),或者在函數(shù)定義中指定deterministic屬性,也是可以正常執(zhí)行的。
因?yàn)閙ysql并沒(méi)有檢查一個(gè)函數(shù)在創(chuàng)建的時(shí)候是否是正是確定結(jié)果的,因此調(diào)用一個(gè)指定了deterministic關(guān)鍵字的函數(shù)在statement模式下可能帶來(lái)的結(jié)果是不安全的,因?yàn)檫@樣的函數(shù)中可能包含不安全的語(yǔ)句。在statement模式下,調(diào)用這種函數(shù)會(huì)觸發(fā)warning,如果是mixed或者row模式,不會(huì)有warning,函數(shù)中語(yǔ)句會(huì)以row模式進(jìn)行復(fù)制。如下:
創(chuàng)建函數(shù)的時(shí)候明確指定deterministic屬性
CREATE FUNCTION f3(p_id INT)
RETURNS INT
deterministic
BEGIN
? UPDATE t1 SET x=1 WHERE x = p_id;
? RETURN ROW_COUNT();
END;
這個(gè)函數(shù)不管log_bin_trust_function_creators? ?設(shè)置為多少都能創(chuàng)建成功,因此指定的結(jié)果是確定的。
在format_format=statement模式下調(diào)用:
mysql> select f3(1)//
+-------+
| f3(1) |
+-------+
| ? ? 0 |
+-------+
1 row in set, 1 warning (0.00 sec)
mysql> show warnings//
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note ?| 1592 | Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. |
+-------+------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
產(chǎn)生了warning,提示語(yǔ)句在statement模式下是不安全的(和log_bin_trust_function_creators 設(shè)置無(wú)關(guān),設(shè)置1或者0,都會(huì)有warning產(chǎn)生)
在binlog_format = row模式下調(diào)用:
mysql> set binlog_format=row//
Query OK, 0 rows affected (0.00 sec)
mysql> select f3(1)//
+-------+
| f3(1) |
+-------+
| ? ? 0 |
+-------+
1 row in set (0.00 sec)?
并不會(huì)提示warning,在mixed模式下也是一樣,不會(huì)有warning,都是以row模式進(jìn)行binlog記錄。
可以看出,即使我們創(chuàng)建函數(shù)的時(shí)候繞過(guò)了mysql的檢查,成功創(chuàng)建了函數(shù),但是在調(diào)用的時(shí)候,mysql還是會(huì)根據(jù)binlog_format來(lái)確認(rèn)結(jié)果,從而選擇是row模式,還是statement,并作出提示。
為了避開(kāi)創(chuàng)建函數(shù)的檢查條件,可以設(shè)置log_bin_trust_function_creators?= 1,這樣mysql就不會(huì)進(jìn)行檢查了,默認(rèn)設(shè)置0,這個(gè)參數(shù)只能設(shè)置global 級(jí)別。也可以在server啟動(dòng)的時(shí)候加上--log_bin_trust_function_creators?=1選項(xiàng)。如果binlog沒(méi)有開(kāi)啟,log_bin_trust_function_creators?參數(shù)也就沒(méi)作用。
觸發(fā)器和函數(shù)類似,因此前面講的關(guān)于函數(shù)的說(shuō)明同樣對(duì)觸發(fā)器有效,除了下面這個(gè):create trigger語(yǔ)句沒(méi)有deterministic屬性,因此觸發(fā)器總是被假定為deterministic,但是在一些場(chǎng)景下這個(gè)假設(shè)會(huì)失效。例如,uuid()函數(shù)就是nondeterministic的(不能復(fù)制的),因此在使用這些函數(shù)尤其注意。觸發(fā)器會(huì)更新表,因此create trigger語(yǔ)句沒(méi)有更新表所需要的權(quán)限時(shí),會(huì)和創(chuàng)建函數(shù)一樣報(bào)異常。在slave端,slave通過(guò)觸發(fā)器的definer屬性來(lái)決定觸發(fā)器的創(chuàng)建者,這就就決定了觸發(fā)器所需的權(quán)限。
如果一個(gè)函數(shù)更新了數(shù)據(jù) ,那么mysql會(huì)以select語(yǔ)句的形式記錄調(diào)用方式,這就避免了數(shù)據(jù)更新無(wú)法記錄日志從而使得無(wú)法復(fù)制。一般情況下,select語(yǔ)句是不會(huì)記錄子binlog中的,但是一個(gè)select語(yǔ)句有可能調(diào)用一個(gè)函數(shù)
導(dǎo)致數(shù)據(jù)變更。為了解決這種方式,當(dāng)select使用的函數(shù)更新了數(shù)據(jù),那么函數(shù)調(diào)用方式就以select語(yǔ)句的形式記錄在binlog中(這里有個(gè)前提,binlog_format=statment。row和mixed不存在這個(gè)問(wèn)題)
CREATE FUNCTION f1(a INT) RETURNS INT
BEGIN
? IF (a < 3) THEN
? ? INSERT INTO t2 VALUES (a);
? END IF;
? RETURN 0;
END;
CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3);
SELECT f1(a) FROM t1;
在binlog中可以發(fā)現(xiàn)是以select語(yǔ)句記錄binlog的:
如果是row或者mixed模式,則都是以row模式進(jìn)行binlog記錄。
當(dāng)一個(gè)函數(shù)中調(diào)用一個(gè)存儲(chǔ)過(guò)程的時(shí)候發(fā)生了錯(cuò)誤,這樣mysql同樣會(huì)以select語(yǔ)句的形式記錄函數(shù)的調(diào)用,這種情況下,binlog中記錄的select語(yǔ)句同時(shí)會(huì)記錄
期望的error code,在slave端,如果同樣的錯(cuò)誤出現(xiàn),那么這就是期望的結(jié)果同時(shí)復(fù)制不會(huì)中斷,否則復(fù)制會(huì)中斷。
binlog記錄函數(shù)的調(diào)用方式而不是記錄函數(shù)中的執(zhí)行語(yǔ)句對(duì)復(fù)制是一種安全的結(jié)果,主要有兩個(gè)方面的原因:
在master slave上函數(shù)的的調(diào)用路徑可能不同,其次執(zhí)行語(yǔ)句的SQL 線程有所有權(quán)限,和master可能不同,master可能沒(méi)這么大的權(quán)限,但是slave上有,就有可能導(dǎo)致主從上執(zhí)行結(jié)果不同。
這樣的結(jié)果就是雖然一個(gè)用戶需要create routine的權(quán)限來(lái)創(chuàng)建一個(gè)函數(shù),用戶可以寫很危險(xiǎn)的語(yǔ)句在函數(shù)中,而且只能在slave上通過(guò)有所有權(quán)限的SQL 線程來(lái)執(zhí)行。例如,master slave有不同的server id 1 和2,一個(gè)用戶可以在master上創(chuàng)建一個(gè)不安全的函數(shù)unsafe_func():
mysql>?delimiter?//
?mysql>?CREATE?FUNCTION?unsafe_func?()?RETURNS?INT
BEGIN?
IF?@@server_id=2?THEN?dangerous_statement;?
END?IF;?
?RETURN?1;
END;??
//
?mysql>?delimiter?;?
mysql>?INSERT?INTO?t?VALUES(unsafe_func());
函數(shù)創(chuàng)建語(yǔ)句和插入語(yǔ)句都會(huì)記錄在binlog中,因此slave可以執(zhí)行這些語(yǔ)句,因?yàn)镾QL 線程有所有權(quán)限(往往主庫(kù)創(chuàng)建和調(diào)用函數(shù)的用戶權(quán)限比較有限),因此將會(huì)執(zhí)行到這些危險(xiǎn)語(yǔ)句,因此,在master slave
上這個(gè)函數(shù)調(diào)用產(chǎn)生來(lái)不一樣的結(jié)果,所以它不是復(fù)制安全的。
為了避免開(kāi)啟binlog的mysql上的這種危險(xiǎn)情況,函數(shù)的創(chuàng)建這必須有所有權(quán)限,不僅僅是必須的create routine權(quán)限。同樣的,alter function也是一樣。沒(méi)有super權(quán)限,會(huì)發(fā)生如下錯(cuò)誤:
ERROR 1419 (HY000): You do not have the SUPER privilege and
binary logging is enabled (you *might* want to use the less safe
log_bin_trust_function_creators variable)
如果不想創(chuàng)建函數(shù)的用戶擁有super權(quán)限,可以設(shè)置全局參數(shù)log_bin_trust_function_creators =1,或者在服務(wù)啟動(dòng)的時(shí)候增加參數(shù)--log_bin_trust_function_creatros =1,如果binlog沒(méi)有開(kāi)啟,這個(gè)參數(shù)則沒(méi)有作用。
如果一個(gè)函數(shù)更新數(shù)據(jù)是不確定的,是不可重復(fù)的,這會(huì)導(dǎo)致兩個(gè)不良后果:
導(dǎo)致slave和master的數(shù)據(jù)不一致
恢復(fù)數(shù)據(jù)的時(shí)候?qū)е潞驮紨?shù)據(jù)不同(這里主要是數(shù)據(jù)恢復(fù)時(shí)出現(xiàn))
為了處理這些問(wèn)題,mysql做如下強(qiáng)制要求:在master上,拒絕創(chuàng)建或者變更一個(gè)函數(shù),除非定義的函數(shù)是確定結(jié)果的或者不更新數(shù)據(jù)的。這兩個(gè)函數(shù)屬性的作用如下:
deterministic 或者not deterministic屬性決定一個(gè)函數(shù)對(duì)于給定的輸入是否每次產(chǎn)生相同的結(jié)果,如果沒(méi)有屬性給定,默認(rèn)是not deteministic的。定義一個(gè)函數(shù)是deterministic的,需要明確指定deterministic屬性。
contains sql ,no sql,reads sql data和modify sql data屬性指出一個(gè)函數(shù)是讀數(shù)據(jù)還是更新數(shù)據(jù),no sql 或者reads sql data明確一個(gè)函數(shù)是不更新數(shù)據(jù)的。如果不指定屬性,默認(rèn)是contains sql,如果一個(gè)函數(shù)是明確不更新數(shù)據(jù)的話,
需要特別指定no sql、reads sql data中的一種。默認(rèn)情況下,要使得create function語(yǔ)句能否執(zhí)行,至少需要deteministic ,no sql或者reads sql data的三個(gè)中一個(gè)被明確指定,否則被會(huì)報(bào)錯(cuò):
ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL,
or READS SQL DATA in its declaration and binary logging is enabled
(you *might* want to use the less safe log_bin_trust_function_creators
variable)
如果設(shè)置log_bin_trust_function_creators =1 ,則deterministic 或者不更新數(shù)據(jù)的屬性被忽略。
調(diào)用存儲(chǔ)過(guò)程,binlog記錄是在語(yǔ)句執(zhí)行階段,而不是調(diào)用階段。也就是說(shuō)binlog記錄的不是call 語(yǔ)句,而是存儲(chǔ)過(guò)程中真正執(zhí)行的語(yǔ)句。因此在master更新的數(shù)據(jù)在slave上同樣被更新到,這就避免了同一個(gè)存儲(chǔ)過(guò)程在主從上導(dǎo)致不一樣的結(jié)果。
通常,binlog中記錄的存儲(chǔ)過(guò)程中執(zhí)行的語(yǔ)句只要有同樣的權(quán)限就可以在另外一臺(tái)機(jī)器上被執(zhí)行。有一個(gè)特殊場(chǎng)景需要注意:在非標(biāo)準(zhǔn)的上下文中存儲(chǔ)過(guò)程的執(zhí)行結(jié)果不完全相同:
一個(gè)語(yǔ)句記錄在binlog中可以要包含關(guān)聯(lián)一個(gè)本地的過(guò)程變量,這些變量在存儲(chǔ)過(guò)程外部是不存在的,因此一個(gè)引用了變量的語(yǔ)句不能直接按照語(yǔ)句的原樣進(jìn)行記錄binlog,而是為了寫入binlog每一個(gè)被引用的變量用如下的結(jié)構(gòu)進(jìn)行替換:
?NAME_CONST(var_name, var_value)
var_name 是本地的變量名,var_value是一個(gè)常量,表示引用這個(gè)變量的語(yǔ)句執(zhí)行時(shí)候該變量的值,name_const()函數(shù)的值為var_value,名字為var_name.因此,如果直接調(diào)用該函數(shù),可以得到如下結(jié)果:
mysql> SELECT NAME_CONST('myname', 14);
+--------+|myname|
+--------+|14|
+--------+
name_const()函數(shù)使得binlog中記錄在slave上執(zhí)行和存儲(chǔ)過(guò)程中的原始語(yǔ)句在 master上執(zhí)行產(chǎn)生同樣的效果。使用create table...select語(yǔ)句時(shí)候,當(dāng)select 語(yǔ)句中當(dāng)列表達(dá)式引用本地變量的時(shí)候,使用name_cons函數(shù)的時(shí)候會(huì)導(dǎo)致一些問(wèn)題。轉(zhuǎn)變這些引用為name_const表達(dá)式的過(guò)程中導(dǎo)致master和slave為不同的列名,或者name太長(zhǎng)也不能作為一個(gè)合法的列標(biāo)識(shí)。一種解決方式就是為列名提供一個(gè)別名引用本地變量。下面語(yǔ)句myvar 的值為1:
create table t1 select myvar;
記錄在binlog中會(huì)被重寫為如下語(yǔ)句:
create table t1 select name_const(myvar ,1);
為了確保master和slave有相同的列名,將語(yǔ)句寫成如下方式:
create table t1 select myvar as myvar;
binlog中會(huì)被記錄為如下:
create table t1 select name_const(myvar ,1) as myvar; 這樣就能確保主從的列名都是一致的。
另外一條語(yǔ)句記錄到binlog中可能包含引用用戶定義的變量。為處理這個(gè)特點(diǎn),mysql寫入一個(gè)set 語(yǔ)句到binlog確保該變量在slave上和master上有相同的值。例如,一條語(yǔ)句引用了變量@my_var,該語(yǔ)句在binlog中會(huì)處理為如下語(yǔ)句,value就是master上@my_var變量的值:
set @my_var = value;
存儲(chǔ)過(guò)程調(diào)用可以在包含commit或者rollback的事務(wù)中,事務(wù)的上下文會(huì)被記錄下來(lái),這樣事務(wù)中的存儲(chǔ)過(guò)程部分就能夠在slave中正確的復(fù)制執(zhí)行。也就是說(shuō),mysql記錄存儲(chǔ)過(guò)程中真實(shí)執(zhí)行和更改數(shù)據(jù)的語(yǔ)句,同時(shí)必要的時(shí)候會(huì)記錄begin,commit,rollback。例如,一個(gè)存儲(chǔ)過(guò)程只更新事務(wù)表而且在一個(gè)事務(wù)中執(zhí)行,如果被回滾了,那么這部分更新不會(huì)被記錄在binlog中。如果一個(gè)存儲(chǔ)過(guò)程調(diào)用在一個(gè)commit的事務(wù)中,更新前后會(huì)記錄begin和commit語(yǔ)句。如果一個(gè)存儲(chǔ)過(guò)程調(diào)用在一個(gè)rollback的事務(wù)中,這些被記錄會(huì)以同樣的規(guī)則被記錄在binlog中,當(dāng)其以獨(dú)立的方式執(zhí)行時(shí)這些語(yǔ)句都會(huì)被應(yīng)用:
事務(wù)表的更新不會(huì)記錄在binlog中
非事務(wù)表的更新會(huì)被記錄在binlog中,因?yàn)閞ollback不會(huì)回滾掉非事務(wù)表的更新
如果同時(shí)更新事務(wù)表和非事務(wù)表,這些記錄會(huì)前后會(huì)記錄begin和rolleback語(yǔ)句,因此slave更新和回滾的記錄就和master上更新和回滾的記錄一致。
在statement復(fù)制模式下,如果一個(gè)函數(shù)調(diào)用了一個(gè)存儲(chǔ)過(guò)程,binlog中不會(huì)記錄call語(yǔ)句。在這種場(chǎng)景下,只有函數(shù)調(diào)用語(yǔ)句被記錄(如果調(diào)用它的語(yǔ)句被記錄在binlog)或者是一個(gè)do語(yǔ)句(如果調(diào)用它的數(shù)據(jù)沒(méi)有記錄),正因如此,在一個(gè)函數(shù)中調(diào)用存儲(chǔ)過(guò)程需要小心,盡管存儲(chǔ)過(guò)程自身是安全的。也就是說(shuō),在一個(gè)函數(shù)中調(diào)用存儲(chǔ)過(guò)程,binlog中只會(huì)記錄函數(shù)的調(diào)用,不會(huì)記錄存儲(chǔ)過(guò)程的調(diào)用。
說(shuō)了這么多,就是為了說(shuō)明mysql對(duì)于創(chuàng)建函數(shù)的一些限制,以及調(diào)用函數(shù)如何記錄binlog,以及我們?cè)谌粘J褂煤瘮?shù)過(guò)程中,應(yīng)該注意什么。
再回到業(yè)務(wù)的報(bào)錯(cuò),創(chuàng)建函數(shù)失敗,函數(shù)中沒(méi)有指定deterministic ,no sql,reads sql data 屬性,從而導(dǎo)致報(bào)錯(cuò),解決辦法如下:
1.如果函數(shù)只是為了查詢方便而創(chuàng)建的,不更改數(shù)據(jù),那么可以指定reads sql data,deterministic屬性中的一種即可
2.如果函數(shù)要更改數(shù)據(jù),那么可以指定deterministic屬性通過(guò)創(chuàng)建函數(shù),但是為了確保復(fù)制安全,需要將binlog_format設(shè)置為row模式