自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

PostgreSQL客戶端處理事務功能詳解

數(shù)據(jù)庫 其他數(shù)據(jù)庫 數(shù)據(jù)庫運維 PostgreSQL
在這里我們將討論的是PostgreSQL客戶端處理事務功能,希望通過本文能對大家了解PostgreSQL有所幫助。

PostgreSQL所針對的目標,與目前使用MySQL數(shù)據(jù)庫的人群很接近。那么究竟PostgreSQL有何優(yōu)勢?本文將為大家做出解釋。

本文將介紹PostgreSQL的事務處理功能的基本概念,并講解如何通過PostgreSQL客戶端以及從PHP腳本內部來執(zhí)行各種事務。通過本文,您將學習什么是事務,PostgreSQL是如何實現(xiàn)它們的,以及怎樣在自己的PHP應用程序中如何使用事務。

一、什么是事務?

事務可以看作是一個數(shù)據(jù)庫操作的有序集,這些操作應作為整體來對待,即集內所有的操作都成功的時候,該事務才被認為是成功的,否則的話,即使其中只有一個操作失敗,該事務也會被認為是不成功。如果所有的操作全部成功,那么事務就會被提交,這時它的所作的修改才能被所有其他數(shù)據(jù)庫進程所用。如果操作失敗,該事務就會被回滾,同時事務內部所有已完成操作所做的修改會被全部撤銷。在事務提交之前,一次事務期間所作的修改,只對擁有此事務的進程可用。之所以這樣做,是為了防止其他線程使用了事務修改的數(shù)據(jù)后,事務隨后又發(fā)生了回滾,從而導致數(shù)據(jù)完整性錯誤。

#T#

事務功能是企業(yè)數(shù)據(jù)庫的關鍵所在,因為許多業(yè)務流程是由多步組成的,下面我們以在線購物為例進行說明。在結帳時,顧客的購物車會跟現(xiàn)有庫存進行比對,以確保有現(xiàn)貨。接下來,顧客必須提供收費與交貨信息,這時就需要檢查相應的信用卡是否可用,并從中扣款。然后,需要從產品庫存清單中扣除相應的數(shù)量,如果庫存不足,還應向采購部門發(fā)出通知。在這些步驟中,只要有一步發(fā)生錯誤,那么所有修改都不應該生效。假設沒有現(xiàn)貨的情況下,還是從顧客的信用卡中扣了款的話,那么顧客會很生氣,問題就會很嚴重了。同樣地,作為在線商家,當信用卡無效的時候,您也肯定不希望從存貨清單中扣除此次顧客選擇的商品數(shù)量,或者因此而發(fā)出相應的采購通知。

我們這里所說的事務,必須滿足四大要件:

原子性:事務所有的步驟必須全部成功;否則,任何步驟都不會被提交。

一致性:事務所有的步驟必須全部成功;否則,所有的數(shù)據(jù)都會恢復到事務開始之前的狀態(tài)。

隔離性:在事務完成之前,所有已執(zhí)行的步驟必須與系統(tǒng)保持隔離。

持久性:所有提交的數(shù)據(jù),系統(tǒng)必須加以恰當保存,并保證萬一系統(tǒng)發(fā)生故障時仍能將數(shù)據(jù)恢復到有效狀態(tài)。

PostgreSQL的事務支持功能完全遵循上述四項基本原則(有時候人們簡稱為ACID),從而能夠有效保證數(shù)據(jù)庫的完整性。

二、PostgreSQL的事務隔離

PostgreSQL的事務支持是通過通常所說的多版本并發(fā)控制或者MVCC方法實現(xiàn)的,也就是說,每當事務進行處理時,它看到的是自己的數(shù)據(jù)庫快照,而非底層數(shù)據(jù)的實際狀態(tài)。 這使得任何給定的事務無法看到其它已經啟動但是尚未提交的事務對數(shù)據(jù)所作的部分修改。這項原則就是所謂的事務隔離。

