编程中无法回避的基础知识---事务

编程中无法回避的基础知识---事务

        

         进行软件开发已经有一段时间了,有些东西虽然一直在用但是并不是很理解为什么去用它,它的机制又是什么,是不是还有其他的用途?就像我们在对数据库进行一系列操作时,我们为了保证数据的一致性往往会用到事务。本文将简单的介绍一下事务的相关知识,和简单用法。

 

         基本概念

 

         定义

         事务是将一系列 数据源更新分组或分批的方法,以便在回滚事务时同时提交所有事务或者不提交任何事务[MSDN]。

         事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begintransaction和end
transaction语句(或函数调用)来界定。事务由事务开始(begintransaction)和事务结束(end transaction)之间执行的全体操作组成。[百度百科]

         特性

         事务是恢复和并发控制的基本单位。具有4个属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

         类型

         按事务是否跨越多数据资源来分类:

         1)本地事务:事务操作一个数据资源,如数据库和消息队列。在物理上表现为位于同一台计算机。

         2)分布事务:事务跨越多个数据源,如操作两个服务器上的数据库。

         按事务处理方式划分:

         1)手动事务:使用显示指令来控制事务的开始和结束,这种方式可以处理嵌套事务。SQLServer,ADO.NET都提供手动事务处理。

         2)自动事务:通过有组件声明事务特性,把组件自动置于事务环境中。使用自动事务不能处理嵌套事务。自动事务的本质是依托于COM+。

 

         简单的实例

         实例一

namespace 简单的事务
{
    class Program
    {
        private static  Test test;
        static void Main(string[] args)
        {
            test=new Test();
            test.Add();

        }
    }

    public class Test
    {
        SqlConnection conn = new SqlConnection("datasource=.;Initial Catalog=Test;Integrated Security=SSPI;Persist SecurityInfo=False");
        public void Add()
        {
            conn.Open();
            SqlCommand command = new SqlCommand("insert intotest2 values(111)", conn);
            try
            {
                command.Transaction =conn.BeginTransaction();
                command.ExecuteNonQuery();
                command.CommandText = "insert intotest values(222)";
                command.ExecuteNonQuery();
                command.Transaction.Commit();
            }
            catch (Exception err)
            {
                Console.WriteLine(err);
                Console.ReadKey();
                command.Transaction.Rollback();
            }
        }
    }
}

 

         实例二

         这是一个简单三层的事务示例,

namespace 事务    //U层的代码
{
    class Program
    {

        static void Main(string[] args)
        {
            bll sbll = new bll();
            bool flag =sbll.MoveScore();
            if (flag == true)
            {
                Console.WriteLine("事务执行成功");
            }
            else
            {
                Console.WriteLine("事务执行失败");
            }
        }
    }
}

namespace AddTestBll   //BLL层
{
    public class bll
    {
         private dal dal;

         public Boolean MoveScore() {
             SqlConnection sqlCon = new SqlConnection("datasource=.;Initial Catalog=Test;Integrated Security=SSPI;Persist SecurityInfo=False");
        //打开连接
       sqlCon.Open() ;
            //定义事务
        SqlTransaction sqlTran =sqlCon.BeginTransaction(IsolationLevel.ReadCommitted);
            //用try...Catch...finally保证事务在出错时会回滚
            try
            {
                int intResult =dal.Add1(sqlTran);
                int intResult1 =dal.add2(sqlTran);

                if (1 == intResult&& 1 == intResult1)
                {
                    //如果都为真,提交
                    sqlTran.Commit();
                    return true;  //添加成功
                }
                else
                {
                    sqlTran.Rollback();
                    return false; //添加失败
                }

            }
            catch (Exception e)
            {
                //出现异常时,事物回滚
                sqlTran.Rollback();
                return false;
            }

            finally
            {
                sqlCon.Close();
            }

        }
    }
}

namespace AddTestDal      //Dal层
{
    public class dal
    {
        test enTest = new test();
        private SQLHelper sqlHelper;
        public int Add1(SqlTransaction sqlTran)
        {
            int intResult = 0;
            //enTest.Id ="222";
            string strSql = "insert intotest values(222)";
            intResult =sqlHelper.ExecuteNonQuery(strSql, CommandType.Text, sqlTran);

            return intResult;
        }

