js333 > 计算机互联网 > 金沙js333娱乐场:的并行控制与数据存取冲突侦测

原标题:金沙js333娱乐场:的并行控制与数据存取冲突侦测

浏览次数:110 时间:2019-11-06

C#.NET Transaction 机制实例讲解,

.NET Transaction 机制

说到交易机制,简单来说就是例如我们在汇入订单时,可能会连动好几个SQL指令,但是如果哪天刚好中段资料有问题时,这样会导致insert一半,后续可能导致库存乱掉或是订单明细会有问题,因此我们就会运用到交易机制。

当整个交易机制都完成后,才会执行所有的sql 指令

public static MySqlConnection openMysqlConnection()
{

   MySqlConnection conn = new MySqlConnection("連線");
   conn.Open();
   return conn;
}

protected void Button1_Click(object sender, EventArgs e)
{
   using (MySqlConnection con = new MySqlConnection())
   {
    MySqlConnection conn = openMysqlConnection();
    MySqlTransaction tran = conn.BeginTransaction();

    //do something
   }
    tran.Commit();
}

Transaction 机制实例讲解, .NET Transaction 机制 说到交易机制,简单来说就是例如我们在汇入订单时,可能会连动好几个SQL指令,但是如...

   先说一下为什么要说到事务处理,实际上对于数据处理来说,对于数据库来说,整个程序开发发展到现在,任何程序任何项目都离不开数据处理,数据库,事务是一个非常重要的概念,不仅是ASP.NET当中甚至其他的编程语言编程环境当中,事务处理是一个非常重要的问题,也就是说事务处理本身是超脱于ASP.NET这个范围的;
   1-有人问了什么是事务处理?
   事务是一组组合成逻辑工作单元的数据库操作(所以看到这大家应该明白,事务是相对于数据库操作来的,事务本身是因为数据库的出现而出现的,为了对数据库操作过程中出现的问题而提出了事务的概念),虽然系统可能出错,但是事务将控制和维护每个数据库的一致性和完整性,也就是说事务处理的目的是为了维护数据库的一致性和完整性,并且事务是个单元,所谓的单元就是如果没有错误的话就修改成功,这样理解作为事务来说这些基本的操作要么全部成功,要么全部失败,我们知道这是在任何数据库当中都会遇到的这样一个问题;
   2-事务处理的过程是怎样的呢?
   事务处理流程是和数据库没有关系的,也就是说任何的数据库都是遵照这个流程来做的;1:开始一个事务,进入”事务待命“状态;2:在“事务待命”状态,记录事务中改变的数据库记录,注意不能直接改变数据库当中的值,必须先用一个顺序的”事务日志“记录在一边,(把它记下来,要改哪些,把它记在事务日志当中),同时对要改变的原始记录进行加锁,让其他用户无法读写(无法读写就是同一个时刻呢我们只允许一个用户对某个数据进行读写,这样的目的是为了提高保证数据的一致性),如果记录已被其他事务加锁,就报错;3:在“事务待命”状态如果用户给出Commit Transaction 命令,则进入事务拷贝状态,拷贝所有加锁的记录成备份(为什么备份,为了以后出错的时候还能返回);4:上面3执行完了,则进入”事务更新状态“,这是关键的更新状态(不是一上来就更新,首先药记录下来要对哪些值进行更新,然后把要更新的值复制一份作为备份,然后在进行更新),用“事务日志”中的记录一一更新实际的数据库记录;5:上面4执行完则进入“事务结束状态”,释放所有的记录锁,然后抛弃“事务日志”和备份的数据库记录;6:上面作完后删除事务,这是一个常见的事务处理的过程,这个是和数据库没有关系的;但是最为关键的是事务处理必须执行以下过程:一但数据库由于软件或者硬件问题发生故障,重启后,一但有事务没有正常删除,这是事务处理最最核心,最最关键的部分,如果出错怎么办,我们刚才假设总是没有出错,但是作为程序员来说,我们编程的时候是不都要想的全面一些呢,则:7:如果在“事务待命”和“事务结束”状态,则重新从5中结束事务的动作开始执行;8:如果在“事务更新”状态,则重新从4开始更新记录,并向下执行,结果虽然系统崩溃过,但事务仍然能正常提交;
   3-事务处理举例
   有人说你用教条解释了事务处理的流程,不是很明白,对了我本人也是非常讨厌教条式的概念和理论,没有实际生活中来的例子生动形象,好了,那我给大家举得例子,例子如下:
   银行取款的例子,比如:小王拿着一张卡去银行取钱了,他这次的目的是取100元,取款机里面有200元,取钱的流程是:A判断余额-B取钱-C扣除(200-100=100),如果取钱的过程中出错了怎么办,本来已经把100元取走了,还没有扣除,如果在这个时候取款机突然报错,机器死机了,取走100元结果取款机里面还有200元,还是显示200元,如果不作为一个事务来做的话,就会出现这样的情况,银行要赔钱了,所以要作为一个事务来处理,如果发现200元取走了100元取钱的动作已经完成了,当系统重新启动以后,继续执行扣除,最后把你取走的100元扣掉,虽然我们的系统崩溃了,但是系统重新启动以后,继续把没有做完的事务做完ABC则作为一个逻辑单元来存在;在假如甲乙两个人同时取钱的话,就要保证同时某一刻只能有一个人取钱(同时只有一个人做ABC三个动作,为了保证数据的一致性),如果说甲取了100元,但是还没来得及扣除情况下,银行里面显示还是200元,乙要再取的话还能取,实际上这种情况不能再取了,所以我们要保证数据的一致性,保证银行不赔钱,所以我们经常会遇到对数据库处理的时候是不要加锁,讲到这里就明白了,加锁的目的就是让同一时刻对某一个数据只有一个人进行操作,而且作为ABC这三个动作来说呢,把它作为一个事务来处理,要么全部成功,要么全部失败,既然钱取走了,就一定要扣掉,系统虽然崩溃了,重新启动后还要把这个事务作完;
   通过这个银行取钱的例子大家明白了吧;
   4-事务处理的有关事项
   事务处理的关键在于为了防止这样的情况,万一系统崩溃了,数据库再次启动后,仍然保持数据的一致性,逻辑性,也就是事务处理在这个时候发生的,如果说正正常常的,事务处理相对来说它就没有起到作用,就是预防万一出错的情况下,应用中包含的事务应当尽量让他瞬间完成的,也就是说一个事务很快的完成的,否则你说他取钱和扣除的过程,我们上个例子ABC三个动作应该马上立马完成的,如果说他取钱和扣除用上10分钟的话,你想想其他的人没法取钱了,避免在比较忙的时候造成用户进程的互锁,在这种情况下也是为了提高效率,所以作为一个事务来说应该是很快完成的,事务是要加锁的,也就是某一个时刻向下呢一个事务必须执行,其他不能同时访问了,特别是进行更新,我们知道计算机它崩溃的外因是不可预料的,特别是对于银行,用户的保密的数据作好数据的一致性是非常非常重要的,千万不能出任何的差错,所以事务处理是业务系统安全稳定的最后一道防线;
   5-那事务处理有哪些方法呢?
   1:直接写入SQL
   直接写SQL语句,SQL语句本身是可以有事务的,有事务处理的;在存储过程中使用Begin Tran,Commit Tran RollBack Tran。优点:独立于应用程序,拥有运行一个事务的最佳性能(在存储过程写事务处理是性能最好的)。限制:事务处理的上下文仅存在于数据库调用中(事务处理只能在SQL语句中体现,如果在SQL语句之外是无法访问的),数据库代码与数据库系统相关的(因为是SQL语句当中进行的事务处理,不同的数据库写的方法不一样);
   2:通过ADO.NET实现
   我们说在.NET当中呢,通过ADO.NET可以实现事务处理;在ADO.NET中使用Connection和Transacion对象来控制事务,若要执行事务请执行以下操作:调用Connrction对象的BeginTransaction方法标记一个事务的开始(BeginTransaction返回一个Transaction对象),将Transaction对象分配给要执行的Command的Transaction属性(将这个Tranaction对象赋值给Command对象的Transaction属性),调用Transaction对象的Commit方法来完成事务,或调用Rollback来取消事务;优点:简单性,和数据库事务差不多得快,独立于数据库。缺点:不能跨越多个数据库,事务执行在数据库连接层上,所以需要在事务中维护一个数据库连接。
   3:COM+事务(分布式事务)
   在某些特定的情况下,我们要用的;一般的数据库事务控制要求事务里所做的操作必须在同一个数据库内(必须对同一个数据库进行操作),这就存在一个问题,在分布式应用程序中,我们往往要同时操作多个数据库,SQLServer,Oracle,MySQL,你可能要操作两个数据库甚至多个数据库,你也希望这些操作要么同时成功,要么同时失败,也就是他们要做一个事务来处理,这种情况下就要用COM+的分布式事务处理了;