SQL標準規(guī)定了三種屬性以用來確定一個事務處于四級隔離級別的哪一級,這些屬性如下所示:

臟讀:一個事務讀取了另一個未提交的并行事務寫的數(shù)據(jù)

不可重復讀:當一個事務重新讀取前面讀取過的數(shù)據(jù)時,發(fā)現(xiàn)該數(shù)據(jù)已經被另一個已提交的事務修改過

幻讀:一個事務重新執(zhí)行一個查詢時,返回一套符合查詢條件的行,發(fā)現(xiàn)這些行因為其他最近提交的事務而發(fā)生了改變

這三種情況確定了一個事務的隔離級別,所有四種水平如表1所示。

表1 SQL標準事務隔離級別

SQL標準事務隔離級別

PostgreSQL允許您請求四種可能的事務隔離級別中的任意一種。但是在內部,實際上只有兩種可用的隔離級別,分別對應讀已提交和可串行化。如果你選擇了讀未提交的級別,實際上你用的是讀已提交,在你選擇可重復的讀級別的時候,實際上你用的是可串行化,所以實際的隔離級別可能比你選擇的更嚴格。雖然這看起來是有悖于我們的直覺,但是SQL標準的確允許這樣做,因為四種隔離級別只定義了哪種現(xiàn)象不能發(fā)生,但是沒有定義那種現(xiàn)象一定發(fā)生,所以除了不允許的事務特性之外,所有的特性都是允許的。舉例來說,如果您請求可重復讀模式,那么該標準只是要求您不準臟讀以及不可重讀,但是卻沒有要求允許幻讀。因此,可串行化事務模式滿足可重復讀模式的要求,即使它跟定義沒有完全吻合。因此,您應當確切的知道,當您請求讀未提交模式的時候,您實際得到的卻是讀已提交模式;而當您請求可重復讀的時候,實際得到的是可串行化模式。您還應當意識到,默認情況下,如果您沒有請求一個特定的隔離級別,那么您得到的將是讀已提交隔離級別。

下面我們了解一下讀已提交和可串行化之間的主要區(qū)別。在讀已提交模式下SELECT 查詢只能看到該查詢開始之前提交的數(shù)據(jù)而永遠無法看到未提交的數(shù)據(jù)或者是在查詢執(zhí)行時其他并行的事務提交的改變;不過 SELECT 的確看得見同一次事務中前面更新的結果,即使它們還沒提交也看得到。實際上,一個 SELECT 查詢看到一個在該查詢開始運行的瞬間該數(shù)據(jù)庫的一個快照。請注意兩個相鄰的 SELECT 命令可能看到不同的數(shù)據(jù),哪怕它們是在同一個事務里,因為其它事務會在第一個SELECT執(zhí)行的時候提交。當一個事務處于可串行化級別的時候,一個 SELECT 查詢只能看到在該事務開始之前提交的數(shù)據(jù)而永遠看不到未提交的數(shù)據(jù)或事務執(zhí)行中其他并行事務提交的修改;不過,SELECT 的確看得到同一次事務中前面的更新的效果,即使事務還沒有提交也一樣。這個行為和讀已提交級別是不太一樣,它的 SELECT 看到的是該事務開始時的快照,而不是該事務內部當前查詢開始時的快照。這樣,一個事務內部后面的SELECT命令總是看到同樣的數(shù)據(jù)。這意味著,讀已提交模式下一個事務內部后面的SELECT命令可以看到不同的數(shù)據(jù),但是在可串行化模式下卻總是看到同樣的數(shù)據(jù)。

