使用栈处理回滚

Posted shuai7boy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用栈处理回滚相关的知识,希望对你有一定的参考价值。

简述:项目中回滚的方法很多种,目前我用到的一种是事务回滚。一种是是手动回滚。

事务回滚就是让代码包在一个事务里面,然后所有的代码成功执行后,最后有一个提交的操作。 

手动回滚,就是自己写代码处理回滚。

写博客背景:

我在公司负责的支付那块,开始用的事务回滚,将所有的支付逻辑都包在了一个大的事务里面,这样就会导致当有并发的时候,总是发生锁表问题。  然后采取的方案就是把大事务拆分成很多小事务,每个事务里面包含一个唯一的数据库操作逻辑。提交后外面代码写上对上步的回滚操作并放在栈里面,这样当有异常时,就会按照后进先出原则依次回滚。经过测试,成功解决了并发支付问题。 (PS:但是还有一个问题是,对于同一个数据,两个人同时支付会同时走支付代码,这块还没处理好业务并发,之前考虑加锁,但是这样系统就又变成了单线程执行,后面再考虑方案。)

用控制台简单写了一个Demo,计算了一个累加的操作,然后每一步都记录了回滚,每一步异常都会回滚到最初的数据10上面。 

 目录结构如下:

技术分享图片

Program.cs 

  private static Stack<IRollBack> _rollBack = new Stack<IRollBack>();
        private static int Sum = 10;
        static void Main(string[] args)
        {

            try
            {
              
                int Num1 = 3;
                int Num2 = 5;              
                //定义一个元数据是Sum=10,Num1=3,Num2=5
                //第一步: Sum=Sum+Num1   Sum=10+3=13  
                //第一步回滚: Sum=Sum-Num1  Sum=13-3=10
                Sum = Sum + Num1;
                IRollBack r1 = new Num1RollBack(Sum, Num1);
                _rollBack.Push(r1);
               
                //第二步: Sum=Sum+Num2  Sum=13+5=18
                //第二步回滚: Sum=Sum-Num2  Sum=18-5=13
                Sum = Sum + Num2;
                IRollBack r2 = new Num1RollBack(Sum, Num2);
                _rollBack.Push(r2);
                Console.WriteLine(Sum);

                //throw new Exception("测试回滚");
                Console.WriteLine("zj...");
                Console.ReadKey();

            }
            catch (Exception ex)
            {
                RollBack();             
            }

            Console.ReadKey();

        }

        public static void RollBack()
        {
            IRollBack rollBack = null;
            while (_rollBack.Count>0)
            {
                rollBack = _rollBack.Pop();
                Sum=rollBack.RollBack();
            }
            Console.WriteLine(Sum);
        }

IRollBack.cs

 public interface IRollBack
    {
        int RollBack();
    }

Num1RollBack.cs

    public class Num1RollBack : IRollBack
    {
        private int _sum, _num1;
        public Num1RollBack(int sum,int num1)
        {
            _sum = sum;
            _num1 = num1;
        }
        public int RollBack()
        {
            return _sum - _num1;
        }
    }

Num2RollBack.cs

    public class Num2RollBack : IRollBack
    {
        private int _sum, _num2;
        public Num2RollBack(int sum, int num2)
        {
            _sum = sum;
            _num2 = num2;
        }
        public int RollBack()
        {
            return _sum - _num2;
        }
    }

 一般情况下我们在web中都是操作的数据库,所以回滚接口定义成void即可,然后每个回滚实现接口处理回滚操作。

以上是关于使用栈处理回滚的主要内容,如果未能解决你的问题,请参考以下文章

java jdbc addBatch批处理不回滚

回栈事务后如何持久化分片数据?

jvm调优

如何在休眠中处理多个会话事务提交和回滚?

在 Node.js 中处理回滚的 MySQL 事务

在 Android 中使用片段时处理后按