web后台多用户操做同一条数据同步问题

场景(问题)描述以下:程序员

0,用户A、B同时打开一个页面,页面显示,客户表T_CUSTOMER字段(C_NAME、C_AGE)数据库

姓名:张三,年龄:25安全

1,A 将姓名“张三”改成“张三1”,而后保存服务器

2,B 将年龄“25”改成“30”,而后保存网络

这样A的操做就被覆盖了,姓名又变回“张三”了,你们通常怎么到处这种状况?并发

这里给出一个较易用的解决方案oracle

给表添加一字段:LAST_UPDATE,即最后更新时间性能

回放场景设计

0,用户A、B同时打开一页面,面页显示:版本控制

姓名:张三,年龄:25,LAST_UPDATE:2008-10-17 13:45:00

1,A 将姓名“张三”改成“张三1”,而后保存

重点在这里:更新数据时WHERE条件里多一条件:AND LAST_UPDATE = '2008-10-17 13:45:00'

更新成功,此时触发器会将当前时间“2008-10-17 13:46:00”赋值给LAST_UPDATE

2,B 将将年龄“25”改成“30”,而后保存

B更新数据时WHERE条件里也有这个条件:AND LAST_UPDATE = '2008-10-17 13:45:00',但此时LAST_UPDATE的值已经在A修改记录时变成2008-10-17 13:46:00

下面要作的就是给出提示了:喔哟,此信息在你发呆这段时间已被人改过啦,因此你须要返工。

触发器代码以下:
===================================================
CREATE OR REPLACE TRIGGER T_CUSTOMER
BEFORE UPDATE ON T_CUSTOMER
FOR EACH ROW
/*
记录最后修改时间
*/
BEGIN
:NEW.LAST_UPDATE := SYSDATE;
END;
===================================================

若是触发器不熟悉或者只是不喜欢用触发器,彻底能够修改记录时同时给LAST_UPDATE字段赋值,以此替代触发器的做用。

 

 

 

【并发操做】多用户并发操做的解决方案

【问题】在之前的系统开发中,常常遇到一个一样问题,就是多个用户同时并发操做一条记录,此次在交易系统开发过程当中,又出现了这样问题。好比交易商A提交单子,由审核人员B审核,此时A正在修改单位,B也正在查看这条记录,A先修改保存后B再审核保存,致使B审核经过的记录不是他所看到的。

【分析】仔细考虑问题,大概分析了三个方法, 并肯定了一个可行的方案,可能还有不完善的地方,但解决现有问题仍是绰绰有余的。

最早想的是在交易业务代码中用lock对修改方法加锁,运行时注入单例,而且对方法加同步锁,保证了业务数据的正确性, 可是效率低下,用户在使用中不方便,背离了系统能够并发操做的原则。

而后考虑使用悲观锁,此次运行时注入原型,并发操做效率提升, 可是,在同步处理数据库表时又形成锁表,这样并发效率依旧很低。

最后考虑乐观锁, 只是一种数据版本校验机制,它不作数据库层次上的锁定,须要在要并发操做的主表中加入一个"VERSION"字段或者“LASTUPDATETIME”,若是研究过oracle的SCN应该有殊途同归之妙,它的原理是这样:运行时注入原型,这时数据表并不锁住,只是每次update或insert时将VERSION更新, 当下次update,insert时,会校验VERSION,若是不一致,此时提示信息已经修改过了,而且在事务控制下rollback,这样,保证了数据的正确性,而且也不影响并发操做的效率。可是出现的问题是:若是A读了数据,将来及更新,B先更新了数据, 那么他将提交不上数据,由于VERSION已经失效,这样就形成了A从新读取数据,从新填写单据信息。 这也是乐观锁一个缺点,能够在更新前临时保存A填写的数据,再在跳转页中加载这些数据,保证了交易商不用麻烦再次输入这些数据,更新成功则清空这些临时数据

【结果】

乐观锁在并发操做问题上,保证了业务效率和数据的正确性,基本能够采用这种方案解决交易中并发问题。

●悲观锁:指在应用程序中显式地为数据资源加锁。悲观锁假定当前事务操

 

纵数据资源时,确定还会有其余事务同时访问该数据资源,为了不当前

 

事务的操做受到干扰,先锁定资源。尽管悲观锁可以防止丢失更新和不可

 

重复读这类并发问题,可是它会影响并发性能,所以应该很谨慎地使用悲

 

观锁。

 

●乐观锁:乐观锁假定当前事务操纵数据资源时,不会有其余事务同时访问

 

该数据资源,所以彻底依靠数据库的隔离级别来自动管理锁的工做。应用

 

程序采用版本控制手段来避免可能出现的并发问题。

 

----------------------------------------------------------------------------

http://blog.163.com/lqc-rabbit/blog/static/7594799320081131113720281/