        public int add2(SqlTransaction sqlTran)
        {
            int intResult = 0;
            string strSql = "insert intotest values(111)";
            intResult =sqlHelper.ExecuteNonQuery(strSql, CommandType.Text, sqlTran);
            return intResult;
        }
    }
    public class SQLHelper
    {
        private SqlConnection conn = null;
        private SqlCommand cmd = null;
        private SqlDataReader sdr = null;

        public SQLHelper()
        {
            string connStr = "datasource=.;Initial Catalog=Test;Integrated Security=SSPI";
            conn = new SqlConnection(connStr);
        }

        private SqlConnection GetConn()
        {
            if (conn.State == ConnectionState.Closed)
            {
                conn.Open();
            }
            return conn;
        }
        ///<summary>
        ///执行带参数的增删改SQL语句或存储过程
        ///</summary>
        ///<paramname="cmdText">增删改SQL语句或存储过程</param>
        ///<paramname="paras">参数集合</param>
        ///<paramname="cType">命令类型</param>
        ///<returns>返回更新的记录条数</returns>
        public int ExecuteNonQuery(string cmdText, CommandType cType, SqlTransaction sqlTran)
        {
            try
            {
                //实例化数据库命令SqlCommand
                cmd = new SqlCommand(cmdText,GetConn());
                //命令类型:存储过程or SQL语句
                cmd.CommandType = cType;
                cmd.CommandTimeout = 180; //设置最大连接时间
                //事务
                cmd.Transaction = sqlTran;
                //定义事务执行结果
                int intResult =cmd.ExecuteNonQuery();
                //执行事务:大于0返回true,否则返回false。
                if (intResult > 0)
                {
                    //事务执行成功
                    return intResult;
                }
                else
                {
                    //事务执行失败
                    return intResult;
                }
            }
            catch (Exception ex)
            {
                //抛出异常
                throw ex;
            }
        }
    }
}

      

         上面是两个关于本地事务的小例子,最近项目中用到了分布式而底层还用到了EF,这样就要求运用到分布式事务了,研究中,如果读者有相关的资料希望能分享给大家,谢谢!

         文中代码自建了一个测试库里面两张表的表结构如下(记得设置主键)

        

 

         优秀的博客推荐:

         1、.NET简谈事务、分布式事务处理:http://wangqingpei557.blog.51cto.com/1009349/748799/

         2、简述.net中有哪几种事务:http://wangzhiyu110.blog.sohu.com/156427139.html

         3、.NET简谈事务本质论:http://wangqingpei557.blog.51cto.com/1009349/719056

时间: 2024-08-18 07:33:45

编程中无法回避的基础知识---事务的相关文章

编程中无法回避的基础知识---委托和事件

编程中无法回避的基础知识---委托和事件          在C#开发中,有时我们需要实现这样的情况:只要新添加一个对象,就要执行一系列的方法.如果每次挨个调用,这样既浪费时间,又造成代码冗余.这个时候我们就可以使用委托来建立一个方法链条,设置好后,可以让一个对象依次去执行这个链条上的各个方法.这样的结果就是:简化了代码,提高了效率,提高了代码的可维护性.        究竟什么是委托呢?事件有何委托有什么关系呢?          一.定义          委托是一个类,它定义了方法的类型,

在C语言编程中使用变量的基础教程_C 语言

C语言在明面上将数的变量分为两类,整型变量以及浮点数,对应着现实世界的整数和小数. 首先是整数,使用了这么多的C语言之后,每当在使用整数之时都会将其想象成二进制的存在,而不是十进制.原因在于,这是程序的本质所在,稍有研究编译器工作原理的都会发现,在编译器处理乘法乃至除法的时候,优秀的编译器总会想方设法的加快程序的速度,毫无疑问在所有运算中移位运算是最快速的"乘法"以及"除法": 1<<2 == 4 ,8>>2 == 2 而正常一个乘法相当于十

J2ME中需要的Java基础知识