日前台湾高铁及其系统包商所开发的订票系统,曾出现大量重复订位之情形,产生了「车次、时段与路程」都一模一样的重复序号。类似此种订票系统,除了可使用 Web-based 架构外,若考虑到断线的处理作业,是否能在断线的情况下还能够交易,那么还可考虑 client-server 的架构,如此一来就要设计各个 client side 可以配给的车号、数量,以及恢复断线后再同步的机制,才能够实时处理,并尽可能避免重复划位的现象。

一些 ASP.NET + Oracle 11g 边学边写的随笔。本系列文章可帮助对 Oracle 不熟悉、甚至完全不会使用的 .NET 程序员,能在最短时间内上手并开发应用程序,避免像版工我一样花了大把时间翻书、查文件、撰码实作和测试、发问等回复。本帖内容包括:Oracle 的「空字符串 = NULL」特性、Oracle 的 Transaction Isolation Level、Oracle 的备份 & 还原。

   上面提到的事务处理的核心在于为了防止系统崩溃了,数据库再次启动后,仍然保持数据的一致性,逻辑性;
   不过其实事务还有一点在我们实际的应用中非常重要的一点,比如:有个进销存系统,当采购成功的时候,数据表Order
(订单表)里插入一条记录,同时OrderInfo(订单明细表)里插入多条这个订单的明细记录,如果成功都成功,如果失败都失败,不可能,有订单的记录,没有订单明细的记录吧,也不可能有订单明细的记录,没有订单的记录吧;
   不过个人认为在目前我们所做的项目中用到COM+事务的情况不多见,因为我们大部分都是操作同一个数据库;

