2006年6月15日
1, 脏读
一个事务读到另一个事务,尚未提交的修改,就是脏读。这里所谓的修改,除了Update操作,不要忘了,还包括
Insert和Delete操作。
脏读的后果:如果后一个事务回滚,那么它所做的修改,统统都会被撤销。前一个事务读到的数据,就是垃圾数据。
举个例子:预订房间。
有一张Reservation表,往表中插入一条记录,来订购一个房间。
事务1:在Reservation表中插入一条记录,用于预订99号房间。
事务2:查询,尚未预定的房间列表,因为99号房间,已经被事务1预订。所以不在列表中。
事务1:信用卡付款。由于付款失败,导致整个事务回滚。
所以插入到Reservation 表中的记录并不置为持久(即它将被删除)。
现在99号房间则为可用。
所以,事务2所用的是一个无效的房间列表,因为99号房间,已经可用。如果它是最后一个没有被预定的房间,那么这将是一个严重的失误。
注:脏读的后果很严重。
2,不可重复读。
在同一个事务中,再次读取数据时【就是你的select操作】,所读取的数据,和第1次读取的数据,不一样了。就是不可重复读。
举个例子:
事务1:查询有双人床房间。99号房间,有双人床。
事务2:将99号房间,改成单人床房间。
事务1:再次执行查询,请求所有双人床房间列表,99号房间不再列表中了。也就是说,
事务1,可以看到其他事务所做的修改。
在不可重复读,里面,可以看到其他事务所做的修改,而导致2次的查询结果不再一样了。
这里的修改,是提交过的。也可以是没有提交的,这种情况同时也是脏读。
如果,数据库系统的隔离级别。允许,不可重复读。那么你启动一个事务,并做一个select查询操作。
查询到的数据,就有可能,和你第2次,3次...n次,查询到的数据不一样。一般情况下,你只会做一次,select
查询,并以这一次的查询数据,作为后续计算的基础。因为允许出现,不可重复读。那么任何
时候,查询到的数据,都有可能被其他事务更新,查询的结果将是不确定的。
注:如果允许,不可重复读,你的查询结果,将是不确定的。一个不确定的结果,你能容忍吗?
3,幻读
事务1读取指定的where子句所返回的一些行。然后,事务2插入一个新行,这个新行也满足事务1使用的查询
where子句。然后事务1再次使用相同的查询读取行,但是现在它看到了事务2刚插入的行。这个行被称为幻象,
因为对事务1来说,这一行的出现是不可思议的。
举个例子:
事务1:请求没有预定的,双人床房间列表。
事务2:向Reservation表中插入一个新纪录,以预订99号房间,并提交。
事务1:再次请求有双人床的未预定的房间列表,99号房间,不再位于列表中。
注:幻读,针对的是,Insert操作。如果事务2,插入的记录,没有提交。那么同时也是脏读。
posted @
2009-04-13 12:37 liulang 阅读(7312) |
评论 (0) |
编辑 收藏
clob = rs.getClob(fieldName);
String rtn=clob.getSubString((long)1,(int)clob.length());
posted @
2009-04-08 12:17 liulang 阅读(3169) |
评论 (3) |
编辑 收藏
在resin3.0中,deploy是默认的发布目录,在MyEclipse中直接发布到resin的deploy目录中,起动服务器就会运行发布的项目,而在resin-3.1.1中发布到deploy目录下的项目不回运行,需要修改conf目录下的resin.conf文件,用editplus等文本编辑器打开,大概在229行左右,有一行 <web-app-deploy path="webapps"/>是建产发布目录路径的,我们在后边加上一行 <web-app-deploy path="deploy"/>,这样在deploy目录下的项目就能正常运行了。
posted @
2009-04-07 10:22 liulang 阅读(685) |
评论 (0) |
编辑 收藏
摘要: java折半查找算法
阅读全文
posted @
2007-09-06 18:02 liulang 阅读(5213) |
评论 (4) |
编辑 收藏
摘要: 这是面试的时候,最后一道算法题, 可能不习惯手写代码, 做错了,太没面子了...
回来一上机就写出来了!
阅读全文
posted @
2007-09-05 17:04 liulang 阅读(6481) |
评论 (5) |
编辑 收藏
摘要: 面试老考这个,都背熟了
阅读全文
posted @
2007-09-05 16:58 liulang 阅读(94807) |
评论 (32) |
编辑 收藏
摘要:
阅读全文
posted @
2006-10-04 06:47 liulang 阅读(582) |
评论 (0) |
编辑 收藏
静态单链表
:
线性表的静态单链表存储结构
:
#define MAXSIZE 100;
typedef struct{
ElemType data;
int cur;
}component,SLinkList[MAXSIZE];
分析
:
这种描述方法便于在不设
”
指针
”
类型的高级程序设计语言中
,
使用的链表结构
.
数组的零分量可看成头节点
.
这种结构仍然需要预先分配一个较大的空间
.
但在插入和删除的时候
,
不需要移动元素
.
仅需要修改指针
.
所以仍然具有链式存储结构的主要优点
.
基本操作
:
(1)
在静态单链表中
,
查找第一个值为
e
的元素
.
int LocateElem_L(SLinkList S, ElemType e)
{
i = S[0].cur;
while(i && S[i].data != e) i=S[i].cur;
return i;
}
分析
:
如果找不到相应的元素
,
返回值为
0.
(2)
将一维数组
space
中的各个分量
,
链成一个备用的链表
.
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)
如果备用空间的链表非空
,
则返回分配的节点下标
,
否则
,
返回
0;
int Malloc_SL(SLinkList &space){
i=space[0].cur;
if(space[0].cur)
space[0].cur =space[i].cur;
return i;
}
(4)
将下标为
k
的空闲节点回收到备用链表
.
void Free_SL(SLinkList &space,int k)
{
space[k].cur =space[0].cur;
space[0].cur = k;
}
(4)
计算集合运算
(A-B
)
∪
(B-A)
假设由终端输入集合元素
,
先建立表示集合
A
的静态链表
S,
然后在输入集合
B
的元素的同时查找
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;
}
}
}
posted @
2006-06-16 01:06 liulang 阅读(1239) |
评论 (0) |
编辑 收藏
线性表的链式存储结构
:
链式存储表示
:
typedef struct LNode{
ElemType
data;
Struct LNode *next;
}LNode,*LinkList;
基本操作在链表上的实现
:
(1)
单链表的取元素算法(经典)
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,
并把指针后移
,
循环体执行的次数
,
与被查元素的位置有关
.
假设表长为
n,
如果
1<=i<=n,
那么循环体中语句的执行次数为
i-1.
否则次数为
n
所以时间复杂度为
O(n).
(2)
插入元素算法
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
个节点
,
所以时间复杂度为
O(n);
(4)
单链表的建立算法
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;
}
}
算法分析
:
按照逆序循环输入
n
个数据元素的值
,
建立新节点
.
并插入
.
因此算法的时间复杂度为
O(n).
posted @
2006-06-16 01:04 liulang 阅读(941) |
评论 (3) |
编辑 收藏
线性表 :
是 n(n>=0) 个相同特性数据元素的有序序列 .
顺序存储结构和实现
线性表的顺序存储结构 , 可以随机存取 . 逻辑上相邻的两个元素 , 在物理存储上也是相邻的 . 顺序存储表示 :
( 见源代码 ) 基本操作在顺序表上的实现
( 见源代码 )
四大基本操作 :
(1) 构造一个空的线性表
( 简单 )
(2) 顺序表的插入算法 .
算法分析 :
时间主要耗费在移动元素上 , 与问题的规模 (N) 和你插入元素的具体位置有关 , 即插入元素位置越靠近 , 位序 1, 消耗的时间也就越多 . 设在位序 i 插入元素的概率位 pi=1/(n+1), 移动元素的个数为 ,(n-i+1):
那么在长度为 n 的顺序表中 , 插入一个元素 , 所需移动元素的期望值为 :
E = ∑ P i*(n-i+1) (i=1,2,3,..,n+1)
=n/2;
平均移动表中的一半元素 . 时间复杂度 O( n )
(3) 顺序表的删除算法 .
算法分析 :
同上 , E = ∑ q i*(n-i) (i=1,2,3,..,n+1) qi=1/n
=(n-1)/2;
时间复杂度为 O (n);
(4) 定位算法 .
算法分析 :
基本操作是进行两个元素之间的比较 , 假设存在该元素为 a i( 1 ≤ i ≤ n), 则比较的次数为 i, 否则为 n, 所以算法时间复杂度为 O(n); 顺序存储结构的性能小结 :
优点 :
(1) 可以随机存取 , 顺序表中的数据元素 .
(2) 存储空间连续 , 不必要增加额外的存储空间 . 比如如果你以链式结构存储 , 那么你就不得不增加一个指针域 .
缺点 :
(1) 插入和删除一个元素 , 需要移动大量元素 , 耗费时间 .
(2) 初始化顺序表的时候 , 要预先分配一个最大空间 . 有时候会使存储空间得不到充分利用 .
(3) 容量难以扩充 .
posted @
2006-06-15 17:25 liulang 阅读(1503) |
评论 (0) |
编辑 收藏