分布式事务——【新生入学系统】

前言  

  了解分布式事务之前,先要明白事务到底是一个什么东西。事务(Transaction)就像搞对象,要么做男女朋友,要么就做陌生人,没有好朋友这么一说。

  官方解释:事务提供了一种机制将一个活动涉及的所有操作纳入到一个不可分割的执行单元,组成事务的所有操作只有在所有操作均能正常执行的情况下方能提交,只要其中任一操作执行失败,都将导致整个事务的回滚。简单说:事务提供了一种“要么不做,要么全做”的机制。瞬间感觉,事务有了东北大老爷们的气概~

事务特性

  原子性(Atomicity)、一致性(Consistence)、隔离性(Isolation)、持久性(Durability),这几个特性都是围绕事务原子性来展开的。原子性体现了事务的不可分割,整个事务内部与外界隔离开,从一个一致性的状态转换到另外一个一致性的状态,最后事务执行完成后,把内存中的数据存入到数据库中,就叫做持久化。

分布式事务

  个人理解是活动涉及多个服务器的事务称为分布式事务。当一个分布式事务结束时,事务的原子性要求所有的服务器要么提交该事务,要么全部终止。其中的一个服务器充当协调者,通过协议让所有的服务器保持相同的结果。

  举个小例子,权限可以控制学生通过邮箱来登录整个云平台。基础为权限提供学生信息,如果基础修改了学生的学号,那么相应的在权限系统、考试系统中就要进行学生学号的同步修改。

  事务不在局限于在一个系统内部执行,可以跨系统实现数据的同步。

实例

  我所知道的分布式事务一般存在于数据库里,或者VS代码里面。下面是简单的一个小demo,希望大家能够对WCF中的分布式事务更加的了解。

  代码背景:客户端A给服务端B转账,A减少多少金额,B增加相应的转账信息,金额。

客户端:

IAccount类:

<span style="font-family:KaiTi_GB2312;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace WCF_ATTransTest.Service
{
    //建立服务契约B转账WCF服务
    [ServiceContract]<span style="font-family: SimSun;">//特性</span>

    public interface IAccountB
    {
        [OperationContract]
        [TransactionFlow(TransactionFlowOption.Allowed)]//允许客户端使用事务;
        void deposit(int depositorid, double amount);//存款的方法
    }

}
</span>

  TransactionFlowOption.Allowed表示opreation可以参与事务流。到服务端的IAccountB中可以看到另外一个属性:TransactionFlowOption. Mandatory。这个属性是必须根据传入的事务进行分布式事务,如果客户端没有事务便抛出异常。

Program控制台:

<span style="font-family:KaiTi_GB2312;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;
using System.ServiceModel;
using System.ServiceModel.Channels;
using WCF_ATTransTest.Service;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

//建立A转账客户端
namespace WCF_ATTransTest.Client
{
    class Program
    {
        static void Main(string[] args)
        {

            /*
             客户端和服务端的通信是如何发生的呢?
             * 根据我们前面的学习,从实际操作上看,我们在服务端定义好协定和实现,
             * 配置好公开的终结点,打开元数据交换,在客户端添加服务引用,然后就
             * 直接new出来一个叫做XXXClient 的对象,这个对象拥有服务协定里的所有方法,直接调用就可以了。
             * 实际上客户端和服务端中间要建立一个通道,通过通道交流。
             * 客户端会在这两个终结点之间建立一个通道,然后把对服务端服务的
             * 调用封装成消息沿通道送出,服务器端获得消息后在服务器端建立服务对象
             * ,然后执行操作,将返回值再封装成消息发给客户端。
             */
            //System.ServiceModel提供了一个名为ChannelFactory<>的类,他接受服务协定接口作为泛型参数
            //,这样new出来的实例叫做服务协定XXX的通道工厂。

            //New一个通道工厂的实例 ,服务协定接口作为泛型参数。
            ChannelFactory<IAccountB> myFactory = new ChannelFactory<IAccountB>("endpointConfig");
            //产生一个通道,工厂是协定接口创建的,所以在这也实先了IAccountB接口
            IAccountB myClient = myFactory.CreateChannel();
            Double amount = 500;
            int depositorid = 1;
            using (TransactionScope scop = new TransactionScope())//使代码块成为事务性代码
            {
                #region 数据访问,在指定账户上减少存款
                string connstr = ConfigurationManager.ConnectionStrings["ConnStr"].ToString();
                //A客户端减少 金额调用B的WCF服务
                SqlCommand mySqlCommand = new SqlCommand("update account set amount = amount - @amount where depositorid = @depositorid ");
                mySqlCommand.Connection = new SqlConnection(connstr);

                SqlParameter par1 = new SqlParameter("@amount", SqlDbType.Decimal);
                par1.Value = amount;
                mySqlCommand.Parameters.Add(par1);

                par1 = new SqlParameter("@depositorid", SqlDbType.Int);
                par1.Value = depositorid;
                mySqlCommand.Parameters.Add(par1);

                mySqlCommand.Connection.Open();
                mySqlCommand.ExecuteNonQuery();
                mySqlCommand.Connection.Close();
                #endregion

                try
                {
                    myClient.deposit(depositorid, amount);//调用通道的协定方法
                    scop.Complete();
                }
                catch (Exception e)
                {
                    Transaction.Current.Rollback();//如果事务执行不成功,回滚到A没有减钱的状态<span style="font-family: SimSun;font-size:18px;"></span><pre name="code" class="csharp">
</span><span style="font-family: KaiTi_GB2312;">} } } }}</span>