若要避免产生重复划位,先剔除系统架构的分析、设计、OOAD 落实与否的问题不看,单就编程技术来探讨,较简单的做法是采用 ADO.NET 的「交易 (Transaction)」写法。让某位订票者在交易座位 1A 时,其它人都无法读取此 1A 座位,一直到他的交易结束为止,亦可搭配使用 dirty read 去强行读取;类似数据库的「独占锁定 (exclusive lock)」,让某人修改数据时,其它人连读取都不行 (亦会限制同时在线数量)。此种「独占锁定」类似 ADO.NET 的「封闭式 (悲观) 并行存取.aspx)」机制,虽然会长时间从数据被读取开始即将其锁定,但至少可保证交易一定有效。像这种资料 lock 的机制只要撰写 Transaction 程序,或是调整数据库的锁定策略、锁定提示就可做到。此外还可搭配使用数据库的 TimeStamp 计数器,判断「数据列 (row)」中的任何值是否有任何改变。另外 SQL Server 2005 还有更优越的「Snapshot Isolation 快照隔离模式」,其提供一种新的隔离层级,可将写入流程、读取流程作适当地隔离,使得读取动作不等待写入动作、写入动作不干扰读取动作,以提高数据的可用性、加快交易的执行速度。

(十) Oracle 小技巧

   鉴于有网友提出文章只是讲到纯理论,没有实例,所以特意补上实例以供参考,先说一下我们做事情先明白为什么要这么做,这么做的原因是什么,不这么做会导致什么后果,如果会导致后果那么这个后果发生的概率有多大。而现在很多书本上都是一步步指导你怎样做,怎样开发,却始终未曾提及为什么要这么做;
   好了,我就附上在ADO.NET中实现事务的代码如下:

