zoukankan      html  css  js  c++  java
  • 【RabbitMq/Springboot】利用RabbitMq实现跨库转账的原理性实现

    本文涉及RabbitMq版本3.7.18,Springboot版本:2.5.4。

    之前我们探讨了单库转账,这回准备来实现一个跨库转账,实现声明这只是原理性实现,不是最终版本。

    实现的想法是在A机的本地账户扣款,然后把远程账户和加款金额发到队列里,B机接到消息后更新本地库的对应账户。

    A机为T440p,资金转出账户001,消息生产者和RabbitMq都在里面;B机为T14,转入账户002、消息消费者在里面。

    A机实现分以下几步:

    1.准备远程转账函数

    @Component
    public class AccountService {
        @Resource
        private AccountMapper amapper=null;
        
        @Autowired
        private RabbitMqMsgSender mqSender;
        
        @Transactional(rollbackFor=Exception.class) 
        public void remoteTransfer(int amount,String fromAccount,String remoteAcccount) throws TransferException{
            int count=amapper.add(-amount, fromAccount);
            if(count==0) {
                throw new TransferException("对转出账户:"+fromAccount+"操作,更新记录数为0.只有可能是该账户不存在。");
            }
            
            mqSender.send(remoteAcccount+"/"+amount);
        }
    }

    可以看到原来给转入加款的部分被替换成了往消息队列里发消息,消息格式为:远程账户/加款金额。

    2.在测试函数中执行

    @SpringBootTest
    class MyBankApplicationTests {
    
        @Autowired
        private AccountService aService;
        
        @Test
        void test() {
            try {
                aService.remoteTransfer(100, "001", "002");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    这个也可以点击页面按钮通过Ajax调用函数什么的,为了简便就直接在测试类里做了。

    3.看看数据库情况:

    看001账户被扣款一百,至少本地是对的。

    B机实现分以下几步:

     1.收到消息后对数据库进行处理

    import javax.annotation.Resource;
    
    import org.springframework.amqp.rabbit.annotation.RabbitHandler;
    import org.springframework.amqp.rabbit.annotation.RabbitListener;
    import org.springframework.stereotype.Component;
    
    import com.hy.mybank.mapper.AccountMapper;
    
    @Component
    @RabbitListener(queues="queue01")
    public class RabbitMqMsgReceiver {
        @Resource
        private AccountMapper amapper=null;
        
        @RabbitHandler
        public void QueueReceive(String receivedMsg) {
            System.out.println("收到消息:"+receivedMsg);
            
            String[] arr=receivedMsg.split("[//]");
            String toAccount=arr[0];
            int amount=Integer.parseInt(arr[1]);
            
            amapper.add(amount, toAccount);
        }
    }

    这边的处理也简单,直接劈分消息,第一个元素为转入账户,第二个元素为金额,进行数据操作即可。

    值得注意的是,QueueReceive函数一旦出现任何异常,队列里的消息是不会丢失的。我在劈分receivedMsg后写错序号,导致下标越界异常,但队列里面的消息还在,虽然它已经被取到劈分过了,这说明这个函数一有异常,消息是会被退回队列的。加上队列里消息存储机制,可以说安全性至少有两层。

    2.add函数

    @Mapper
    public interface AccountMapper {
    
        @Update("Update account set balance=balance+#{count} where customer_id=#{customer_id}")
        int add(int count,String customer_id);
    
    }

    这个函数就是操作数据库的SQL,没啥好说的。

    3.数据库情况

    可以看到002账户增加了100元,这个帐是平的了。

    以上即为跨库转账的原理性实现,这个实现当然是有漏洞的,比如转入账户不存在,转出账户的钱岂不是消失了,怎么保证远程转账的原子性,是接下来需要思考的问题。

    -END-

  • 相关阅读:
    典型案例道出“服务台”的价值
    银监会拟允许银行理财产品直接投资
    解读中国版存款保险制度:差别费率+强监管色彩
    央行牵头互联网金融“顶层设计”引业内关注
    央行降息 是农村互联网金融的救命稻草?
    历史上最伟大的 12 位程序员
    年关将至业内警示P2P跑路风险
    央行启动我国征信自律组织研究课题
    windows下开启redis拓展
    php使用curl新增微信临时素材(上传图片)
  • 原文地址:https://www.cnblogs.com/heyang78/p/15252805.html
Copyright © 2011-2022 走看看