现在有大部分人,都是从零开始学J2ME的,学习J2ME的时候,总是从Java基础开始学习,而且现在讲Java基础的书籍中都是以J2SE来讲基础,这就给学习造成了一些不必要的麻烦,下面将J2ME中用到的和不需要的Java基础知识做一个简单的说明:        J2ME中使用到的Java基础知识: 1.  Java语法基础:包括基本数据类型.关键字.运算符等等 2.  面向对象的思想:类和对象的概念,继承和多态等等. 3.  异常处理 4.  多线程 J2ME中没有用到的Java基础知识: 1. 

Java多线程编程中synchronized关键字的基础用法讲解_java

多线程编程中,最关键.最关心的问题应该就是同步问题,这是一个难点,也是核心. 从jdk最早的版本的synchronized.volatile,到jdk 1.5中提供的java.util.concurrent.locks包中的Lock接口(实现有ReadLock,WriteLock,ReentrantLock),多线程的实现也是一步步走向成熟化.   同步,它是通过什么机制来控制的呢?第一反应就是锁,这个在学习操作系统与数据库的时候,应该都已经接触到了.在Java的多线程程序中,当多个程序竞争同一

对JavaScript客户端应用编程的一些建议_基础知识

你可能注意到了,最近的一段时间越来越多的Web应用有变复杂的趋势,重心从服务端慢慢向着客户端转移. 这是个正常的趋势么?我不知道.支持和反对者的讨论就像是在讨论复活者和圣诞节哪一个更好一样; 很难说哪一方观点就是完全正确的.因此,本文不会探讨究竟哪一方是对的,不过我还是试图解释一下使用大家所熟知的面向对象编程也许可以成功的解决客户端编程中存在的一些问题. 不太规范的代码的示例 为了顾及一个应用的响应以及用户体验, 导致我们创建了持续增长的复杂的代码, 这些代码变得难于理解和维护. 你可以轻松的想

设计模式中的facade外观模式在JavaScript开发中的运用_基础知识

概念 外观模式(门面模式),是一种相对简单而又无处不在的模式.外观模式提供一个高层接口,这个接口使得客户端或子系统更加方便调用. 外观模式并不是适配器模式,适配器模式是一种包装器,用来对接口进行适配以便在不兼容系统中使用它.而创建外观元素则是图个方便.它并不用于达到需要特定接口的客户系统打交道这个目的,而是用于提供一个简化的接口. JavaScript代码示例 用一段再简单不过的代码来表示 var getName = function(){ return ''svenzeng" } var ge

Java线程编程中Thread类的基础学习教程_java

一.线程的状态 在正式学习Thread类中的具体方法之前,我们先来了解一下线程有哪些状态,这个将会有助于后面对Thread类中的方法的理解. 线程从创建到最终的消亡,要经历若干个状态.一般来说,线程包括以下这几个状态:创建(new).就绪(runnable).运行(running).阻塞(blocked).time waiting.waiting.消亡(dead). 当需要新起一个线程来执行某个子任务时,就创建了一个线程.但是线程创建之后,不会立即进入就绪状态,因为线程的运行需要一些条件(比如内

ASP.NET2.0中使用数据源控件之基础知识

asp.net|控件|数据|数据源     数据源控件是 Microsoft Visual Studio 2005 中引入的一种新型服务器控件,它们是数据绑定体系结构的一个关键部分,能够通过数据绑定控件来提供声明性编程模型和自动数据绑定行为.本文及此系列中的后续几篇文章将介绍实现数据源控件的核心内容. 引言 简而言之,数据源控件概括了一个数据存储和可以针对所包含的数据执行的一些操作.DataBound 控件通过其 DataSourceID 属性与一个数据源控件相关联.大多数传统的数据存储要么是表

深入学习JavaScript中的原型prototype_基础知识

javascript 是一种 prototype based programming 的语言, 而与我们通常的 class based programming 有很大 的区别,我列举重要的几点如下: 1.函数是first class object, 也就是说函数与对象具有相同的语言地位 2.没有类,只有对象 3.函数也是一种对象,所谓的函数对象 4.对象是按 引用 来传递的 那么这种 prototype based programming 的语言如何实现继承呢(OO的一大基本要素), 这也便是