.Net中的事务处理(多用户同时操做一条信息时是用-并发) [Web Applicaion in C#]
SqlConnection myConnection = new SqlConnection("Data Source=localhost;Initial Catalog=Northwind;Integrated Security=SSPI;");
myConnection.Open();

SqlTransaction myTrans = myConnection.BeginTransaction(); //使用New新生成一个事务
SqlCommand myCommand = new SqlCommand();
myCommand.Transaction = myTrans;

try
{
myCommand.CommandText = "Update Address set location='23 rain street' where userid='0001'";
myCommand.ExecuteNonQuery();
myTrans.Commit();
Console.WriteLine("Record is udated.");
}
catch(Exception e)
{
myTrans.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Sorry, Record can not be updated.");
}
finally
{
myConnection.Close();


须要注意的是,若是使用OleDb类而不是Sqlclient类来定义SQL命令和链接,咱们就必须使用OleTransation来定义事务。


数据库系统程序员须要比通常应用软件程序员懂得更多。通常程序员对事务处理的理解不够全面。事务处理的关键是在提交事务或者取消事务时,万一系统崩溃了,数据库在再次启动时,仍然须要保持数据可逻辑一致性。

最简单的事务处理过程以下:

1. 开始一个事务。进入“事务待命”状态。
2. 在“事务待命”状态,记录事务中改变的数据库记录。此改变不能直接改变数据库中的值,必须先用一个顺序的“事务日志”记录在一边。同时,对于要改变的原始记录加锁,让其它用户没法读和写。(考虑银行取款问题,能够发现若是此时两个用户都在对同一账号取数,而后减去必定金额,在前后写回数据库,银行就亏钱了)。若是记录已经被其它事务加锁,则报错;同一事务中却能够重复加锁。
3. 在“事务待命”,若是用户给出commit transaction命令,则进入“事务拷贝”状态,拷贝全部加锁的记录成备份。
4. 上面3执行完,则进入“事务更新”状态,用“事务日志”中记录一一更新实际的数据库记录。
5. 上面4执行完,则进入“事务结束”状态,释放全部的记录锁,而后抛弃“事务日志”和备份的原数据库记录。
6. 上面5作完后,事务被删除。

可是,最为关键的是,事务系统必须执行如下过程:一但数据库因为软件、硬件问题发生故障,重启动后,一旦有事务没正常删除,则:

7. 若是在“事务待命”、“事务结束”状态,则从新从5中结束事务的动做开始执行。
8. 若是在“事务更新”状态,则从新从4开始更新记录,并继续想下执行。结果,虽然系统崩溃过,但事务仍然能正常提交。

Informix、Oracle、DB2等数据库的实际事务处理流程更复杂,目的是具备更好的抵抗系统错误性质,由于事务保护是业务系统安全稳定的最后一道防线(比用2个CPU、热备份等更重要。由于那些方法对已经混乱错误的数据照样保护,结果常常形成更多问题)。因为事务处理的流程比通常程序想像得复杂,所以可能会感到用起来比较繁琐。可是了解事务在保护数据库方面的良苦用心,就能够更好地设计出更灵活的业务流程。

若是“一个完整的事务可能包括a,b,c,d四个小事务”就比较奇怪。既然是个过程构成一个事务,不必中间在划分为4个小事务,问为中间任何操做出错都须要整个“回滚”到a以前。在执行完a后用一个if语句判断要不要再执行“b,c,d”就行,end if以后提交事务。

应用中包含的事务应当尽可能让它“瞬间”完成,避免在比较忙时形成用户进程的互锁。事务比较频繁的系统,一秒钟有几个用户互锁就可能形成严重问题,由于事务是以一个稳定的频率来的,而服务器上互锁的进程越积越多,几个小时后,可能有上百台机器都死掉了,只能一台一台地从新开机,花费不少时间、金钱,还会被用户骂死!

可是并非说事务之间就不能有用户交互。能够在用户3分钟还没确认后,就自动报告错误,而且取消事务。不过我从不冒这个险,而是使用下面方法。

将事务拆分红两段,须要很是深刻地研究用户业务流程,研究用户在发现业务数据不一致时是如何纠正的,而且继承用户手工操做流程。这样,软件分析的工做量相应加大了。有时,这是必然的,应当说服用户接受这种现象,而且与开发者一块儿逐步解决。

好比,卖彩票的交易,用户输入彩票号码,此时在POS机打印彩票而且记帐。这并不须要在卖彩票时与后台服务器实时联网,只要每隔10分钟上传一次数据就好了。只有这样,才能在现有的硬件和网络条件下使得彩票销售开展起来。若是开发者固守者彩票号码录入、服务器记帐、前台打印合并为一个事务的天真想法,其产品必定会在激烈的市场中败阵。

固然,随着硬件、软件、网络的不断变化,如何灵活应用事务的方法会不断变化,没有必定的规矩,关键要看软件的效果。虽然大的事务可能不断拆分红小的事务,中间用业务流程联系起来;同时,合并一些小的事务或者由计算机自动处理业务数据不一致问题,从而给用户提供网络上的“傻瓜相机”同样的易用、稳定的产品仍然是今天最有挑战意义的软件工程目标。 --------------------------------------------------------------------------------------

这个问题不是C#处理的,而是你调用的存储过程或批查询须要处理的,若是你用C#执行一系列的更新语句的话,你可使用ADO .NET SqlClient的事务来控制并发时的数据完整性!

SqlConnection conn=new SqlConnection(connectionstr);

SqlTransaction mytran=conn.BeginTransaction();

SqlCommand cmd=new SqlCommand();

cmd.Connection=conn;

cmd.Transaction=mytran;

cmd.CommandText=.....;

int rc=cmd.ExecuteNoQuery();

 

mytran.Commit();

....

你能够经过错误处理机制来控制事务提交仍是会滚...

 

-------------------------------------------------------------------------------------------- 我在程序中使用一种原始的方法处理须要锁定的内容。好比个人表中存储有订单的行项目,每次只容许一个用户对行项目进行编辑。创建“锁定表”,每当用户编辑订单时,在"锁定表"中加入订单号。当加入失败时则说明已有用户在编辑订单,当用户退出订单或锁定时间超过一个阈值时则删除锁定记录,容许其余用户编辑并锁定订单。这样处理适合锁定多行的订单类数据,锁定表中能够保存其余附加信息。还有一种方法在数据库中使用事务。使用事务更新数据库,这样能够保证同一时间只有一个用户能够对行更新。

相关文章
相关标签/搜索