1, 臟讀
一個(gè)事務(wù)讀到另一個(gè)事務(wù),尚未提交的修改,就是臟讀。這里所謂的修改,除了Update操作,不要忘了,還包括
Insert和Delete操作。
臟讀的后果:如果后一個(gè)事務(wù)回滾,那么它所做的修改,統(tǒng)統(tǒng)都會(huì)被撤銷。前一個(gè)事務(wù)讀到的數(shù)據(jù),就是垃圾數(shù)據(jù)。
舉個(gè)例子:預(yù)訂房間。
有一張Reservation表,往表中插入一條記錄,來訂購(gòu)一個(gè)房間。
事務(wù)1:在Reservation表中插入一條記錄,用于預(yù)訂99號(hào)房間。
事務(wù)2:查詢,尚未預(yù)定的房間列表,因?yàn)?9號(hào)房間,已經(jīng)被事務(wù)1預(yù)訂。所以不在列表中。
事務(wù)1:信用卡付款。由于付款失敗,導(dǎo)致整個(gè)事務(wù)回滾。
所以插入到Reservation 表中的記錄并不置為持久(即它將被刪除)。
現(xiàn)在99號(hào)房間則為可用。
所以,事務(wù)2所用的是一個(gè)無(wú)效的房間列表,因?yàn)?9號(hào)房間,已經(jīng)可用。如果它是最后一個(gè)沒有被預(yù)定的房間,那么這將是一個(gè)嚴(yán)重的失誤。
注:臟讀的后果很嚴(yán)重。
2,不可重復(fù)讀。
在同一個(gè)事務(wù)中,再次讀取數(shù)據(jù)時(shí)【就是你的select操作】,所讀取的數(shù)據(jù),和第1次讀取的數(shù)據(jù),不一樣了。就是不可重復(fù)讀。
舉個(gè)例子:
事務(wù)1:查詢有雙人床房間。99號(hào)房間,有雙人床。
事務(wù)2:將99號(hào)房間,改成單人床房間。
事務(wù)1:再次執(zhí)行查詢,請(qǐng)求所有雙人床房間列表,99號(hào)房間不再列表中了。也就是說,
事務(wù)1,可以看到其他事務(wù)所做的修改。
在不可重復(fù)讀,里面,可以看到其他事務(wù)所做的修改,而導(dǎo)致2次的查詢結(jié)果不再一樣了。
這里的修改,是提交過的。也可以是沒有提交的,這種情況同時(shí)也是臟讀。
如果,數(shù)據(jù)庫(kù)系統(tǒng)的隔離級(jí)別。允許,不可重復(fù)讀。那么你啟動(dòng)一個(gè)事務(wù),并做一個(gè)select查詢操作。
查詢到的數(shù)據(jù),就有可能,和你第2次,3次...n次,查詢到的數(shù)據(jù)不一樣。一般情況下,你只會(huì)做一次,select
查詢,并以這一次的查詢數(shù)據(jù),作為后續(xù)計(jì)算的基礎(chǔ)。因?yàn)樵试S出現(xiàn),不可重復(fù)讀。那么任何
時(shí)候,查詢到的數(shù)據(jù),都有可能被其他事務(wù)更新,查詢的結(jié)果將是不確定的。
注:如果允許,不可重復(fù)讀,你的查詢結(jié)果,將是不確定的。一個(gè)不確定的結(jié)果,你能容忍嗎?
3,幻讀
事務(wù)1讀取指定的where子句所返回的一些行。然后,事務(wù)2插入一個(gè)新行,這個(gè)新行也滿足事務(wù)1使用的查詢
where子句。然后事務(wù)1再次使用相同的查詢讀取行,但是現(xiàn)在它看到了事務(wù)2剛插入的行。這個(gè)行被稱為幻象,
因?yàn)閷?duì)事務(wù)1來說,這一行的出現(xiàn)是不可思議的。
舉個(gè)例子:
事務(wù)1:請(qǐng)求沒有預(yù)定的,雙人床房間列表。
事務(wù)2:向Reservation表中插入一個(gè)新紀(jì)錄,以預(yù)訂99號(hào)房間,并提交。
事務(wù)1:再次請(qǐng)求有雙人床的未預(yù)定的房間列表,99號(hào)房間,不再位于列表中。
注:幻讀,針對(duì)的是,Insert操作。如果事務(wù)2,插入的記錄,沒有提交。那么同時(shí)也是臟讀。
clob = rs.getClob(fieldName);
String rtn=clob.getSubString((long)1,(int)clob.length());
線性表的靜態(tài)單鏈表存儲(chǔ)結(jié)構(gòu) :
#define MAXSIZE 100;
typedef struct{
? ElemType data;
? int cur;
}component,SLinkList[MAXSIZE];
分析 :
這種描述方法便于在不設(shè) ” 指針 ” 類型的高級(jí)程序設(shè)計(jì)語(yǔ)言中 , 使用的鏈表結(jié)構(gòu) . 數(shù)組的零分量可看成頭節(jié)點(diǎn) . 這種結(jié)構(gòu)仍然需要預(yù)先分配一個(gè)較大的空間 . 但在插入和刪除的時(shí)候 , 不需要移動(dòng)元素 . 僅需要修改指針 . 所以仍然具有鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)的主要優(yōu)點(diǎn) .
(1) ?? 在靜態(tài)單鏈表中 , 查找第一個(gè)值為 e 的元素 .
int LocateElem_L(SLinkList S, ElemType e)
{
?? i = S[0].cur;
?? while(i && S[i].data != e) i=S[i].cur;
?? return i;
}
分析
:
如果找不到相應(yīng)的元素
,
返回值為
0.
(2)
????
將一維數(shù)組
space
中的各個(gè)分量
,
鏈成一個(gè)備用的鏈表
.
space[0].cur
為頭指針
.
void InitSpace(SLinkList &space){
?? for(i =0;i<MAXSIZE-1;++i)
????? space[i].cur = i+1;
?? space[MAXSIZE-1].cur =0;
}
(3) ?? 如果備用空間的鏈表非空 , 則返回分配的節(jié)點(diǎn)下標(biāo) ,
否則 , 返回 0;
int Malloc_SL(SLinkList &space){
?? i=space[0].cur;
?? if(space[0].cur)
????? space[0].cur =space[i].cur;
?? return i;
}
(4) 將下標(biāo)為 k 的空閑節(jié)點(diǎn)回收到備用鏈表 .
void Free_SL(SLinkList &space,int k)
{
space[k].cur =space[0].cur;
space[0].cur = k;
}
(4)
??
計(jì)算集合運(yùn)算
(A-B
)
∪
(B-A)
假設(shè)由終端輸入集合元素
,
先建立表示集合
A
的靜態(tài)鏈表
S,
然后在輸入集合
B
的元素的同時(shí)查找
S
表
,
如果存在相同的元素
,
則從
S
表中刪除
,
否則將其插入到
S
表中
.
具體代碼如下
:
void difference(SLinkList &space , int &s)
{
?????
InitSpace_SL(space);
????? s = Malloc_SL(space);
????? r=s;
????? scanf(m,n);
?????
for(j=1;j<=m;++j)
{???? i =Malloc_SL(space);
??????????
scanf(space[i].data);
?????????? space[r].cur =i;
?????????? r=i;
????? }? space[r].cur=0;
for
(j=1;j<=n;++j){
??? scanf(b);
??? p=s;k=space[s].cur;
???
while(k!=space[r].cur && space[k].data !=b)
??? { p=k;k=space[k].cur;}
if
(k==space[r].cur)
{
???
?? i = Malloc_SL(space);
???
?? space[i].data = b;
???
?? space[i].cur = space[r].cur;
???
?? space[r].cur = i;
???
?? r=i;
??? }
???
else{
????? space[p].cur =space[k].cur;
?????
Free_SL(space,k);
????? if(r==k)
????? r=p;
??? }
}
}
鏈?zhǔn)酱鎯?chǔ)表示 :
typedef struct LNode{
? ElemType ? data;
? Struct LNode *next;
}LNode,*LinkList;
基本操作在鏈表上的實(shí)現(xiàn) :
(1) ?? 單鏈表的取元素算法(經(jīng)典)
Status GetElem_L(LinkList L, int i,ElemType &e)
{
p=L->next; j=1;
while(p && j<i)
{
????? p=p->next;++j;
}
if(!p || j>i) return ERROR;
e=p->data;
return OK;
}
算法分析
:
基本操作是
:
比較
j
和
I,
并把指針后移
,
循環(huán)體執(zhí)行的次數(shù)
,
與被查元素的位置有關(guān)
.
假設(shè)表長(zhǎng)為
n,
如果
1<=i<=n,
那么循環(huán)體中語(yǔ)句的執(zhí)行次數(shù)為
i-1.
否則次數(shù)為
n
所以時(shí)間復(fù)雜度為
O(n).
Status ListInsert_L(LinkList &L, int i,ElemType e)
{
?? p=L;j=0;
?? while(p&&j<i-1)
????? { p=p->next;++j}
?? if(!p || j>i-1)
????? return ERROR;
?? s = (LinkList)malloc(sizeof(LNode));
?? s->data = e;
?? s->next = p->next;
?? p->next =s;
?? return OK;
}
(3)
??
刪除元素算法
Status ListDelete_L(LinkList &L, int i,ElemType &e)
{
?? p=L;j=0;
while(p &&j<i-1)
?? {p=p->next;++j}
if(!p ||j>i-1)
????? return? ERROR;
??
q=p->next;
?? p->next =q->next;
?? e =q->data;
?? free(q);
?? return OK;
}
算法分析
:
插入和刪除算法
,
都要先找到第
i-1
個(gè)節(jié)點(diǎn)
,
所以時(shí)間復(fù)雜度為
O(n);
void CreateList_L(LinkList &L,int n){
?L =(LinkList)malloc(sizeof(LNode));
?L->next = null;
? for(i = n;i>0;--i){
?
? p =(LinkList)malloc(sizeof(LNode));
? scanf(&p->data);
? p->next = L->next;
? L->next =p;
? }
}
算法分析 :
按照逆序循環(huán)輸入 n 個(gè)數(shù)據(jù)元素的值 , 建立新節(jié)點(diǎn) . 并插入 . 因此算法的時(shí)間復(fù)雜度為 O(n).