至于 ASP.NET 2.0 / Visual Studio 2005 亦提供了入门级的解决方案,可由 SqlDataSource 等数据存取控件的图形设定接口中,勾选「进阶」按钮内的「使用开放式并行存取」选项,即可启动冲突侦测机制 (ConflictDetection 属性)。此举会将控件预设的「OverwriteChanges」改为「CompareAllValues」,并判断数据从刚才第一次读取到更新的这段期间内,是否曾被其它使用者变更过,此一选项亦即 ADO.NET 的「开放式 (乐观) 并行存取.aspx)」机制,只有当数据正在修改时才会进行锁定,并在修改完后再对各个「数据域 (column)」的新旧数据进行比对,看是否曾在这段期间内抢先被其它使用者修改了同一笔记录;但其它所有使用者仍可在此时去读取,类似于数据库的「共享锁定 (shared lock)」。若未勾选「使用开放式并行存取」此一选项时,即会采用预设的「后进先写入」机制,这种做法也是只在修改时才会锁定,但不会将更新后的数据与原始数据作比对,因此有可能发生欲修改的数据被其它使用者覆写掉之情形。

*金沙js333娱乐场 , 在 SQL Plus 中,用「desc」指令,可浏览数据表的 schema,如:desc table1;

   strConn是连接字符串,这里就不写明了;


* 不论是用 SQL Plus,还是 Oracle SQL Developer 工具,在执行完 INSERT、UPDATE、DELETE 语句后,都必须再执行一次「Commit;」指令,才会真正写入数据库,这点和他牌的数据库不同;但若是透过 ASP.NET 应用程序写入 Oracle,则不必加上此一动作。若某个人透过 SQL Plus 或 Oracle SQL Developer 写入 Oracle 之后,未再执行「Commit;」或「Rollback;」指令,会造成该笔记录被锁住,别人都无法「修改」该笔记录 (用户的应用程序或浏览器会一直处于等待状态),但仍可「读取」。

 1  /// <summary>
 2         /// 插入采购单利用事务
 3         /// </summary>
 4         /// <param name="order">采购单头</param>
 5         /// <param name="ls">采购单信息</param>
 6         /// <returns>返回插入的表头id</returns>
 7         public int InsertOrder(OrderData order, List<OrderInfoData> orderinfolist)
 8         {
 9             SqlConnection conn = new SqlConnection(strConn);
10             conn.Open();
11             SqlCommand cmd = new SqlCommand("insert into [order](Order_No, PurveyInfo_ID, User_ID, Order_Time, Down, Blank, YiTuiHui, ZaiTu, YiShouHuo) values(@order_no, @purveyinfo_id, @user_id, @order_time, 0, 0, 0, 0, 0)", conn);
12             SqlTransaction trans;
13             trans = conn.BeginTransaction();
14             cmd.Transaction = trans;
15             List<int> rlist = new List<int>();
16             try
17             {
18                 cmd.Parameters.AddWithValue("@order_no", order.Order_No);
19                 cmd.Parameters.AddWithValue("@purveyinfo_id", order.PurveyInfo_ID);
20                 cmd.Parameters.AddWithValue("@user_id", order.User_ID);
21                 cmd.Parameters.AddWithValue("@order_time", order.Order_Time);
22                 cmd.ExecuteNonQuery();
23                 cmd.CommandText = "select @@IDENTITY";
24                 int i = Convert.ToInt32(cmd.ExecuteScalar());
25                 foreach (OrderInfoData orderinfo in orderinfolist)
26                 {
27                     cmd.CommandText = "insert into orderInfo values(@order_id,@merchandiseinfo_id, @price, @quantity, 0)";
28                     cmd.Parameters.Clear();
29                     cmd.Parameters.AddWithValue("@order_id", i);
30                     cmd.Parameters.AddWithValue("@merchandiseinfo_id", orderinfo.MerchandiseInfo_ID);
31                     cmd.Parameters.AddWithValue("@price", orderinfo.Price);
32                     cmd.Parameters.AddWithValue("@quantity", orderinfo.Quantity);
33                     cmd.ExecuteNonQuery();
34                 }
35                 trans.Commit();
36                 return i;
37             }
38             catch (SqlException ex)
39             {
40                 trans.Rollback();
41                 throw ex;
42             }
43             finally
44             {
45                 conn.Close();
46             }
47         }

