【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-

 

posted @   逆火狂飙  阅读(206)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
历史上的今天:
2014-09-10 【Canvas与旗帜】红白蓝黄星正方形旗帜(用于制作120*120图标)
生当作人杰 死亦为鬼雄 至今思项羽 不肯过江东
点击右上角即可分享
微信分享提示