• 【巨杉数据库】银行流水查询系统设计


    目录

            前言

            前端        

            后端 


    前言

            银行流水账单俗称银行卡存取款交易对账单,也称银行账户交易对账单。指的是客户在一段时间内与银行发生的存取款业务交易清单。一般而言,在申请贷款或者信用卡时,银行或其他金融机构会要求借款人提供申请者本人最近三个月或者以上的银行账单流水,以便银行在审核和授信时进行参考。

            银行流水账单查询系统为个人客户提供在线查询和打印服务。而本项目为整个系统提供数据库部分的支撑。

    需求如下

    查询编号

    查询需求

    发生频率

    要求返回时间

    最大并发数

    1

    按照交易流水号查询交易细节。

    <=100ms

    100

    2

    按照账号(不包括对方账户)查询交易流水,优先显示距离查询时间较近的交易。每页最多返回10条记录。

    <=500ms

    100

    3

    查询某月内交易总数

    1

    4

    查询某月内总交易额

    1

    架构图

     

    前端

     

            采用Vue3.0+Element-plus 开发,已部署至front_end。web服务器使用nginx,解决跨域问题

     

    查询一实现:

    1. const handleSearch=()=>{
    2. let param={
    3. txID:data.searchValue
    4. }
    5. console.log(param)
    6. FindByTxID(param).then(res=>{
    7. data.tableData=res.data.data
    8. ElMessage.success('查询耗时:'+res.data.cost)
    9. }).catch(e=>{
    10. console.log(e)
    11. })
    12. }

    查询2实现

            实现了异步分页功能

    1. const handleClick=(e)=>{
    2. console.log(e)
    3. data.curPage=Number(e.target.innerText)
    4. let param={
    5. accountID:data.searchValue,
    6. pageNum:data.curPage
    7. }
    8. FindHisory(param).then(res=>{
    9. data.tableData=res.data.data.data
    10. data.totalPage=res.data.data.count
    11. }).catch(e=>{
    12. console.log(e)
    13. })
    14. }
    15. const handleSearch=()=>{
    16. data.curPage=1
    17. let param={
    18. accountID:data.searchValue,
    19. pageNum:data.curPage
    20. }
    21. FindHisory(param).then(res=>{
    22. data.tableData=res.data.data.data
    23. data.totalPage=res.data.data.count
    24. ElMessage.success('查询耗时:'+res.data.cost)
    25. }).catch(e=>{
    26. console.log(e)
    27. })
    28. }

    查询3 查询4实现

            前端选择年-月后,将计算出该年-月的起始日期和终止日期传给后端

    1. export function getMonthScope(date) {
    2. const odd=['01','03','05','07','08','10','12']
    3. const even=['04','06','09','11']
    4. let mid=date.split('-')
    5. if (odd.indexOf(mid[1])!=-1) {
    6. mid[2] = "31";
    7. }
    8. else if (even.indexOf(mid[1])!=-1) {
    9. mid[2] = "30";
    10. }
    11. else if (mid[1]==='02'){
    12. let year=Number(mid[0])
    13. if ((year%4==0 && year%100!=0) || (year % 400==0)) mid[2]='29'
    14. else mid[2]='28'
    15. }
    16. return {
    17. ldate:date,
    18. rdate:mid[0] + "-" + mid[1] + "-" + mid[2]
    19. };
    20. }
    1. const handleDateChange=()=>{
    2. let param=getMonthScope(data.selectValue)
    3. if (data.searchType==0){
    4. FindTxCount(param).then(res=>{
    5. data.result=res.data.data
    6. ElMessage.success('查询耗时:'+res.data.cost)
    7. })
    8. }else if (data.searchType==1){
    9. FindTxAmount(param).then(res=>{
    10. data.result=res.data.data
    11. ElMessage.success('查询耗时:'+res.data.cost)
    12. })
    13. }
    14. }

     

     

     


    后端 

             后端使用flask框架,并自己简单实现了连接池,不需要每次查询都新建连接,减少了开销。

            对于查询1和查询2,在tx_id和account_id上建立索引

            对于查询3和查询四,在tx_time上建立倒序索引,因为查询2需要查询时间最近的项

    1. class ConnectionPool(object):
    2. def __init__(self, **kwargs):
    3. self.size = kwargs.get('size', 100)
    4. self.kwargs = kwargs
    5. self.host='localhost'
    6. self.port=11810
    7. self.conn_queue = queue.Queue(maxsize=self.size)
    8. for i in range(self.size):
    9. self.conn_queue.put(self._create_new_conn())
    10. def _create_new_conn(self):
    11. return client(self.host, self.port)
    12. def put_conn(self, conn):
    13. self.conn_queue.put(conn)
    14. def get_conn(self):
    15. conn = self.conn_queue.get()
    16. if conn is None:
    17. conn = self._create_new_conn()
    18. return conn
    19. pool = ConnectionPool()

       

    查询一和查询二的测试代码和测试结果

    1. import time
    2. import requests
    3. import random
    4. import sys
    5. from concurrent.futures import ThreadPoolExecutor
    6. import threading
    7. tPool=ThreadPoolExecutor(max_workers=100)
    8. BaseUrl="http://121.36.229.172:8899"
    9. def testFind1():
    10. response=requests.get(BaseUrl+'/findByTxID',params={
    11. 'txID':random.randint(10000,2009999)
    12. })
    13. response=response.json()
    14. return response
    15. def testFind2():
    16. response=requests.get(BaseUrl+'/findHistory',params={
    17. 'accountID':random.randint(622700000001,622700000030),
    18. 'pageNum':random.randint(1,4)
    19. })
    20. response=response.json()
    21. return response
    22. def callback(res):
    23. cost.append(res.result()['cost'])
    24. if len(cost)==iter:
    25. print(sum(cost)/len(cost))
    26. if __name__ == "__main__":
    27. iter=100
    28. if len(sys.argv) == 1:
    29. sys.exit(-1)
    30. elif sys.argv[1]=="test1":
    31. cost = []
    32. for i in range(iter):
    33. future = tPool.submit(testFind1)
    34. future.add_done_callback(callback)
    35. elif sys.argv[1]=="test2":
    36. cost = []
    37. for i in range(iter):
    38. future = tPool.submit(testFind2)
    39. future.add_done_callback(callback)
    40. else:
    41. print('error')

     

  • 相关阅读:
    leetcode分类刷题:栈(Stack)(一、字符串相邻元素删除类型)
    【UE5 Cesium】17-Cesium for Unreal 建立飞行跟踪器(2)
    shell之ipcrm命令
    物理层 (physical layer)
    LabVIEW 使用VISA Close真的关闭COM口了吗
    立体库堆垛机提升电机运行动作功能块
    【Axure视频教程】可拖动的知识图谱
    【opencv】传统图像识别:hog+svm行人识别实战
    vue3 学习笔记01 -- 搭建项目及基础配置
    笔试面试相关记录(11)
  • 原文地址:https://blog.csdn.net/masterwater/article/details/125456811