(本文在版工的旧 Blog 中,发表日期为 2007/01/07)
(本文有些 Hyperlink 是连到台湾的网站,内地的网友可能会无法开启连结)


 

 

       以上代码的意思是当采购成功的时候,数据表Order(订单表)里插入一条记录,同时OrderInfo(订单明细表)里插入多条这个订单的明细记录,如果成功都成功,如果失败都失败;不可能,有订单的记录,没有订单明细的记录,也不可能有订单明细的记录,没有订单的记录;
   本文来自CSDN博客,转载请标明出处:
  

(十一) Oracle 里没有「空字符串」这种东西

Oracle 里根本没有「空字符串 ('')」这种东西,而会将空字符串视为 Null,但在 SQL Server、其它厂牌的数据库和 ANSI SQL 92 的定义却并非如此。

当您将 Oracle 里一个表的 varchar2 字段,更新成空字符串时,如下:
UPDATE table1 SET col1='' [WHERE id=80];
在 Oracle 中会等同于:
UPDATE table1 SET col1=NULL [WHERE id=80];

此时,当您用如下的 SQL 语句去 SELECT 时,会查不出任何数据 (但用其它厂牌的数据库则查得到):
SELECT * FROM table1 WHERE col1='';

若改成如下,用 IS NULL 去当查询条件,才查得到数据 (但用其它厂牌的数据库则查不到):
SELECT * FROM table1 WHERE col1 IS NULL;

即使您改用 ADO.NET 的 OracleDataReader.IsDBNull 方法,写 .NET 应用程序去判断,结果也是一样。

此时,当您用 LENGTH 函数去判断 col1 字段的长度,会返回 Null,而不是 0,如下:
SELECT LENGTH(col1) FROM table1 WHERE id=80;

这些 Oracle 的「空字符串」特性,和其它厂牌的数据库,以及 ANSI SQL 92 的定义都不同。

参考文件:


 

(十二) Oracle 的「Transaction (事务;交易)」隔离层级

SQL Server 的 Isolation Level (事务隔离层级) 有七种,并可和 ADO.NET 做搭配;而 Oracle 的 Isolation Level 只有两种,分别为:ReadCommitted、Serializable,但 Oracle 的 ReadCommitted,和 SQL Server 的 ReadCommitted,名称虽然相同,但在功能和定义上皆不同。Oracle 的 ReadCommitted,类似于 SQL Server 2005 的「快照隔离 (Snapshot)」。

ReadCommitted 是 SQL Server 默认的 Isolation Level,其特性为当某一笔记录在「 修改 (Edit;Update)」时,别人都无法「读取」;ReadCommitted 也是 Oracle 默认的 Isolation Level,但其特性和 SQL Server 的版本完全不同,Oracle 的版本为,当某一笔记录在「修改」时,别人仍可以「读取」,但不能「修改」(该笔记录会被锁定,直到正在修改的那个人 Commit 或 Rollback)。

Oracle 的 ReadCommitted,其特性为,当一笔记录在被「修改」时,若有别人刚好也来「读取」这一笔记录,Oracle 会将这笔记录上一次被 Commit 的版本先取出来给其它人读取,避免造成「共享锁定」,亦即避免让其它人的浏览器或应用程序一直处于等待中,而无法进行其它的工作。

ADO.NET / Visual Studio 中用来联机 Oracle 的 Data Provider,不论是 OleDb、OracleClient、ODP.NET 皆是如此,和 SqlClient 的 Isolation Level 完全不同。

参考文件:






 

(十三) Oracle 的备份、还原方式

Oracle 的「备份、还原」,有下列四种方式:
* Cool Backup (Offline Backup)
* Hot Backup (Online Backup)
* RMAN
* Exp / Imp

到了 Oracle 10g 时,引入了新的 Data Pump 工具,且性能比旧的 Exp / Imp 要好,因其不必经由 Session 进行,但使用上较麻烦,必须先建立备份用的相关目录。其指令如下:
expdp userid=system/密码 tables=xxx,yyy directory=abc_dir => abc_dir: 此为 Oracle 目录,要先建立
impdp userid=system/密码 dumpfile=EXPDAT.DMP directory=abc_dir