服务端:

IAccountB类:

<span style="font-family:KaiTi_GB2312;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace WCF_ATTransTest.Service
{

    //建立系统B转账WCF服务
    [ServiceContract]
    public interface IAccountB
    {
        [OperationContract]

        [TransactionFlow(TransactionFlowOption.Mandatory)]<span style="font-family: Arial, Helvetica, sans-serif;"> //operation必须跟随传入的事务,参与分布式事务</span>
        void deposit(int depositorid, double amount);//转账:账户Id,转账金额
    }

}
</span>

AccountBService类:

<span style="font-family:KaiTi_GB2312;">using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
using Microsoft.KtmIntegration;
using System.IO;

//WCF转账的服务的实现。
namespace WCF_ATTransTest.Service
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class AccountBService : IAccountB
{
    [OperationBehavior(TransactionScopeRequired = true)]//客户端可以发起分布式事务了
    public void deposit(int depositorid, double amount)
    {
        Transaction ambientTransaction = Transaction.Current;

        #region 新建事务性文件

        string path = @"c:\test.txt";//实现的deposit操作中完成两个任务,先转账信息写入C:\text.text,用到了事务性文件TransactedFile.Open
        FileStream fs = TransactedFile.Open(path, System.IO.FileMode.Create,
            System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite);
        //FileStream fs = File.Open(path, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.ReadWrite);
        string fileContent = string.Format("从系统A转账到系统B\r\n用户ID:{0}\r\n转账金额为:{1}", depositorid.ToString(), amount.ToString());
        byte[] byteArrar = Encoding.UTF8.GetBytes(fileContent);
        fs.Write(byteArrar, 0, byteArrar.Count());
        fs.Flush();
        fs.Close();
        #endregion

        #region 数据访问,在指定账户上增加存款
        string connstr = ConfigurationManager.ConnectionStrings["ConnStr"].ToString();
        SqlCommand mySqlCommand = new SqlCommand("update account set amount = amount + @amount where depositorid = @depositorid ");
        mySqlCommand.Connection = new SqlConnection(connstr);

        SqlParameter par1 = new SqlParameter("@amount", SqlDbType.Decimal);
        par1.Value = amount;
        mySqlCommand.Parameters.Add(par1);

        par1 = new SqlParameter("@depositorid", SqlDbType.Int);
        par1.Value = depositorid;
        mySqlCommand.Parameters.Add(par1);

        mySqlCommand.Connection.Open();
        mySqlCommand.ExecuteNonQuery();
        mySqlCommand.Connection.Close();
        #endregion
     }
}
}
</span>

总结

  分布式不仅仅体现在事务中,它代表的是团队合作的精神,把一个大的问题打散成零碎的小问题分配给更多的计算机各个击破。后来也在网上搜了搜分布式和集群的区别:分布式是以缩短单个任务的执行时间来提升效率的,集群是通过提高单位时间内执行的任务数来提升效率的。分布式就像做一个复杂的算术题,把加减乘除分配给不同的人研究,每个人研究一块,总体就出来了。集群是一群人一起做题,固定数量的题就被均摊了。

  信息社会瞬息万变,云、大数据必将是下一波信息浪潮。

 

时间: 2024-08-29 04:06:41

分布式事务——【新生入学系统】的相关文章

你可以做的更好——【新生入学系统】

前言:系统无大小之分.做系统,没有最好,只有更好. 下面是我对我参与过的新生入学系统一点小小的建议,希望它能越来越完善,无论是从稳定性.安全性.兼容性.灵活性 还是用户体验度,都能接受的住测试的考验. 一.公共可完善的地方: 帮助:(New idea) 必要的时候,要有功能详情说明页. 需要使用的地方,一是报到流程,二是比较复杂的功能,比如分配学号,分配宿舍,分配班级的规则. 缓存:(New idea) 整个系统登录的时候需要用到缓存做临时保存,要有定时自动提交的功能,主要是应用于前台学生报到录

底层框架——【新生入学系统】