對于以上區(qū)別,請讀者一定弄清楚。雖然剛看上去有些復雜,但是只要抓住兩個要點,理解起來還是很容易的:首先,PostgreSQL運行事務的并發(fā)運行,也就是說一個事務執(zhí)行的時候,并不妨礙另一事務對相同數(shù)據(jù)操作。其次,一定注意快照的概念,事務提交前操作的是數(shù)據(jù)快照而非數(shù)據(jù)庫本身,同時注意不同隔離級別使用的是何時的快照——事務開始之前的快照,還是事務內部操作開始之前的快照?我想只要抓住了以上要點,我們就能很好的把握各種隔離級別之間的區(qū)別了。

上面介紹了事務的基本概念,接下來我們開始演示如何在PostgreSQL客戶端中使用事務。

三、創(chuàng)建示例表

下面,我們通過一個具體的在線交易應用為例來闡述上面介紹的事務概念。為此,我們需要先給這個示例程序在名為company的數(shù)據(jù)庫中創(chuàng)建兩個表:participant和trunk。同時,我們還會介紹各個表的用途和結構。建好表后,我們還需為它們填入一些樣本數(shù)據(jù),具體如下所示。

我們首先創(chuàng)建Participant表,這個表用來存放參與物品交換者的信息,包括他們的姓名、電子郵件地址和可用現(xiàn)金:

  1. CREATE TABLE participant (  
  2. participantid SERIAL,  
  3. name TEXT NOT NULL,  
  4. email TEXT NOT NULL,  
  5. cash NUMERIC(5,2) NOT NULL,  
  6. PRIMARY KEY (participantid)  
  7.  );  
  8. CREATE TABLE participant (  
  9. participantid SERIAL,  
  10. name TEXT NOT NULL,  
  11. email TEXT NOT NULL,  
  12. cash NUMERIC(5,2) NOT NULL,  
  13. PRIMARY KEY (participantid)  
  14.  ); 

然后,我們開始創(chuàng)建trunk 表。這個表存儲參與者所有的物品的有關信息,包括屬主、名稱、描述和價格:

  1. CREATE TABLE trunk (  
  2. trunkid SERIAL,  
  3. participantid INTEGER NOT NULL REFERENCES participant(participantid),  
  4. name TEXT NOT NULL,  
  5. price NUMERIC(5,2) NOT NULL,  
  6. description TEXT NOT NULL,  
  7. PRIMARY KEY (trunkid)  
  8. ); 

用到的表都建好了,下面我們開始添加樣本數(shù)據(jù)。為簡單起見,我們這里只添加了兩名參與者,即Tom和Jack;并為trunks表添加了少量的物品,如下所示:

  1.  INSERT INTO participant (name,email,cash) VALUES 
  2. ('Tom','Tom@example.com','1100.00');  
  3. INSERT INTO participant (name,email,cash) VALUES 
  4. ('Jack','Jack@example.com','1150.00');  
  5.  INSERT INTO trunk (participantid,name,price,description) VALUES 
  6.  (1,'Linux CD','1.00','Complete OS on a CD'); INSERT INTO trunk (participantid,  
  7.  name,price,description) VALUES 
  8.  (2,'ComputerABC','12.99','a book about computer!');  
  9.  INSERT INTO trunk (participantid,name,price,description) VALUES 
  10.  (2,'Magazines','6.00','Stack of Computer Magazines'); 
四、簡單的示例應用

為了讓讀者切身體會事務的運行機制,我們從命令行來運行我們的示例程序。我們的示例程序將演示兩個交易者如何通過現(xiàn)金的形式來互換物品。在考察代碼之前,先讓我們看一下更容易理解的偽代碼:

1. 參加者Tom請求一個物品,例如位于參加者Jack的虛擬儲物箱中的ComputerABC。

2. 參加者Tom向參加者Jack的帳戶上劃過去$12.99的現(xiàn)金。結果是,Tom的帳戶中現(xiàn)金數(shù)量減去12.99,而Jack的帳戶的現(xiàn)金數(shù)量則增加12.99。

3. 將ComputerABC的屬主改為參加者Tom。

