`
hyhai7
  • 浏览: 34966 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

数据库并发一致性案例分析

阅读更多

转载@http://www.cnblogs.com/zhenyulu/articles/633486.html

本部分内容为《数据库原理》课程中的一个课堂案例,幻灯片提供的动画演示有助于理解并发控制的本质,本文内容为幻灯片的摘要。

1、下载本文所对应的幻灯片; 2、下载本文对应的VS2005代码

如果你对自己并发控制的能力很有自信的话,读完“一、问题提出”后直接可以跳转到“四、看来问题真不简单”处阅读。

本文最后给出了部分测试用代码的简单讲解。

 

一、问题提出

设某银行存款帐户数据如下表:

现在要求编写一程序,完成两项功能:存款取款。每次操作完成后向明细表中插入一行记录并更新帐户余额。

 

二、问题似乎很简单

  • 解决办法:

① 读取最后一行记录的帐户余额数据

② 根据存、取款金额计算出新的帐户余额

③ 将新的记录插入表中

  • 真的这么简单?

在不考虑并发问题的情况下是可行的

如果考虑并发,问题就多了(导致余额计算错误!请参考幻灯片与案例代码)

 

三、让我来想一想

既然存在并发问题,那么解决并发问题的最好办法就是加锁呀!动手试试~~

怎么加锁?加什么锁?

读之前加共享锁?不行!(参考幻灯片)

读之前加排它锁?还是不行!(参考幻灯片)

当然,问题还不止这些!如何读取最后一行记录?你会发现随着明细记录的增加越来越没效率。

 

四、看来问题真的不是这么简单

问题出在哪里那?从系统设计一开始我们就走错了!重新设计!

 

  • 为什么引入冗余数据?

确保帐户余额在唯一的地方进行存储

避免了读取帐户余额时访问大量数据并排序

  • 新的问题:

我们无法直接对数据库进行锁操作

必须通过合理的事务隔离级别完成并发控制(ReadUnCommitted、ReadCommitted、RepeatableRead、Serializable),哪一种好呢?

 

五、着急吃不着热豆腐

看来我们必须对各事务隔离级别逐一分析

① ReadUnCommitted

显然不行

在这个事务隔离级别下连脏数据都可能读到,何况“脏”帐户余额数据。

② ReadCommitted

也不行

该隔离级别与二级封锁协议相对应。读数据前加共享锁,读完就释放。前面分析过,此处不再赘述。

③ RepeatableRead

这个隔离级别比较迷惑人,需要仔细分析:

RepeatableRead对应第三级封锁协议:读前加共享锁,事务完成才释放。

(过程参考幻灯片,结论:可以避免并发问题,但带来了死锁!)

④ Serializable

该事务隔离级别在执行时可以避免幻影读。

但对于本案例执行效果与RepeatableRead一样(效率低下,成功率低,还有讨厌的死锁!)。

似乎走到了绝路

经过重新设计后仍然无法让人满意的解决问题!连最高隔离级别都会在高度并发时因为死锁造成很大一部分事务执行失败!

 

六、绝处逢生

  • 原因分析

死锁的原因是因为读前加S锁,而写前要将S锁提升为X锁,由于S锁允许共享,导致X锁提升失败,产生死锁。

  • 解决办法

如果在读时就加上X锁,就可避免上述问题(从封锁协议角度这似乎不可能,但确完全可行!)

其实SQL Server允许在一条命令中同时完成读、写操作,这就为我们提供了入手点。

在更新帐户余额的同时读取帐户余额,就等同于在读数据前加X锁。命令如下:

UPDATE Account
SET @newBalance = Balance = Balance + 100
WHERE AccountID = 1

上面的命令对帐户余额增加100元(粗体部分)

同时读取更新后的帐户余额到变量@newBalance中

由于读取操作融入写操作中,实现了读时加X锁,避免因锁的提升造成死锁。

完成存取款的操作可由下面的伪代码实现:

@amount = 存取款的金额
BEGIN TRANSACTION
Try
{
UPDATE Account
SET @newBalance = Balance = Balance + @amount
WHERE AccountID = 1
INSERT INTO AccountDetail (AccountID, Amount, Balance)
VALUES (1, @amount, @newBalance)
COMMIT
}
Catch
{
ROLLBACK
}
  • 改造结果:

通过上述改造,事务中只有写操作而没有了读操作

因此甚至将事务隔离级别设置为ReadUnCommitted都能确保成功执行

写前加X锁,避免了因提升S锁造成死锁的可能

  • 实验结果:

所有并行执行的事务全部成功

帐户余额全部正确

程序执行时间同串行执行各事务相同

 

七、事情并没有结束

还有可优化的余地:网络带宽受到限制时,数据在网络上传输的时间往往比对数据进行读写操作的时间要长。

  • 一个典型的更新过程:

1、读前加锁

2、帐户数据从网上传过来

3、修改、插入新记录

4、将改后的数据通过网络传回去

5、数据库提交更新并解锁。

如果网速很慢,资源锁定时间就很长。

  • 解决办法:

使用存储过程,修改后的更新过程:

1、将存、取款用到的数据通过网络发给存储过程。

2、数据加锁、修改、解锁。

3、将结果通过网络回传。

将网络延迟放到了事务之外,提高了事务效率。

  • 实验结果

由于在同一台机器上执行数据库与应用程序,实验结果表明存储过程的执行效率不如直接在应用程序中通过命令调用高。

如果能在一个带宽受到限制的网络上将数据库与应用程序分离,然后测试,相信会有令人满意的结果。(有待具体实验证实)

 

八、思考

最近园子里面关于O/R Mapping讨论得很激烈,想问大家一个问题,就是对于上述问题,O/R Mapping是否提供了解决办法,允许在Mapping的同时更加精细的控制更新手段呢?


 

附:代码分析

本文测试用代码共有5个项目,分别是:

1、SimpleUpdate(最简单的更新,在没有并发时工作得很好)

2、SimpleUpdateInMultiThread(引入并发,10个线程同时工作,结果上面的更新策略出现了问题)

3、RepeatableReadUpdate(本文第五部分中,使用RepealableRead事务隔离级别的并发更新,随没有错误,但导致了死锁)

4、AnotherMethod(本文最后给出的更新方式,高效且没有死锁)

5、UseStoredProcedure(使用存储过程完成更新)创建存储过程的代码可以从DataBase目录下找到。

  • 准备工作

首先在SQL Server 2005中建立一空数据库DBApp,程序执行时会自动在此数据库中创建所需要的表以及记录。

  • 1、SimpleUpdate
public void Operation(double amount)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings.Get("ConnectionString"));
SqlCommand cmd = new SqlCommand();
cmd.Connection = conn;
conn.Open();
cmd.CommandText = "SELECT TOP 1 Balance FROM AccountDetail WHERE AccountID = 1 ORDER BY AccountDetailID DESC";
double oldBalance = Convert.ToDouble(cmd.ExecuteScalar());
double newBalance = oldBalance + amount;
cmd.CommandText = "INSERT INTO AccountDetail (AccountID, Amount, Balance) VALUES (1, " +
amount.ToString() + ", " + newBalance.ToString() + ")";
cmd.ExecuteNonQuery();
conn.Close();
}

这段代码没有考虑任何并发问题,也没有使用事务,仅仅是读取最后一条记录的余额数据,然后根据余额和存取钱金额算出最新余额,并将数据插入到明细记录中。在没有并发问题时,该程序可以很好的执行。调用该段代码的主程序如下:

public static void Main()
{
double[] amounts = {-100, 2000, -500, 300, 150, -800, -50, 100, -400, 200};
Account account = new Account();
foreach(double amount in amounts)
{
account.Operation(amount);
}
}

该程序模拟了10次存取款操作,程序执行结果完全正确。

  • 2、SimpleUpdateInMultiThread

在这段代码中引入了并发操作,通过10个线程模拟10个人同时进行存取款操作,为了使得模拟真实有效,特意在两条SQL命令执行之间随机休息了一段时间,其它代码同上没有什么变化,结果会发现,帐户余额计算多处出现错误。

......
public static void Main()
{
double[] amounts = {-100, 2000, -500, 300, 150, -800, -50, 100, -400, 200};
ManualResetEvent[] doneEvents = new ManualResetEvent[amounts.Length];
Account[] accountArray = new Account[amounts.Length];
for(int i=0; i<amounts.Length; i++)
{
doneEvents[i] = new ManualResetEvent(false);
accountArray[i] = new Account(amounts[i],  doneEvents[i]);
ThreadPool.QueueUserWorkItem(new WaitCallback(accountArray[i].ThreadPoolCallback), i);
}
WaitHandle.WaitAll(doneEvents);
ShowResult();
}
......
public void Operation()
{
......
double newBalance = oldBalance + amount;
//为了表示随机性,先随机休息一段时间。
Thread.Sleep(rand.Next(500));
cmd.CommandText = "INSERT INTO AccountDetail (AccountID, Amount, Balance) VALUES (1, " +
amount.ToString() + ", " + newBalance.ToString() + ")";
......
}
  • 3、RepeatableReadUpdate

该段代码引入了事务,并将事务隔离级别设置为RepeatableRead,程序经过漫长的执行后,你会发现尽管没有出现任何余额计算错误,但10个线程中仅有一半左右执行成功,其它线程执行失败,这是由于内部死锁问题造成的。感兴趣的话可以查看SQL Server中锁的状态。

public void Operation()
{
SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings.Get("ConnectionString"));
SqlCommand cmd1 = new SqlCommand();
SqlCommand cmd2 = new SqlCommand();
SqlCommand cmd3 = new SqlCommand();
cmd1.Connection = conn;
cmd2.Connection = conn;
cmd3.Connection = conn;
conn.Open();
SqlTransaction tx = conn.BeginTransaction(IsolationLevel.RepeatableRead);
try
{
cmd1.CommandText = "SELECT Balance FROM Account WHERE AccountID = 1";
cmd1.Transaction = tx;
double oldBalance = double.Parse(cmd1.ExecuteScalar().ToString());
double newBalance = oldBalance + amount;
//为了表示随机性,先随机休息一段时间。
Thread.Sleep(rand.Next(500));
cmd2.CommandText = "INSERT INTO AccountDetail (AccountID, Amount, Balance) VALUES (1, " +
amount.ToString() + ", " + newBalance.ToString() + ")";
cmd2.Transaction = tx;
cmd2.ExecuteNonQuery();
cmd3.CommandText = "UPDATE Account SET Balance = " + newBalance.ToString() + " WHERE AccountID=1";
cmd3.Transaction = tx;
cmd3.ExecuteNonQuery();
tx.Commit();
}
catch
{
tx.Rollback();
throw new Exception("Transaction Error!");
}
conn.Close();
}
  • 4、AnotherMethod

该段代码实现了在更新的同时完成读操作,避免了因锁的提升带来的并发问题。10个线程同时执行成功,并且执行时间与串行执行的时间几乎相同,真正意义上实现了可串行化。

public void Operation()
{
SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings.Get("ConnectionString"));
SqlCommand cmd1 = new SqlCommand();
SqlCommand cmd2 = new SqlCommand();
cmd1.Connection = conn;
cmd2.Connection = conn;
conn.Open();
SqlTransaction tx = conn.BeginTransaction(IsolationLevel.ReadUnCommitted);
try
{
cmd1.CommandText = "UPDATE Account SET @newBalance = Balance = Balance +" + this.amount.ToString() +
" WHERE AccountID = 1";
SqlParameter param = new SqlParameter("@newBalance", SqlDbType.Money, 8);
param.Direction = ParameterDirection.Output;
cmd1.Parameters.Add(param);
cmd1.Transaction = tx;
cmd1.ExecuteNonQuery();
double newBalance = Convert.ToDouble(cmd1.Parameters["@newBalance"].Value);
//为了表示随机性,先随机休息一段时间。
//Thread.Sleep(rand.Next(500));
cmd2.CommandText = "INSERT INTO AccountDetail (AccountID, Amount, Balance) VALUES (1, " +
amount.ToString() + ", " + newBalance.ToString() + ")";
cmd2.Transaction = tx;
cmd2.ExecuteNonQuery();
tx.Commit();
}
catch
{
tx.Rollback();
throw new Exception("Transaction Error!");
}
conn.Close();
}
  • 5、UseStoredProcedure

该段代码使用存储过程实现。存储过程如下,利用了SQL Server 2005中提供的Try...Catch结构配合事务也可以很好的完成上述任务。

CREATE PROCEDURE [dbo].[Operation]
-- Add the parameters for the stored procedure here
@amount money,
@successed char(1) output
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @newBalance money
BEGIN TRY
BEGIN TRANSACTION
UPDATE Account SET
@newBalance = Balance = Balance + @amount
WHERE AccountID = 1
INSERT INTO AccountDetail(AccountID, Amount, Balance)
VALUES (1, @amount, @newBalance)
COMMIT TRANSACTION
SET @successed = 'T'
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION
SET @successed = 'F'
END CATCH
END
posted on 2007-01-29 15:25 吕震宇 阅读(8757) 评论(31)  编辑 收藏
 

评论

#1楼 2007-01-29 16:58 阿水      
没有那么复杂吧?这样的情况,只要是管理软件的话
基本都碰到过,没有哪个业务能简单到直接更新或者新增一条记录。
我的做法是,在开始处理数据时 给 指定记录加锁。
所谓加锁就是 update table1 set no = no where no = 1
这样的语句,作用是出了你别人不能修改这条记录。
等你处理完了,事务提交,那么别的更新语句才能进入。
另ORM能不能解决这个问题,我觉得挺难。
比较好的设计或许能避免吧。
 回复 引用 查看   

#2楼[楼主2007-01-29 17:23 吕震宇      
@阿水 
是有些复杂,但在你的系统里,有没有遇到过有人将no设置为1,但却忘了改回来(因为意外或为其他什么原因)的时候呢?我做数据库时发现什么不可能发生的事情都可能发生。如果再手工改回来就有点太麻烦了,维护任务太艰巨。
 回复 引用 查看   

第四条:AnotherMethod
因为update的时候。已经为这条记录X锁了。还有必要在特意指出“UNCOMMITTED”隔离级别吗?
 回复 引用   

也许我会在事务中先
select amount读取金额
insert 插入记录
update 更新金额

这样就出错了?也许在select的时候造成了脏读?!以后我要注意这个问题了:)

谢谢。对SQL的锁又有了一定的心得。
 回复 引用   

#5楼 2007-01-29 18:02 阿水      
update table1 set no = no where no = 1
刚搂主说 有没有遇到过有人将no设置为1,但却忘了改回来
我这里没有把NO改成1,
只是一条不更改数据的UPDATE作用就是锁定数据,
只要你UPDATE了,虽然什么都没修改,但是
数据库还是会锁定这条记录的,直到你的事务提交。

加派他锁的时候,条件
一般是主键的,
比如我处理一张单据的总数量。
那么开始处理之前,我需要这样写

开始事务
UPDATE Bill01Mt set Bill01No = Bill01No where Bill01No = '123'
然后开始处理业务逻辑
(这是必须保证,没有人能更新Bill01No = '123'这条记录)
提交事务

这里不说异常会滚得情况了。

其实并发,我们现在的系统里也存在隐患的
不过那时没有办法的,只是发生概率很低 

另外个人认为ORM处理业务逻辑的话,对并发的控制
肯定要比用存储过程差(全是猜得,没有测试过)
 回复 引用 查看   

#6楼[楼主2007-01-29 19:47 吕震宇      
@小春[匿名] 
确实没有必要特意指出“UNCOMMITTED”隔离级别,我只是想说“UnCommitted”事务隔离级别遵循的是一级封锁协议,即写前加X锁,事务完成后释放,因此完全符合本案例的要求。 

@阿水 
呵呵,我没有看到是set no = no,原来是个虚假更新,不错!这样确实可以确保此类并发问题!我也认为这是一个非常可行的方法。
 回复 引用 查看   

#7楼 2007-01-29 20:51 yus[未注册用户]
我认为不能依赖数据库的事务锁,可以考虑使用保证所有业务同步进行来确保在同一时刻只有一个线程在运行。比如使用lock来同步线程!
 回复 引用   

#8楼 2007-01-29 21:11 qmxle[未注册用户]
如果是Oracle的话,可以用Select ... for Update
 回复 引用   

#9楼 2007-01-29 21:12 qmxle[未注册用户]
@yus 
这样的话,如果是负债均衡就不行了。
 回复 引用   

#10楼[楼主2007-01-29 21:26 吕震宇      
@qmxle 

查了查SQL Server 2005的文档,摘了一段: 

“在 SQL Server 2005 中,除一些例外情况之外,仅当使用了 WITH 关键字指定表提示时,FROM 子句中才支持这些提示。指定表提示时必须使用括号。 

使用或不使用 WITH 关键字均可使用的表提示如下:NOLOCK、READUNCOMMITTED、UPDLOCK、REPEATABLEREAD、SERIALIZABLE、READCOMMITTED、FASTFIRSTROW、TABLOCK、TABLOCKX、PAGLOCK、ROWLOCK、NOWAIT、READPAST、XLOCK 和 NOEXPAND。如果指定的表提示不含 WITH 关键字,则必须单独指定该提示。” 

例如:FROM t WITH (FASTFIRSTROW, INDEX(myindex)) 

也许这可以和Oracle中的for update对应吧。不过我还没有测试过,有时间会试试的。
 回复 引用 查看   

#11楼[楼主2007-01-29 21:41 吕震宇      
@qmxle 

测试了一下,完全可行! 
如果将示例3、RepeatableReadUpdate 中的SELECT命令修改一下就可以避免死锁问题,解决办法如下: 

将代码中的 

SELECT Balance FROM Account WHERE AccountID = 1 

更改为: 

SELECT Balance FROM Account WITH(UPDLOCK) WHERE AccountID = 1 

然后编译执行,一切OK!不过这种用法似乎只能在SQL Server 2005中使用。
 回复 引用 查看   

#12楼 2007-01-29 22:48 极地银狐.NET      
好文章我一定要mark的
 回复 引用 查看   

#13楼 2007-01-30 00:17 赵宝民[未注册用户]
恩 写的很是不错 业务出发 好 

是否可以把 帐户余额数据 这类会发生并发冲突的对象作为动态数据对象放在应用服务器上 而不是做为数据库中的相对静态的数据来处理呢 
也许这样能好一些吧 不过实现比较麻烦
 回复 引用   

#14楼 2007-01-30 09:50 阿水      
并发问题,在数据库类型的开发中,非常常见的
我以前还碰到过有的业务,会发生死锁(理论上)
但是也没有办法,最后就那么用了,用户大概用了
半年吧,发生过一次问题。不是死锁,而是数据异
常了。复杂的业务有的时候真的没办法,当然了
设计上也是不够完美。哈哈 
我一般避免死锁的办法就是使用虚假更新,
一般的数据库都可以(只要支持事务)
不过 楼主,把这个问题提出来,还是很有意思的 
尤其是对很多没有意识到并发的危险性的人 哈哈
 回复 引用 查看   

#15楼 2007-02-01 10:15 net[未注册用户]
不 mark 对不起高人
 回复 引用   

#16楼 2007-02-01 10:49 大剑师      
@阿水
^_^
 回复 引用 查看   

#17楼 2007-02-03 23:30 lizhiwen      
好久没有看见吕老师写文章了,支持!~
 回复 引用 查看   

#18楼 2007-02-08 17:54 生米煮成稀饭      
我都是直接通过指定加锁类型来避免的
 回复 引用 查看   

#19楼 2007-02-26 16:02 wengwen[未注册用户]
^_^^_^^_^,支持!~
 回复 引用   

#20楼 2007-03-26 12:24 bengxia      
这个SQL SERVER 都2005了,怎么不学学ORACLE的锁机制呢。。。
 回复 引用 查看   

#21楼 2007-04-09 13:53 yunhuasheng      
very good,对事务理解加深了。
 回复 引用 查看   

#22楼 2007-05-21 17:40 fangsang[未注册用户]
必读
 回复 引用   

#23楼 2007-06-04 21:28 king[未注册用户]
楼主有个例子没有说清楚呀!我觉得还是比较重要的就是加排他锁时所发生的幻影读的问题
 回复 引用   

#24楼 2007-07-21 15:35 Lantian[未注册用户]
@吕震宇 

吕老师,表锁定提示在2000就有了,也可以使用 
您可以找到SQL2000的帮助文档,里边就有介绍
 回复 引用   

#25楼 2008-05-31 17:44 easyskys      
这种情况在单据号的自动增加中会经常用到,先取得最大的单据号,再+1,然后insert,看了这篇文单后发现原来写法都有问题,想了很久也没想到办法,请问有什么好的解决办法?非常感谢!
 回复 引用 查看   

#26楼 2008-06-19 19:38 cn_xzw[未注册用户]
老师讲的很有启发!目前做的项目中一个财务的资金流水表就碰到并发问题.不能等到用户出现问题再去解决,应该先研究可能出现问题,然后尽力解决;

@easyskys 单据号问题也会发生多用户同时保存出现单据号重复的可能,一个笨方法是,告诉用户先保存空单据,把单据号先占用;避免用户输入数据数据之后出现,单据重复问题!
 回复 引用   

#27楼 2008-07-17 13:21 Kevin.Qian[未注册用户]
这种情况可以考虑用单独一个表用来存放当前可以使用的最大单据号,这个表可以只有一条数据,这样子你很容易用上面提到的方法操作这个表中的最大单号 

to easyskys: 
这种情况在单据号的自动增加中会经常用到,先取得最大的单据号,再+1,然后insert,看了这篇文单后发现原来写法都有问题,想了很久也没想到办法,请问有什么好的解决办法?非常感谢! 
 回复 引用   

#28楼 2008-11-25 14:24 dachuan      
不错!学习
 回复 引用 查看   

#29楼 2009-11-19 14:43 seuhuan[未注册用户]
没怎么看懂~~~

......................................................
读之前加共享锁?不行!(参考幻灯片)
读之前加排它锁?还是不行!(参考幻灯片)
......................................................
我看过lz的ppt slide9,还是有点不懂
读之前既然加上了排它锁,那么单位那侧读不了数据,直到银行那边对其更新commit了....这样单位读的时候就是300,而不是400了把?这样该不会有啥问题了把?
 回复 引用   

#30楼 2010-05-25 16:41 yellowsail      
读之前加排它锁?还是不行!(参考幻灯片)
一级封锁协议,修改前加排他锁,是不会有丢失修改。所以我觉得是行的
 回复 引用 查看   

分享到:
评论

相关推荐

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第二阶段55讲、线程上下文类加载器以及数据库驱动案例分析.mp4 │  └─第三阶段  Java并发编程.png  Java高并发第三阶段(JUC).png  高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解.mkv ...

    2014-15系统分析师复习笔记精华版(20180227150716).pdf

    分布式数据库必须保证数据库全局数据一致性,并发操作可串行性,和故障的全局性; 【特点】 (1)数据独立性与位置透明性; (2)集中和节点自治相结合; (3)支持全局数据库的一致性和可恢复性; (4)复制透明性...

    大规模分布式系统架构与设计实战

    分布式系统的数据分布、复制、一致性、容错、可扩展性等。范型篇--介绍谷歌、微软、阿里巴巴等知名互联网公司的大规模分布式存储系统架构,涉及分布式文件系统、分布式键值系统、分布式表格系统以及分布式数据库技术...

    汪文君高并发编程实战视频资源全集

    │ 高并发编程第二阶段55讲、线程上下文类加载器以及数据库驱动案例分析.mp4 │  └─第三阶段  Java并发编程.png  Java高并发第三阶段(JUC).png  高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解.mkv ...

    分析MySQL并发下的问题及解决方法

    对于数据库系统来说在多用户并发条件下提高并发性的同时又要保证数据的一致性一直是数据库系统追求的目标,既要满足大量并发访问的需求又必须保证在此条件下数据的安全,为了满足这一目标大多数数据库通过锁和事务...

    MySQL 事务(五).pdf

    案例研究:通过实际案例分析,展示事务在复杂查询中的应用。 适用人群 数据库管理员:需要深入理解MySQL事务管理以维护数据完整性。 后端开发者:在应用开发中需要执行事务操作以保证数据一致性。 数据分析师:在...

    开涛高可用高并发-亿级流量核心技术

    11.6.2 一致性哈希 226 11.6.3 快速恢复 226 12 连接池线程池详解 227 12.1 数据库连接池 227 12.1.1 DBCP连接池配置 228 12.1.2 DBCP配置建议 233 12.1.3 数据库驱动超时实现 234 12.1.4 连接池使用的一些建议 235 ...

    springboot-:记录实现高并发的解决方案

    (2)mysql主从复制,保持数据一致性 (3)使用druid的监控功能 (4)log4j2日志介绍和配置说明 2.redis哨兵模式的实现,实现高可用 主库写,从库读 day02 (1)两次md5,第一次客户端明文+固定盐值 第二次客户端第一次...

    价值过亿的架构师训练营课面试题和答案.pptx

    价值过亿的架构师训练营课面试题和...系统架构 大型网站技术架构 维基百科、淘宝、新浪微博案例分析 第8课 听课总结 系统架构 分布式缓存 一致性哈希 Hash 第9课 听课总结 系统架构 消息队列 负载均衡 数据库备份 第

    深入解析OracleDBA入门进阶与诊断案例 4/4

     8.3 并发控制和一致性读   8.4 回滚段的前世今生   8.5 Oracle 10g的UNDO_RETENTION管理增强   8.6 UNDO_RETENTION的内部实现   8.7 Oracle 10g In Memory Undo新特性   8.8 Oracle 11g UNDO表...

    深入解析OracleDBA入门进阶与诊断案例 3/4

     8.3 并发控制和一致性读   8.4 回滚段的前世今生   8.5 Oracle 10g的UNDO_RETENTION管理增强   8.6 UNDO_RETENTION的内部实现   8.7 Oracle 10g In Memory Undo新特性   8.8 Oracle 11g UNDO表...

    深入解析OracleDBA入门进阶与诊断案例 2/4

     8.3 并发控制和一致性读   8.4 回滚段的前世今生   8.5 Oracle 10g的UNDO_RETENTION管理增强   8.6 UNDO_RETENTION的内部实现   8.7 Oracle 10g In Memory Undo新特性   8.8 Oracle 11g UNDO表...

    深入解析Oracle.DBA入门进阶与诊断案例

    8.3 并发控制和一致性读 349 8.4 回滚段的前世今生 350 8.5 Oracle 10g的UNDO_RETENTION管理增强 355 8.6 UNDO_RETENTION的内部实现 357 8.7 Oracle 10g In Memory Undo新特性 358 8.8 Oracle 11g UNDO表...

    浅谈MySQL索引优化分析

    为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建...但目前它还只是关系型数据库的补充,它在数据的一致性,数据的安全性,查询的复杂性问题上和关系

    Hibernate实战(第2版 中文高清版)

     8.3.2 确保数据一致性   8.3.3 添加领域约束和列约束   8.3.4 表级约束   8.3.5 数据库约束   8.3.6 创建索引   8.3.7 添加辅助的DDL   8.4 小结  第三部分 会话对象处理  第9章 使用对象   9.1 ...

    软考历年上半年考题及答案

    界面整体测试:规范性测试、合理性测试、一致性测试和界面定制性测试 界面元素测试:窗口测试、菜单测试、图标测试、鼠标测试和文字测试。 [问题3] 文本的准确性 与程序的接口 帮助索引的检查 超链接的正确性 链接...

    云计算第二版

    2.2.4 案例分析 24 2.3 分布式锁服务Chubby 25 2.3.1 Paxos算法 26 2.3.2 Chubby系统设计 27 2.3.3 Chubby中的Paxos 29 2.3.4 Chubby文件系统 31 2.3.5 通信协议 32 2.3.6 正确性与性能 34 2.4 分布式结构化数据表...

    asp.net知识库

    第2章 并发操作的一致性问题 (2) Using sqlite with .NET Visual Studio 2005 中的新 DataSet 特性 MySQL 和 .Net2.0配合使用 与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable 与DotNet数据对象...

    oracle学习文档 笔记 全面 深刻 详细 通俗易懂 doc word格式 清晰 连接字符串

     事务控制语言(Transactional Control Language,TCL),用于维护数据的一致性,包括COMMIT(提交事务)、ROLLBACK(回滚事务)和SAVEPOINT(设置保存点)3条语句 二、 Oracle的数据类型 类型 参数 描述 字符类型...

Global site tag (gtag.js) - Google Analytics