MySQL 5.0 新特性教程是為需要了解5.0版本新特性的MySQL老用戶而寫的。簡單的來說是介紹了“存儲過程、觸發器、視圖、信息架構視圖”,在此感謝譯者陳朋奕的努力.
希望這本書能像內行專家那樣與您進行對話,用簡單的問題、例子讓你學到需要的知識。為了達到這樣的目的,我會從每一個細節開始慢慢的為大家建立概念,最後會給大家展示較大的實用例,在學習之前也許大家會認為這個用例很難,但是只要跟著課程去學,相信很快就能掌握。
Conventions and Styles 約定和編程風格
每次我想要演示實際代碼時,我會對MySQL客戶端的屏幕就出現的代碼進行調整,將字體改成CourIEr,使他們看起來與普通文本不一樣。
在這裡舉個例子:MySQL> DROP FUNCTION f;Query OK, 0 rows affected (0.00 sec)
如果實例比較大,則需要在某些行和段落間加注釋,同時我會用將“<--”符號放在頁面的右邊以表示強調。
例如:
MySQL> CREATE PROCEDURE p ()
-> BEGIN
-> /* This procedure does nothing */ <--
-> END;//Query OK, 0 rows affected (0.00 sec)
有時候我會將例子中的"mysql>"和"->"這些系統顯示去掉,你可以直接將代碼復制到mysql客戶端程序中(如果你現在所讀的不是電子版的,可以在mysql.com網站下載相關腳本)所以的例子都已經在Suse 9.2 Linux、MySQL 5.0.3公共版上測試通過。
在您閱讀本書的時候,Mysql已經有更高的版本,同時能支持更多OS了,包括Windows,Sparc,HP-UX。因此這裡的例子將能正常的運行在您的電腦上。但如果運行仍然出現故障,可以咨詢你認識的資深MySQL用戶,以得到長久的支持和幫助。
A Definition and an Example 定義及實例
定義及實例存儲過程是一種存儲在書庫中的程序(就像正規語言裡的子程序一樣),准確的來說,MySQL支持的“routines(例程)”有兩種:一是我們說的存儲過程,二是在其他SQL語句中可以返回值的函數(使用起來和MySQL預裝載的函數一樣,如pi())。我在本書裡面會更經常使用存儲過程,因為這是我們過去的習慣,相信大家也會接受。
一個存儲過程包括名字,參數列表,以及可以包括很多SQL語句的SQL語句集。
在這裡對局部變量,異常處理,循環控制和IF條件句有新的語法定義。
下面是一個包括存儲過程的實例聲明:(譯注:為了方便閱讀,此後的程序不添任何中文注釋)
CREATE PROCEDURE procedure1 /* name存儲過程名*/
(IN parameter1 INTEGER) /* parameters參數*/
BEGIN /* start of block語句塊頭*/
DECLARE variable1 CHAR(10); /* variables變量聲明*/
IF parameter1 = 17 THEN /* start of IF IF條件開始*/
SET variable1 = 'birds'; /* assignment賦值*/
ELSE
SET variable1 = 'beasts'; /* assignment賦值*/
END IF; /* end of IF IF結束*/
INSERT INTO table1 VALUES (variable1);/* statement SQL語句*/
END /* end of block語句塊結束*/
下面我將會介紹你可以利用存儲過程做的工作的所有細節。同時我們將介紹新的數據庫對象—觸發器,因為觸發器和存儲過程的關聯是必然的。
Why Stored Procedures 為什麼要用存儲過程
由於存儲過程對於MySQL來說是新的功能,很自然的在使用時你需要更加注意。
畢竟,在此之前沒有任何人使用過,也沒有很多大量的有經驗的用戶來帶你走他們走過的路。然而你應該開始考慮把現有程序(可能在服務器應用程序中,用戶自定義函數(UDF)中,或是腳本中)轉移到存儲過程中來。這樣做不需要原因,你不得不去做。
因為存儲過程是已經被認證的技術!雖然在MySQL中它是新的,但是相同功能的函數在其他DBMS中早已存在,而它們的語法往是相同的。因此你可以從其他人那裡獲得這些概念,也有很多你可以咨詢或者雇用的經驗用戶,還有許多第三方的文檔可供你閱讀。
存儲過程會使系統運行更快!雖然我們暫時不能在Mysql上證明這個優勢,用戶得到的體驗也不一樣。我們可以說的就是MySQL服務器在緩存機制上做了改進,就像Preparedstatements(預處理語句)所做的那樣。由於沒有編譯器,因此SQL存儲過程不會像外部語言(如C)編寫的程序運行起來那麼快。但是提升速度的主要方法卻在於能否降低網絡信息流量。如果你需要處理的是需要檢查、循環、多語句但沒有用戶交互的重復性任務,你就可以使用保存在服務器上的存儲過程來完成。這樣在執行任務的每一步時服務器和客戶端之間就沒那麼多的信息來往了。
所以存儲過程是可復用的組件!想象一下如果你改變了主機的語言,這對存儲過程不會產生影響,因為它是數據庫邏輯而不是應用程序。存儲過程是可以移植的!當你用SQL編寫存儲過程時,你就知道它可以運行在MySQL支持的任何平台上,不需要你額外添加運行環境包,也不需要為程序在操作系統中執行設置許可,或者為你的不同型號的電腦存儲過程將被保存!如果你編寫好了一個程序,例如顯示銀行事物處理中的支票撤消,那想要了解支票的人就可以找到你的程序。
它會以源代碼的形式保存在數據庫中。這將使數據和處理數據的進程有意義的關聯這可能跟你在課上聽到的規劃論中說的一樣。存儲過程可以遷移!
MySQL完全支持SQL 2003標准。某些數據庫(如DB2、Mimer)同樣支持。但也有部分不支持的,如Oracle、SQL Server不支持。我們將會給予足夠幫助和工具,使為其他DBMS編寫的代碼能更容易轉移到MySQL上。
Setting up with MySQL 5.0 設置並開始MySQL 5.0服務
通過
MySQL_fix_privilege_tables
或者
~/mysql-5.0/scripts/MySQL_install_db
來開始MySQL服務
作為我們練習的准備工作的一部分,我假定MySQL 5.0已經安裝。如果沒有數據庫管理員為你安裝好數據庫以及其他軟件,你就需要自己去安裝了。不過你很容易忘掉一件事,那就是你需要有一個名為MySQL.proc的表。
在安裝了最新版本後,你必須運行
MySQL_fix_privilege_tables
或者
MySQL_install_db
(只需要運行其中一個就夠了)——不然存儲過程將不能工作。我同時啟用在root身份後運行一個非正式的SQL腳本,如下:
mysql>source/home/pgulutzan/mysql-5.0/scripts/MySQL_prepare_privilege_tables_for_5.sql
Starting the MySQL ClIEnt 啟動MySQL客戶端
這是我啟動MySQL客戶端的方式。你也許會使用其他方式,如果你使用的是二進制版本或者是Windows系統的電腦,你可能會在其他子目錄下運行以下程序:
easy@PHPv:~> /usr/local/mysql/bin/MySQL --user=root
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 1 to server version: 5.0.3-alpha-debug
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
在演示中,我將會展示以root身份登陸後的MySQL客戶端返回的結果,這樣意味著我有極大的特權。
Check for the Correct Version 核對版本
為了確認使用的MySQL的版本是正確的,我們要查詢版本。我有兩種方法確認我使用的是5.0版本:
SHOW VARIABLES LIKE 'version';
or
SELECT VERSION();
例如:
MySQL> SHOW VARIABLES LIKE 'version';
+---------------+-------------------+
| Variable_name | Value |
+---------------+-------------------+
| version | 5.0.3-alpha-debug |
+---------------+-------------------+
1 row in set (0.00 sec)
MySQL> SELECT VERSION();
+-------------------+
| VERSION() |
+-------------------+
| 5.0.3-alpha-debug |
+-------------------+
1 row in set (0.00 sec)
當看見數字'5.0.x' 後就可以確認存儲過程能夠在這個客戶端上正常工作。
The Sample "Database" 示例數據庫
現在要做的第一件事是創建一個新的數據庫然後設定為默認數據庫實現這個步驟的SQL語句如下:
CREATE DATABASE db5;
USE db5;
例如:
MySQL> CREATE DATABASE db5;
Query OK, 1 row affected (0.00 sec)
MySQL> USE db5;
Database changed
在這裡要避免使用有重要數據的實際的數據庫然後我們創建一個簡單的工作表。
實現這個步驟的SQL語句如下:
MySQL> CREATE DATABASE db5;
Query OK, 1 row affected (0.01 sec)
MySQL> USE db5;
Database changed
MySQL> CREATE TABLE t (s1 INT);
Query OK, 0 rows affected (0.01 sec)
MySQL> INSERT INTO t VALUES (5);
Query OK, 1 row affected (0.00 sec)
你會發現我只在表中插入了一列。這樣做的原因是我要保持表的簡單,因為在這裡並不需要展示查詢數據的技巧,而是教授存儲過程,不需要使用大的數據表,因為它本身已經夠復雜了。
這就是示例數據庫,我們將從這個名字為t的只包含一列的表開始Pick a Delimiter 選擇分隔符
現在我們需要一個分隔符,實現這個步驟的SQL語句如下:
DELIMITER //
例如:
MySQL> DELIMITER //
分隔符是你通知MySQL客戶端你已經完成輸入一個SQL語句的字符或字符串符號。一直以來我們都使用分號“;”,但在存儲過程中,這會產生不少問題,因為存儲過程中有許多語句,所以每一個都需要一個分號因此你需要選擇一個不太可能出現在你的語句或程序中的字符串作為分隔符。我曾用過雙斜槓“//”,也有人用豎線“|”。我曾見過在DB2程序中使用“@”符號的,但我不喜歡這樣。你可以根據自己的喜好來選擇,但是在這個課程中為了更容易理解,你最好選擇跟我一樣。如果以後要恢復使用“;”(分號)作為分隔符,輸入下面語句就可以了:
"DELIMITER ;//".
CREATE PROCEDURE Example 創建程序實例
CREATE PROCEDURE p1 () SELECT * FROM t; //
也許這是你使用MySQL創建的第一個存儲過程。假如是這樣的話,最好在你的日記中記下這個重要的裡程碑。
CREATE PROCEDURE p1 () SELECT * FROM t; // <--
SQL語句存儲過程的第一部分是“CREATE PROCEDURE”:
CREATE PROCEDURE p1 () SELECT * FROM t; // <--
第二部分是過程名,上面新存儲過程的名字是p1。
Digression: Legal IdentifIErs 題外話:合法標識符的問題
存儲過程名對大小寫不敏感,因此‘P1’和‘p1’是同一個名字,在同一個數據庫中你將不能給兩個存儲過程取相同的名字,因為這樣將會導致重載。某些DBMS允許重載(Oracle支持),但是MySQL不支持(譯者話:希望以後會支持吧。)。
你可以采取“數據庫名.存儲過程名”這樣的折中方法,如“db5.p1”。存儲過程名可以分開,它可以包括空格符,其長度限制為64個字符,但注意不要使用MySQL內建函數的名字,如果這樣做了,在調用時將會出現下面的情況:
MySQL> CALL pi();
Error 1064 (42000): You have a syntax error.
MySQL> CALL pi ();
Error 1305 (42000): PROCEDURE does not exist.
在上面的第一個例子裡,我調用的是一個名字叫pi的函數,但你必須在調用的函數名後加上空格,就像第二個例子那樣。
CREATE PROCEDURE p1 () SELECT * FROM t; // <--
其中“()”是“參數列表”。
CREATE PROCEDURE
語句的第三部分是參數列表。通常需要在括號內添加參數。例子中的存儲過程沒有參數,因此參數列表是空的—所以我只需要鍵入空括號,然而這是必須的。
CREATE PROCEDURE p1 () SELECT * FROM t; // <--
"SELECT * FROM t;"
是存儲過程的主體。
然後到了語句的最後一個部分了,它是存儲過程的主體,是一般的SQL語句。過程體中語句
"SELECT * FROM t;"
包含一個分號,如果後面有語句結束符號(//)時可以不寫這個分號。
如果你還記得我把這部分叫做程序的主體將會是件好事,因為(body)這個詞是大家使用的技術上的術語。通常我們不會將SELECT語句用在存儲過程中,這裡只是為了演示。所以使用這樣的語句,能在調用時更好的看出程序是否正常工作。