如您所見,這個過程中的每一步對于該交易的整體成功來說都是非常關鍵的,所以必須保證我們的數(shù)據(jù)不會由于單步失敗而遭到破壞。當然,現(xiàn)實中的情景要比這里復雜得多,例如必須檢查購買方是否具有足夠的現(xiàn)金等等,不過為了簡單起見,我們忽略了一些細節(jié),以便讀者將主要精力都放到事務這一主題上來。

我們可以提交START TRANSACTION命令來啟動事務處理:

  1. company=# START TRANSACTION;  
  2. START TRANSACTION 

注意,START TRANSACTION還有一個別名,即BEGIN命令,雖然兩者都能完成該任務,但是我們還是推薦您使用后者,因為它符合SQL規(guī)范。接下來,從Tom的帳戶中扣除$12.99:

  1. company=# UPDATE participant SET cash=cash-12.99 WHERE participantid=1;  
  2. UPDATE 1 

然后,為Jack的帳戶增加$12.99:

  1. company=# UPDATE participant SET cash=cash+12.99 WHERE participantid=2;  
  2. UPDATE 1 

然后,將ComputerABC過戶給Tom:

  1. company=# UPDATE trunk SET participantid =1 WHERE name='ComputerABC' AND 
  2. company-# participantid=2;  
  3. UPDATE 1 

現(xiàn)在,我們已經完成了一筆交易,接下來我們開始介紹PostgreSQL的另一個特性:savepoint。注意,Savepoint功能是從PostgreSQL 8.0.0才引入的,因此如果您使用的是該版本之前的PostgreSQL的話,那么就無法使用下面介紹的命令。Savepoint就像是事務的書簽,我們可以在一個事務里設置一個點,以便萬一事務出錯時回滾到該保存點。我們可以像下面這樣提交一個保存點:

  1. company=# SAVEPOINT savepoint1;  
  2. SAVEPOINT 

提交了保存點后,我們就可以繼續(xù)執(zhí)行各種語句了。為了演示保存點的功能,假如我們想要檢驗對participant表所做的修改,但是在查詢命令中拼錯了participant表的名稱:

  1. company=# SELECT * FROM particapant;  
  2. ERROR: relation "particapant" does not exist 

注意,對于8.0.0版本之前的PostgreSQL來說,則必須回滾整個事務。如果我們沒有設置保存點就執(zhí)行了這個查詢,那么我們就會因為事務中的單個錯誤而不得不回滾整個事務。即使我們改正了這個錯誤,PostgreSQL也不會讓我們繼續(xù)該事務:

  1. company=# SELECT * FROM participant;  
  2. ERROR: current transaction is aborted, commands ignored until end of transaction block 

然而,因為我們已經提交了一個保存點,所以我們可以回滾到這個保存點,也就是說使我們的事務回到出錯之前的狀態(tài):

  1. company=# ROLLBACK TO savepoint1;  
  2. ROLLBACK 

注意,拼寫錯誤是一個非常煩人的問題,不過對于PostgreSQL 8.1來說,客戶端psql帶有一個\reseterror選項,能夠自動地設置保存點,并在出錯時進行回滾。

我們現(xiàn)在可以在我們的事務之內進行查詢了,好象根本發(fā)生錯誤一樣。下面我們花一些時間來檢查participant表,以保證向借方和貸方記入正確的現(xiàn)金數(shù)量。

  1. company=# SELECT * FROM participant; 

