.net的事务分为两种,一种是企业事务,一种是数据库事务。企业事务在System.Enterprise空间中,这个多用于与外部网络接口之间的等待,它是通过建立快照(很多东西其实是不能恢复的),另一种是数据库事务。楼主用的就是数据库事务,数据库事务严格来说并不属于.net,它其实是真正的数据库事务的一种包装形式。比如SqlTransaction trans = Conn.BeginTransction();这句在执行时相当于向数据库发送了Begin trans指令,这种情况下会指导在此时的时间段内,该条连接(相当于scope)不允许执行其他的语句。换句话来说,在trans执行commit或rollback之前,该条连接只为事务独占,不可能再执行其他的命令。
换种理解思路你会更明白——conn.BeginTransction() 之后,conn在执行其命令都算是事务的一部分,直到trans提交或回滚。
SqlTransaction trans = conn.BeginTransction()try
{
SqlCommand comm1 = Conn.CreateCommand(sqlString)
comm1.ExecuteNonQuery()
SqlCommand comm2 = new SqlCommand(sqlString2, conn)
comm2.ExecuteNonQuery()
// 提交事务
trans.Commit()
}catch
{
trans.Rollback()
}
以上语句中存在两个sqlcomm都在同一事务内执行。两个命令两种形式是等效的。
这里面有两个注意点,开始事务必须在打开的连接上,如果连接未打开的情况下是会引发错误的,也就是说conn.BeginTransction()语句执行的前替条件是conn处于open状态。所以如果能打开事务,不必要再进行conn.open()了!当然这不是楼主的错误,楼主的错误体现在另一个方面new SqlCommand(string sqltext, Connection conn, SqlTransction trans)方法的用途并不是这么用的。你代码中出现这个方法,其实new SqlCommand(string sqltext, Connection conn)如果conn在事务的标记下,该命令在执行已经做为事务的一部分了(conn标记事务后,没有提交或回滚时,该条连接上执行的所有命令都是事务命令,你可以查看代码上方的理论解释,这样有助于你的学习)。而且再使用一个trans参数传入,会被认为是另一个事务,换句话来说,这句语句在其中一个事务中执行(conn标记的事务上),同时被要求在另一个事务(传入的trans)上执行,造成了事务的并行,而这个在sql上是不被支持的,你也就是为什么你会得到一个错误“SqlCommand不支持并行事务"。
知道原因,那么修改起来也相当容易了。但这个看起来似乎对你很有用,其实呢,这相当于授人以”鱼“,这只是这个问题的解决方案,我肯定你以后不会再犯,即使如此,授人以”渔“岂不更好?
你打开了错误提示,在错误的配置节中使用了mode="on"的方式,所以你可以看到错误的,一般情况下,很多人看到这个都头大了,把这个错误直接发给”高手“,请求对方帮忙,那么这个错误为什么不自己去看下呢?所以一部分会看到这错误的提示,比如”sqlcommand不允许执行并行事务“,知道了错误的原因,很多初学的人还并不知道是什么情况下发生的错误,当然比如除0溢出一样,他只知道运行时某个分母的值是0,仅此而已。但对于排查来说也是相当困难,某个功能块中并不见得只有一个变量被做为除数的。怎么快速定位到代码呢?
堆栈跟踪起到了很大的作用:他不但有调用关系,还有错误发生的行数,它的格式就是方法(当然是方法的全名,空间名+类名+方法名)空格后跟+号和行数。这个其实是一个例外的冒泡顺序,最顶上一层是最终导致错误发生的位置(方法名称+行数),因为它的发生,所以会冒泡到调用它的方法,直接最后一个方法或try监控的方法体内。如果对类库不是很熟悉情况下,从上到下找到第一个自己写的方法,然后再查看对应的行数,就可以找到发生错误的源码位置了。可能不会理解,为什么有这么多类库中方法报错了呢?其实并不是类库错了,你调用的类库只不过是设置了他们执行方法的一些参数而已。所以是你传入的不合适的参数,并不见得是类库的错误。
比如代码下面的代码
public class Defined.Math{
public static int Method1(int num1, int num2)
{return num1/num2}
}
//调用方
Defined.Math.Method1(12,0)
显然调用方会发生错误,而例外的冒泡时的第一个方法是Method1的方法中的语句,而不是调用方的语句!
这就是怎么看冒泡的,虽然这种情况下,一般我们可以找到第一个我们写的方法,然后去修改它,但由于开发模式的原因,修改的未必是第一个冒泡的方法中语句。
方法教你了,再浅谈一下为什么会有这种情况,很多半瓶水的会认为修改Method1,如:
public static int Method1(int num1, int num2){
if(num2==0)
return 0
return num1/num2
}
这种代码看起来能很好的解决兼容问题,其实并非是解决问题之道。为什么呢?原因就是在于.net强大的例外机制!他们从来没有想到过会用这个强大的武器,只会用代码向上堆,有时问题并非那么简单的。如果是网络或者IO之类的错误呢?因为不会用.net的例外机制,所以他们可能没有写过这样的代码:
public void Method(int num){
if(num==0)
throw new Exception()
// other code doing something
}
之所以说.net有一个强大的例外机制作为武器,是因为我们可以创建类继承于Exception实现自定的例外!那些连throw都不会用的,自然从来不会接触到自定的exception的。所以对于同的情况分析时,我们完全可能会自己抛例外,这时怎么修改?你打算把抛出例外的语句改掉吗?
当然我是拿这个例子来说明怎么定位源码中错误的位置,冒泡的第一个位置只是错误发生的位置,并不是修改代码的位置,准确理解这个含义之后,你看堆栈时,可以直接定位到错误,而不是直接定位到你写的第一个抛出例外的方法!
一个大型、稳健、成熟的分布式系统的背后,往往会涉及众多的支撑系统,我们将这些支撑系统称为分布式系统的基础设施。除了前面所介绍的分布式协作及配置管理系统ZooKeeper,我们进行系统架构设计所依赖的基础设施,还包括分布式缓存系统、持久化存储、分布式消息系统、搜索引擎,以及CDN系统、负载均衡系统、运维自动化系统等,还有后面章节所要介绍的实时计算系统、离线计算系统、分布式文件系统、日志收集系统、监控系统、数据仓库等。分布式缓存主要用于在高并发环境下,减轻数据库的压力,提高系统的响应速度和并发吞吐。当大量的读、写请求涌向数据库时,磁盘的处理速度与内存显然不在一个量级,因此,在数据库之前加一层缓存,能够显著提高系统的响应速度,并降低数据库的压力。作为传统的关系型数据库,MySQL提供完整的ACID *** 作,支持丰富的数据类型、强大的关联查询、where语句等,能够非常客易地建立查询索引,执行复杂的内连接、外连接、求和、排序、分组等 *** 作,并且支持存储过程、函数等功能,产品成熟度高,功能强大。但是,对于需要应对高并发访问并且存储海量数据的场景来说,出于对性能的考虑,不得不放弃很多传统关系型数据库原本强大的功能,牺牲了系统的易用性,并且使得系统的设计和管理变得更为复杂。这也使得在过去几年中,流行着另一种新的存储解决方案——NoSQL,它与传统的关系型数据库最大的差别在于,它不使用SQL作为查询语言来查找数据,而采用key-value形式进行查找,提供了更高的查询效率及吞吐,并且能够更加方便地进行扩展,存储海量数据,在数千个节点上进行分区,自动进行数据的复制和备份。在分布式系统中,消息作为应用间通信的一种方式,得到了十分广泛的应用。消息可以被保存在队列中,直到被接收者取出,由于消息发送者不需要同步等待消息接收者的响应,消息的异步接收降低了系统集成的耦合度,提升了分布式系统协作的效率,使得系统能够更快地响应用户,提供更高的吞吐。
当系统处于峰值压力时,分布式消息队列还能够作为缓冲,削峰填谷,缓解集群的压力,避免整个系统被压垮。垂直化的搜索引擎在分布式系统中是一个非常重要的角色,它既能够满足用户对于全文检索、模糊匹配的需求,解决数据库like查询效率低下的问题,又能够解决分布式环境下,由于采用分库分表,或者使用NoSQL数据库,导致无法进行多表关联或者进行复杂查询的问题。
数据库事务采用JDBC即可,关闭Connection的自动提交功能,在resultset和statement的所有DML语句都完成后,提交,Connection.commit()在try。。catch语句块中,捕捉异常Exception,并回滚事务,Connection.rollback()即可;
以上步骤就是JDBC事务处理,当然其中有很多可选参数,看你的业务需求是怎样的
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)