而另一种最古老的 Emp / Imp 只能算是一种转存储工具,执行速度慢,只适合小型数据库。版工我测试结果,用 Export 指令备份 Oracle 11g 的整个 orcl 数据库,里面只有十八个新建的数据表 (每个表只有十多笔,到最多一两百笔记录),就花了半个多小时;Import 还原指令更慢,跑了一个多小时还没跑完,跑到隔天到公司上班才跑完。其指令如下,但它不是在 SQL Plus 里下指令,以 Windows 而言,是要在「命令提示字符 (cmd.exe)」里去下指令 (指令最后面不用加「分号」):
exp system/密码@orcl file=c:orcl_081207.dmp full=y
imp system/密码@orcl full=y ignore=y file=c:orcl_081207.dmp

如此即会汇出整个 orcl 数据库,包括:Index、Sequence、…等等。其中的参数,ignore=y 表示当汇入时,要覆盖同名的数据表;若没加此参数,则同名的表就不会汇入。

若要让 Exp / Imp 跑快一点,就不要下 full=y 的参数,改用 user mode (指定 owner=xxxx ) 的备份会比较快。此外,亦可只汇出或汇入某一个或某几个数据表,如下 (最后面不用加「分号」):
exp system/密码@orcl file=c:orcl_081207.dmp tables=(table1,table2)
imp system/密码@orcl file=c:orcl_081207.dmp tables=(table1)

若想看到指令的 help,可用如下的 help 参数:
exp -help
imp -help

此外,要执行 Emp / Imp 前,TNS (tnsnames.ora) 必须先正确设定。以 Windows Server 2003、Oracle 11g 而言,该档案位于下列目录:
C:appAdministratorproduct11.1.0db_1NETWORKADMIN

tnsnames.ora 我的设定如下:

ORCL_S =
 (DESCRIPTION =
  (ADDRESS_LIST =
   (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.0.1)(PORT = 1521))
  )
 (CONNECT_DATA =
  (SID = ORCL)
 )
)

亦可透过 Oracle 内建的图形界面工具「Net Manager」做设定。注意上述的 SID 一定要设定 (设成数据库的名称),但 Oracle 刚安装好时,SID 不一定会自动加上。设定好后,可用「tnsping 服务名称」指令,来测试是否有设定正确,以上述的 tnsnames.ora 而言,可在 Windows 操作系统的「命令提示字符」里,像这样下 tnsping 指令 (最后面不用加「分号」):
tnsping ORCL_S

参考文件:


 

(十四) Oracle 的存储过程,与 ASP.NET 的「分页」应用程序撰写

过去版工在用 SQL Server 和 Sybase 数据库,搭配 ASP.NET 2.0 程序撰写时,为了应付 GridView 控件的「分页」功能处理,都会写一种用来处理「分页」的 Stored Procedure,可参考本站的几篇系列文章 - ASP.NET 的数据分页:




SQL Server 和 Sybase 数据库的存储过程,都可直接 return 一个 ResultSet 格式的数据 (亦即有多行多列的表格式数据,如同 ADO.NET 中的 DataTable),给呼叫 (调用) 它的应用程序,如下所示,但 Oracle 却不能直接这样 return:

CREATE PROCEDURE dbo.pager_SqlServer2005
AS
 SET @sqlDataTable = 'SELECT * FROM table1'
 exec (@sqlDataTable)
RETURN

Oracle 有它另一套做法,只能透过 REF CURSOR 类型,去处理和返回「结果集」,但听说这样的性能并不好。不知为何 Oracle 干麻要这样自己搞另一套 (包括先前提到的「空字符串」和 Null),非得和其它厂牌的数据库与众不同才高兴,也搞得所有程序员得另外学习一套标准。有关 Oracle 的 Stored Procedure 和 REF CURSOR,可参考下列文件:



(同上,但此为繁体中文版本)




至于 ASP.NET 的 GridView「分页」功能,版工我是放弃 Oracle 的存储过程,改自己写一个 .NET 的函数,去接收 ObjectDataSource 控件传来的参数 (要撷取第几笔到第几笔的记录),将原本可在存储过程中处理的工作,搬到 .NET App_Code 文件夹里的 DAL Layer 来处理。


 

本文由js333发布于计算机互联网,转载请注明出处:金沙js333娱乐场:的并行控制与数据存取冲突侦测

关键词:

上一篇:没有了

下一篇:没有了