前言 开始学习的时候,搭建底层架构非常吃力.听着师哥师姐讲架构,感觉像听天书的似的,脑子里面一团浆糊,就看着师哥的F12按的特别欢,具体跳到哪里了,不知道. 不过硬着头皮做了一段时间的项目后,因为要如果不分析里面的调用关系,根本就不知道一条线怎么下来,所以一开始模仿,渐渐地开始有了自己的思路,感觉整个框架在脑海里面越来越清晰. 底层框架 .Net的框架十分的强大,跟之前的机房收费系统比,真的是从原始社会直接奔向了小康社会. 废话不多说的,赶紧进入正题,整个框架主要分成以下这几块,简单的介绍一下它

数组、集合、泛型解析——【新生入学系统】

一.概念(from 百科) 数组:把有限个类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字称为数组名,编号称为下标. 集合:集合是一组可变数量的数据项(可为0)的组合,这些数据项可能共享某些特征,需要以某种操作方式一起进行操作. 泛型:在程序编码中一些包含参数的类型,也就是说泛型的参数只可以代表类,不能代表个别对象. 二.进化史 开始用内存中的一个位置映射一个值,用"变量"来使用这个值.进一步发展成,用变量来引用一组值,数组诞生.后来有了集合,它是更强的的数组,依

新生入学项目之WCF入门

做新生入学系统这么长时间了,新加入的伙伴问我关于WCF的事情,自己说的也是云里雾里的,还是回过头来总结一下,要不然永远也不会知道自己到底懂得了多少. 一.概述 1.WCF -- 服务 WCF(Windows Communication Foundation)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口,它是.NET框架的一部分.由 .NET Framework 3.0 开始引入. WCF的最终目标是通过进程或不同的系统.通过本地网络或是通过Internet收发客

新生入学——3.0总结

之前写了一篇可以说是感受.收获的总结,现在还是要好好的总结一些3.0新生入学的成果和需要完善的地方. 如果你说我是新生入学元老级人物我真的没有意见,从1.0一直到3.0,也是醉了.只听说过谁是骨灰级程序员,哈哈!虽然3.0还没有结束,还是冒险从三个方面来总结一下3.0我们的新生入学系统. 一.时间 在此仅以几张甘特图代表我跌宕起伏的心情.有我们系统的每个人的. 团队两个人: 分析,大约半个月的时间只有小乖和小美在奋斗,两个人就很自由,但也很有效率,开始的阶段也就是搭框架,学习3.0改善的东西,然

企业级分布式事务

转至:http://www.liaoqiqi.com/post/231 基本概念 本地事务 事务由资源管理器(如DBMS)本地管理 优点:严格的ACID 缺点:不具备分布事务处理能力 全局事务(DTP模型) TX协议:应用或应用服务器与事务管理器的接口 XA协议:全局事务管理器与资源管理器的接口 优点:严格的ACID 缺点:效率非常低 两阶段提交 优点 准备后,仍可提交或回滚 准备时,一致性检查必须OK 准备后,事务结果仍然只在事务内可见 准备后,事务结果已经持久化 缺点: 潜在故障点多带来的脆

新生入学——3.0我们的成长

翻翻写的日报,不敢算ITOO3.0做了多长时间,因为自己总要找理由说是后来才加入的.可是新生入学呢,不说自己以前混日子的时间,自从自己有了自己的重任当上了组长之后,在这个月末也是快两个月了.面对新生入学系统,有点惭愧,因为从一开始并不是很喜欢它,总是在应付,但是当我要负责它的时候,我的喜好似乎不那么重要了,以至于到了现在对它的一种不舍竟像是自己的孩子一样看着他长到这么大. 之前,因为经历过1.0.2.0.在3.0的时候毅然决然的选择了离开它投奔了权限,可是真的不知道是为什么又回到它的身边,所以,

(转)如何用消息队列来代替分布式事务

转自:http://blog.csdn.net/ss123465/article/details/7964184 由于数据量的巨大,大部分Web应用都需要部署很多个数据库实例.这样,有些用户操作就可能需要去修改多个数据库实例中的数据.传统的解决方法是使用分布式事务保证数据的全局一致性,经典的方法是使用两阶段提交协议. 长期以来,分布式事务提供的优雅的全局ACID保证麻醉了应用开发者的心灵,很多人都不敢越雷池一步,想像没有分布式事务的世界会是怎样.如今就如MySQL和PostgreSQL这类面向低

新生入学V3.0颗粒归仓

新生入学系统V3.0接近尾声.每次做项目都有不一样的收获.V1.0,V2.0主要是熟悉了整个项目流程是怎样进行的,可行性分析--需求分析(原型图Axure)--实体设计(PD)--类图时序图(EA)--搭建框架--业务--公布--集成(Jekins)--測试(单元測试+代码走查+用例測试)--验收--总结.另外管理方面通过跟大家的交流和沟通,也锻炼不少,confluence.禅道.SVN等管理工具也小试了一把.只是開始的时候,由于不熟悉需求和业务,跑腿的活非常多,代码训练的比較少. V3.0的时