將返回:

  1. participantid | name | email | cash  
  2. ---------------+--------+--------------------+--------  
  3. 1 | Tom | Tom@example.com | 1087.01  
  4. 2 | Jack | Jack@example.com | 1162.99  
  5. (2 rows

此外,我們還需要檢查一下trunk表,看看ComputerABC的屬主已經是否進行了相應的修改。然而需要注意的是,由于PostgreSQL強制執(zhí)行ACID原則,因此這個改變只對執(zhí)行該事務的當前連接可用。為了說明這一點,我們啟動另一個psql客戶端,并再次登陸數(shù)據(jù)庫company,查看participant表時,我們會發(fā)現(xiàn)交易雙方相應的現(xiàn)金值并沒有變。這是因為ACID中的隔離性所導致的。除非我們提交了所作的修改,否則其他連接是看不到事務處理過程中所作的任何改變的。

如果想撤銷事務該怎么操作呢?回到第一個客戶端窗口,并通過ROLLBACK命令取消這些改變:

  1. company=# ROLLBACK;  
  2. ROLLBACK 

現(xiàn)在,再一次執(zhí)行SELECT命令:

  1. company=# SELECT * FROM participant;  
  2. This returns:  
  3. CHAPTER  
  4.  
  5. participantid | name | email | cash  
  6. ---------------+--------+--------------------+--------  
  7. 1 | Tom | Tom@example.com | 1100.00  
  8. 2 | Jack | Jack@example.com | 1150.00  
  9. (2 rows

需要注意的是,交易雙方的現(xiàn)金量已經恢復為原始值。檢查trunk表還會看到ComputerABC的屬主也沒有任何變化。再次重復前面的過程,這一次通過使用COMMIT命令而不是通過回滾操作來提交改變。一旦提交事務,再次返回到第二個客戶端并查看這兩個數(shù)據(jù)表,您會發(fā)現(xiàn)提交的變化已經可用了。

需要說明的是,COMMIT或者ROLLBACK命令提交之前,事務處理之間對數(shù)據(jù)所作的任何修改都不會生效。這意味著,如果PostgreSQL服務器在提交這些修改之前崩潰的話,那么這些修改也不會發(fā)生;要想使這些修改發(fā)生的話,您必須重新啟動該事務。

五、小結

本文中,我們介紹了PostgreSQL的事務功能,并講解如何通過PostgreSQL客戶端使用事務。讀者通過閱讀本文,將會學習什么是事務,PostgreSQL是如何實現(xiàn)它們的。在后面一篇文章中,我們將介紹如何在自己的PHP應用程序中如何使用事務。

【編輯推薦】

  1. PostgreSQL 8.4發(fā)布 新增查詢監(jiān)控工具
  2. PostgreSQL新版提高Oracle兼容性 欲與甲骨文試比高?
  3. 細化解析PostgreSQL的昨天今天和明天
  4. InnoDB還是MyISAM 再談MySQL存儲引擎的選擇
  5. 淺談MySQL存儲引擎選擇 InnoDB還是MyISAM
責任編輯:彭凡 來源: ITPUB
相關推薦

2010-03-18 15:44:22

VSTS 2010VS 2010

2010-05-12 15:46:51

Subversion客

2022-06-02 10:38:42

微服務數(shù)據(jù)源分布式

2009-03-04 10:27:50

客戶端組件桌面虛擬化Xendesktop

2010-04-08 15:35:13

Oracle 簡易客戶

2020-04-23 09:32:33

zookeeperCP系統(tǒng)

2010-06-01 14:11:11

TortoiseSVN

2013-06-08 09:59:15

VMwarevSphere Web

2010-03-18 16:49:43

Java Socket

2009-07-24 17:31:56

ASP.NET AJA

2010-05-31 15:55:42

2009-12-22 10:29:59

WCF客戶端處理

2009-08-21 16:14:52

服務端與客戶端通信

2021-04-30 08:19:32

SpringCloud客戶端負載Ribbo

2010-02-24 16:39:27

WCF客戶端處理

2010-09-29 15:05:44

DHCP客戶端故障

2011-08-17 10:10:59

2021-09-22 15:46:29

虛擬桌面瘦客戶端胖客戶端

2024-12-02 09:19:44

2022-01-20 16:31:41

AndroidTwitter客戶端
點贊
收藏

51CTO技術棧公眾號