采用GaussDB(for MySQL)完成商场会员卡管理系统设计

1701843325859

这篇文章介绍了如何购买、配置、连接、测试 GaussDB数据库,并且最终采用Qt开发了一个具体的软件演示了数据库的具体应用,演示了数据库整体的使用过程。

一、什么是GaussDB?

GaussDB是华为自主创新研发的分布式关系型数据库。该产品支持分布式事务,同城跨AZ部署,数据0丢失,支持1000+的扩展能力,PB级海量存储。同时拥有云上高可用,高可靠,高安全,弹性伸缩,一键部署,快速备份恢复,监控告警等关键能力,能为企业提供功能全面,稳定可靠,扩展性强,性能优越的企业级数据库服务。

GaussDB分布式形态整体架构如下:

  • Coordinator Node:协调节点CN,负责接收来自应用的访问请求,并向客户端返回执行结果;负责分解任务,并调度任务分片在各DN上并行执行。
  • GTM:全局事务管理器(Global Transaction Manager),负责生成和维护全局事务ID、事务快照、时间戳、sequence信息等全局唯一的信息。
  • Data Node:数据节点DN,负责存储业务数据(支持行存、列存、混合存储)、执行数据查询任务以及向CN返回执行结果。

GaussDB 主备版形态整体架构如下:

  • ETCD:分布式键值存储系统(Editable Text Configuration Daemon)。用于共享配置和服务发现(服务注册和查找)。
  • CMS:集群管理模块(Cluster Manager)。管理和监控分布式系统中各个功能单元和物理资源的运行情况,确保整个系统的稳定运行。
  • Data Node:数据节点DN,负责存储业务数据(支持行存、列存、混合存储)、执行数据查询任务以及返回执行结果。

应用场景

  • 交易型应用

    大并发、大数据量、以联机事务处理为主的交易型应用,如政务、金融、电商、O2O、电信CRM/计费等,服务能力支持高扩展、弹性扩缩,应用可按需选择不同的部署规模。

  • 详单查询

    具备PB级数据负载能力,通过内存分析技术满足海量数据边入库边查询要求,适用于安全、电信、金融、物联网等行业的详单查询业务。

二、创建GaussDB-MySQL数据库

链接:https://www.huaweicloud.com/product/gaussdbformysql.html

【1】选择云数据库

image-20231204145134408

【2】配置实例

image-20231204150109621

【3】提交实例

image-20231206111501235

【4】完成购买

image-20231206111704231

【5】查看数据库详情

目前数据库正在创建中,等待一段时间,在页面可以看到创建成功的提示。

image-20231206111752320

【6】登录数据库

数据库完全创建完毕之后,点击登录测试数据库。

image-20231206113150796

image-20231206112743836

输入数据库账号、密码。

image-20231206112806860

先点击测试连接,测试通过后,点击登录。

image-20231206112823720

【7】新建数据库

点击新建数据库。

image-20231206112857593

输入数据库名称。

image-20231206113019575

提示创建成功。

image-20231206113038654

【8】绑定公网IP

为了方便数据库在公网下能够访问,需要购买公网IP,然后绑定。

(1)点击数据库的实例名称

image-20231206113408108

(2)在数据库的详情页面(点击数据库名字进入)。 就可以看到绑定公网IP的地方。

image-20231206113325045

(3)如果没有就买一个

image-20231206113630483

我选择购买1个月,一M带宽。

image-20231206113709236

image-20231206113742648

image-20231206113844050

(4)继续回到绑定公网IP的页面

image-20231206114017790

image-20231206114037846

绑定成功。

image-20231206114059822

(5)接下来还要配置内网安全组,不然公网IP无法访问。 这一步很重要!

image-20231206134020917

image-20231206134129448

添加成功。

image-20231206134148034

(6)如果不需要SSL协议,也可以自己关闭

image-20231206135923910

【9】实例连接方式

GaussDB(for MySQL)提供使用内网、公网和数据管理服务(Data Admin Service,简称DAS)连接实例的方式。

连接方式连接地址使用场景说明
DAS连接无需使用IP地址华为云数据管理服务(Data Admin Service,简称DAS)是一款专业的简化数据库管理工具,提供优质的可视化操作界面,大幅提高工作效率,让数据管理变得既安全又简单。你可以通过数据管理服务连接并管理GaussDB(for MySQL)实例。GaussDB(for MySQL)默认为你开通了远程主机登录权限,推荐你使用更安全便捷的数据管理服务连接实例。易用、安全、高级、智能。推荐使用DAS连接。
内网连接读写内网地址系统默认提供内网IP地址。当应用部署在弹性云服务器上,且该弹性云服务器与GaussDB(for MySQL)实例处于同一区域,同一VPC时,建议单独使用内网IP连接弹性云服务器与GaussDB(for MySQL)数据库实例。安全性高,可实现GaussDB(for MySQL)的较好性能。推荐使用内网连接。
公网连接弹性公网IP不能通过内网IP地址访问GaussDB(for MySQL)实例时,使用公网访问,建议单独绑定弹性公网IP连接弹性云服务器(或公网主机)与GaussDB(for MySQL)数据库实例。降低安全性。为了获得更快的传输速率和更高的安全性,建议你将应用迁移到与你的GaussDB(for MySQL)实例在同一VPC内 ,使用内网连接。

【10】公网连接实例流程

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【11】约束与限制

GaussDB(for MySQL)使用和命名上有一些固定限制,用来提高实例的稳定性和安全性。

功能使用限制
GaussDB(for MySQL)访问如果GaussDB(for MySQL)数据库实例没开通公网访问,则该实例必须与弹性云服务器在同一个虚拟私有云内才能访问。弹性云服务器必须处于目标GaussDB(for MySQL)数据库实例所属安全组允许访问的范围内。如果GaussDB(for MySQL)数据库实例与弹性云服务器处于不同的安全组,系统默认不能访问。需要在GaussDB(for MySQL)数据库的安全组添加一条“入”的访问规则。“入”规则开放TCP协议,使用数据库实例的默认端口。GaussDB(for MySQL)数据库实例的默认端口:主备版默认端口为3306,需用户手动修改端口号后,ECS或外网才能访问其他端口。
数据库的root权限创建实例页面只提供管理员root用户权限(仅限主备版)。
修改数据库参数设置大部分数据库参数可以通过控制台进行修改。
数据迁移使用DRS或mysqldump迁移到GaussDB(for MySQL)数据。
MySQL存储引擎GaussDB(for MySQL)只支持InnoDB存储引擎。
重启GaussDB(for MySQL)实例无法通过命令行重启,必须通过GaussDB(for MySQL)的管理控制台重启实例。
查看GaussDB(for MySQL)备份GaussDB(for MySQL)数据库实例在对象存储服务上的备份文件,对用户不可见。
开启binlogGaussDB(for MySQL) 不支持只读节点开启binlog。
分区表GaussDB(for MySQL)现有产品能力和社区8.0.22版本是兼容的,对于分区表,如果是list分区,目前每个分区的values最多只支持256个,超出会报错。(规避措施:将values个数过多的分区拆成更小的分区,确保每个分区的values个数都不超过256个。)

命名约束:

参数约束
实例名称长度在4个到64个字符之间,必须以字母开头,可以包含字母、数字、中划线或下划线,不能包含其他特殊字符。
数据库名称长度可在1~64个字符之间,由字母、数字、下划线、中划线组成,中划线累计总长度小于等于10个字符,且不能包含其他特殊字符。以下名称不能作为数据库名。extra_healthib_buffer_poolibtmp1logfilesalsql_extra_health
账号(非管理员)长度在1到32个字符之间,由字母、数字、下划线组成,不能包含其他特殊字符
密码长度为832个字符,至少包含大写字母、小写字母、数字、特殊字符三种字符的组合,其中允许输入!@#$%^*-_=+?,()&特殊字符。
参数模板名称长度在1~64个字符之间,区分大小写,可包含字母、数字、中划线、下划线或句点,不能包含其他特殊字符。
备份名称长度在4~64个字符之间,必须以字母开头,区分大小写,可以包含字母、数字、中划线或者下划线,不能包含其他特殊字符。

【12】GaussDB(for MySQL)与其他服务的关系

GaussDB(for MySQL)与其他服务之间的关系。

相关服务交互功能
弹性云服务器(ECS)GaussDB(for MySQL)配合弹性云服务器(Elastic Cloud Server,简称ECS)一起使用,通过内网连接GaussDB(for MySQL)可以有效的降低应用响应时间、节省公网流量费用。
虚拟私有云(VPC)对你的GaussDB(for MySQL)数据库实例进行网络隔离和访问控制。
对象存储服务(OBS)存储你的GaussDB(for MySQL)数据库实例的自动和手动备份数据。
云监控服务(Cloud Eye)云监控服务是一个开放性的监控平台,帮助用户实时监测GaussDB(for MySQL)资源的动态。云监控服务提供多种告警方式以保证及时预警,为你的服务正常运行保驾护航。
云审计服务(CTS)云审计服务(Cloud Trace Service,简称CTS),为用户提供云服务资源的操作记录,供你查询、审计和回溯使用。
数据复制服务(DRS)使用数据复制服务,实现数据库平滑迁移上云。
企业管理服务(EPS)企业管理服务(Enterprise Project Management Service,简称EPS)提供统一的云资源按企业项目管理,以及企业项目内的资源管理、成员管理。
标签管理服务(TMS)标签管理服务(Tag Management Service,简称TMS)是一种快速便捷将标签集中管理的可视化服务,提供跨区域、跨服务的集中标签管理和资源分类功能。
分布式数据库中间件(DDM)对于云数据库 GaussDB(for MySQL),使用分布式数据库中间件服务(Distributed Database Middleware,简称DDM),后端对接多个数据库实例,实现分布式数据库的透明访问。

【13】GaussDB(for MySQL)与RDS for MySQL的区别

GaussDB(for MySQL)拥有较好的性能、扩展性和易用性。

类别RDS for MySQLGaussDB(for MySQL)
架构传统主备架构,主备通过binlog同步数据。存算分离架构,计算节点共享一份数据,无需通过binlog同步数据。
性能十万级QPS,高并发场景下性能提升3倍。百万级QPS,性能是开源MySQL的7倍;复杂查询场景,支持将提取列、条件过滤、聚合运算等操作向下推给存储层处理,性能相比传统架构提升数十倍。
扩展性最多添加5个只读节点,添加只读所需时间与数据量大小相关,并且需要增加一份存储。存储自动扩容,最大支持4TB。最多添加15只读,由于共享存储,添加只读节点所需时间与数据量大小无关,且无需增加一份存储。存储自动扩容,最大支持128TB。
可用性故障自动倒换,RTO通常小于30秒。主节点和只读节点无需通过binlog进行数据同步,延时更低,故障自动切换,RTO通常小于10秒。
备份恢复通过全量备份+binlog回放实现任意时间点回滚。通过全量备份(快照)+redo回放实现任意时间点回滚,备份恢复速度更快。
数据库版本MySQL 5.6、5.7和8.0。

三、Navicat远程登录数据库

绑定公网IP之后,接下来使用Navicat Premium 16 远程登录数据库,测试数据库的连接情况。

3.1 新建连接

image-20231206114640599

3.2 输入数据库连接参数

主机就填绑定的公网IP。 端口号3306

用户名填root(也可以填自己新建的用户)

密码就是创建数据库的时候设置的密码。

image-20231206114737483

3.3 测试连接

参数填好之后,点击左下角的按钮,测试连接。

正常情况相爱,就看到弹窗,测试连接成功。

如果说连接不了服务器。一定要检查自己的安全组输入规则是否开放了其他IP地址和3306端口的访问.

image-20231206134552082

3.4 登录数据库

测量连接成功之后,回到菜单页面,点击数据库名称就可以连接上数据库。

进入之后,就可以看到我们刚才在华为云网页端创建的数据库名称。 到此,我们的数据库的创建、公网连接已经完成了。接下来就可以正常的使用数据库进行完成我们的应用开发了。

image-20231206134737879

四、门店会员卡管理系统开发

4.1 项目说明

下面采用Qt框架,远程访问刚才创建的华为云的GaussDB-MySQL数据库,开发一款门店会员卡管理系统,完成 注册、充值、消费、查询、销户等基本功能。所有的用户数据都放在华为云的GaussDB-MySQL数据库里。

4.2 新建工程

image-20231123204107281

image-20231123105425946

image-20231123105456525

image-20231123105508309

4.3 修改pro工程文件

增加数据库的支持。

QT       += sql

image-20231123204149759

4.4 设计UI界面

image-20231123204213476

这是设计好的界面:

image-20231123114053797

4.5 需要添加的代码

#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>

4.6 会员卡建表代码

//创建VIP卡余额管理表
void Widget::CreateTAB_VIP_Card()
{
    //数据库:建表,如果存在就不创建,不存在就创建
    QSqlQuery sql_query(database);

    QString tableName = "vip"; // 要查询的表名,可以根据实际情况修改

    //下面语句查询指定的表是否存在.
    sql_query.exec(QString("SELECT COUNT(*) FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema = '%1' AND table_name = '%2'")
               .arg(database.databaseName(), tableName));

    if(sql_query.next())
    {
        if(sql_query.value(0).toInt()==0)
        {
            qDebug("数据库表是不存在的.准备创建.\n");
            //创建表格 创建表格语句:create table <table_name> (f1 type1, f2 type2,…);
            /* CREATE TABLE 是告诉数据库系统创建一个新表的关键字。
                * CREATE TABLE 语句后跟着表的唯一的名称
                * 或标识*/

            /*下面的语句: 创建一个名称为password的表,字段分别是存放 卡号 姓名 电话 余额*/

            QString tableName = "vip";
            QString createSql = "CREATE TABLE " + tableName + "(id INT PRIMARY KEY, card VARCHAR(100), name VARCHAR(100), phone VARCHAR(100), money INT)";


            sql_query.prepare(createSql);
            if(!sql_query.exec())
            {
                Log_Text_Display("VIP卡余额管理表创建失败.\n");
            }
            else
            {
                Log_Text_Display("VIP卡余额管理表创建成功.\n");
            }
        }
        else
        {
            Log_Text_Display("VIP卡余额管理表是存在的.不需要创建.\n");
        }
    }
}

4.7 注册新的会员卡

//注册新的VIP客户
bool Widget::add_VIP_Card(QString card,QString name,QString phone)
{
    if(name.isEmpty())return false;
    if(phone.isEmpty())return false;

    //指定操作的数据库
    QSqlQuery sql_query(database);

    //查询原数据库表里有没有重复数据
    //查询全部数据
    sql_query.prepare("select * from vip");
    if(!sql_query.exec())
    {
        Log_Text_Display("VIP卡余额管理表查询错误.\n");
    }
    else
    {
        while(sql_query.next())
        {
            //ID、账号、密码、类型
            // int id = sql_query.value(0).toInt(); //ID
            QString find_card = sql_query.value(1).toString(); //卡号
            QString find_name = sql_query.value(2).toString(); //姓名
            QString find_phone = sql_query.value(3).toString(); //电话
            int money = sql_query.value(4).toInt(); //余额

            //判断卡号有没有冲突的
            if(find_card==card)
            {
                QMessageBox::information(this,"提示","你使用的卡已经注册!\n请注销后重试.",
                QMessageBox::Ok,QMessageBox::Ok);
                return false;
            }
        }
    }

    //查询最大ID
    QString select_max_sql = "select max(id) from vip";
    int max_id = 0;
    sql_query.prepare(select_max_sql);
    if(!sql_query.exec())
    {
        Log_Text_Display("VIP卡余额管理表最大ID查找失败.\n");
    }
    else
    {
        while(sql_query.next())
        {
            max_id = sql_query.value(0).toInt();
        }

        Log_Text_Display(QString("data base max id:%1\n").arg(max_id));

        //添加数据
        //插入数据 插入语句:insert into <table_name> values (value1, value2,…);
        QString insert_sql = tr("insert into vip values(?,?,?,?,?)");
        sql_query.prepare(insert_sql);
        //if(max_id!=0)max_id+=1; //判断是否是第一次数据
        sql_query.addBindValue(max_id+1); //id
        sql_query.addBindValue(card);    //卡号
        sql_query.addBindValue(name);    //姓名
        sql_query.addBindValue(phone);    //电话
        sql_query.addBindValue(0);    //余额
        if(!sql_query.exec())
        {
            Log_Text_Display("数据插入失败.\n");
        }
        else
        {
            return true;
        }
    }
    return false;
}

4.8 会员卡充值

//单卡充值
void Widget::on_pushButton_Recharge_clicked()
{
    QString card=ui->lineEdit_reg_vip_number->text();
    if(card.isEmpty())
    {
        QMessageBox::warning(this,"提示","请输入正确的卡号",QMessageBox::Ok);
        return;
    }

    //数据库查询
    //指定操作的数据库
    QSqlQuery sql_query(database);

    //查询数据库对应的ID
    int id=0;
    int flag=0;
    QString find_card;
    QString find_name;
    QString find_phone;
    int find_money=0;

    //查询全部数据
    sql_query.prepare("select * from vip");
    if(!sql_query.exec())
    {
        Log_Text_Display("数据库查询错误.\n");
    }
    else
    {
        while(sql_query.next())
        {
            id=sql_query.value(0).toInt(); //id
            find_card = sql_query.value(1).toString(); //卡号
            find_name = sql_query.value(2).toString(); //姓名
            find_phone = sql_query.value(3).toString(); //电话
            find_money = sql_query.value(4).toInt(); //余额

            if(find_card==card)
            {
                flag=1; //查找成功
                break;
            }
        }
    }

    if(flag==0)
    {
        QMessageBox::warning(this,"提示",QString("%1 此卡未注册.").arg(card),QMessageBox::Ok);
        return;
    }


    //进行充值  UPDATE COMPANY SET ADDRESS = 'Texas' WHERE ID = 6;

    int val=ui->lineEdit_input->text().toInt();
    if(val<=0)
    {
        QMessageBox::warning(this,"提示","请输入充值金额",QMessageBox::Ok);
        return;
    }

    find_money=find_money+val;
    //进行充值  字符串类型要用''包起来
    QString cmd=QString("UPDATE vip SET money=%1 WHERE ID=%2").arg(find_money).arg(id);
    sql_query.prepare(cmd);
    if(!sql_query.exec())
    {
        Log_Text_Display("数据库修改错误.\n");
    }

    qDebug()<<cmd;


    QString info=QString("卡号:%1\n姓名:%2\n电话:%3\n余额:%4\n")
            .arg(card)
            .arg(find_name)
            .arg(find_phone)
            .arg(QString("%1").arg(find_money));
    QMessageBox::information(this,"充值成功",info,QMessageBox::Ok);

    on_pushButton_cha_xun_all_clicked();
}

4.9 会员卡余额查询

//查询单卡卡余额
void Widget::on_pushButton_query_clicked()
{
    QString card=ui->lineEdit_reg_vip_number->text();
    if(card.isEmpty())
    {
        QMessageBox::warning(this,"提示","请输入正确的卡号",QMessageBox::Ok);
        return;
    }

    //数据库查询
    //指定操作的数据库
    QSqlQuery sql_query(database);

    //查询数据库对应的ID
    int id=0;
    int flag=0;
    QString find_card;
    QString find_name;
    QString find_phone;
    int find_money=0;

    //查询全部数据
    sql_query.prepare("select * from vip");
    if(!sql_query.exec())
    {
        Log_Text_Display("数据库查询错误.\n");
    }
    else
    {
        while(sql_query.next())
        {
            id=sql_query.value(0).toInt(); //id
            find_card = sql_query.value(1).toString(); //卡号
            find_name = sql_query.value(2).toString(); //姓名
            find_phone = sql_query.value(3).toString(); //电话
            find_money = sql_query.value(4).toInt(); //余额

            if(find_card==card)
            {
                flag=1; //查找成功
                break;
            }
        }
    }

    if(flag==0)
    {
        QMessageBox::warning(this,"提示",QString("%1 此卡未注册.").arg(card),QMessageBox::Ok);
        return;
    }

    QString info=QString("卡号:%1\n姓名:%2\n电话:%3\n余额:%4\n")
            .arg(card)
            .arg(find_name)
            .arg(find_phone)
            .arg(QString("%1").arg(find_money));
    QMessageBox::information(this,"查询信息",info,QMessageBox::Ok);
}

4.10 查询全部信息

//查询VIP卡全部信息
void Widget::on_pushButton_cha_xun_all_clicked()
{
    //设置全选
    for(int i=0;i<ui->tableWidget_card_cha_xun->rowCount();i++)
    {
        ui->tableWidget_card_cha_xun->item(i,0)->setSelected(true);
    }
    /*获取选中的列表里的所有条目*/
    QList<QTableWidgetItem*> list=ui->tableWidget_card_cha_xun->selectedItems();

    /*从列表中依次移除条目*/
    for(int i=0;i<list.count();i++)
    {
        /*获取条目的行号*/
        int row=ui->tableWidget_card_cha_xun->row(list.at(i));
        delete list.at(i); //彻底删除条目
        //因为上面的循环是以条目数量为准,所以卸载行号只需要卸载一行即可
        if(row!=-1)
        {
            ui->tableWidget_card_cha_xun->removeRow(row);
        }
    }

    //指定操作的数据库
    QSqlQuery sql_query(database);
    //查询全部数据
    sql_query.prepare("select * from vip");
    if(!sql_query.exec())
    {
        Log_Text_Display("数据库查询错误.\n");
    }
    else
    {
        while(sql_query.next())
        {
            QString card = sql_query.value(1).toString(); //卡号
            QString name = sql_query.value(2).toString(); //姓名
            QString phone = sql_query.value(3).toString(); //电话
            int money=sql_query.value(4).toInt(); //余额

            //返回行数。
            int RowCount=ui->tableWidget_card_cha_xun->rowCount(); //获取当前总行数
            ui->tableWidget_card_cha_xun->setRowCount(RowCount+1); //设置行数
            int i;
            //通过总列数创建单元格
            for(i=0;i<ui->tableWidget_card_cha_xun->columnCount();i++)
            {
                ui->tableWidget_card_cha_xun->setItem(RowCount,i,new QTableWidgetItem(""));
                //设置文本对齐方式
                ui->tableWidget_card_cha_xun->item(RowCount,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
            }

            //设置文本
            ui->tableWidget_card_cha_xun->item(RowCount,0)->setText(card);
            ui->tableWidget_card_cha_xun->item(RowCount,1)->setText(name);
            ui->tableWidget_card_cha_xun->item(RowCount,2)->setText(phone);
            ui->tableWidget_card_cha_xun->item(RowCount,3)->setText(QString("%1元").arg(money));
        }
    }
}

4.11 编译运行

【1】运行之后,就可以正常的添加用户了。

image-20231206135635961

【2】对指定的用户进行充值

image-20231206135744877

image-20231206140143990

【3】查询指定用户信息

image-20231206135818915

五、登录数据库查看数据

5.1 软件端的数据

目前在我们开发的软件端,已经存入了5个用户。

image-20231206140251341

5.2 Navicat登录查看

image-20231206140332320

5.3 华为云控制台登录查看

image-20231206140438794

六、总结

这篇文章介绍了如何购买、配置、连接、测试 GaussDB数据库,并且最终采用Qt开发了一个具体的软件演示了数据库的具体应用,演示了数据库整体的使用过程。

通过对GaussDB的购买、配置、连接到实际应用的全面体验,可以深刻感受到了华为自主创新研发的分布式关系型数据库所带来的便捷与高效。GaussDB不仅具备稳定、安全、易扩展的特点,更在实际应用中展现出卓越的性能和与各种开发工具的良好兼容性。使用Qt开发的演示软件,充分展示了数据库在实际应用中的便利性,同时也体现了GaussDB在数据处理和管理方面的强大能力。GaussDB无疑为企业和个人用户提供了一个值得信赖的数据库解决方案,帮助我们在数字化时代更好地管理和应用数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/361178.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

排序链表---归并--链表OJ

https://leetcode.cn/problems/sort-list/submissions/499363940/?envTypestudy-plan-v2&envIdtop-100-liked 这里我们直接进阶&#xff0c;用时间复杂度O(nlogn)&#xff0c;空间复杂度O(1)&#xff0c;来解决。 对于归并&#xff0c;如果自上而下的话&#xff0c;空间复…

SpringAop实现访问日志功能的添加

AOP 是 Spring 体系中非常重要的两个概念之一&#xff08;另外一个是 IoC&#xff09;&#xff0c;今天这篇文章就来带大家通过实战的方式&#xff0c;在编程猫 SpringBoot 项目中使用 AOP 技术为 controller 层添加一个切面来实现接口访问的统一日志记录。 #一、关于 AOP AO…

springboot3+vue3支付宝交易案例-结算支付

springboot3vue3支付宝交易案例-结算支付&#xff01;今天下午整理了一下结算的内容。遇到了很多问题。汇总分享给大家。 第一个问题&#xff1a;支付宝结算后&#xff0c;返回的交易编码&#xff0c;和交易时间&#xff0c;交易状态&#xff0c;都应该使用varchar来存。 第二…

DMA+串口空闲中断实现RS485不定长数据接收和发送

目录 1、环境说明2、实现不定长数据接收需要做哪些事&#xff1f;2.1、数据的接收与缓存2.2、数据帧的结束判断2.3、数据帧的长度计算 3、RS485串口实现不定长数据发送4、代码实现结语&#xff1a; 1、环境说明 单片机型号;Cortex-M4架构&#xff0c;AT32F437 说明&#xff1a…

C语言操作符

文章目录 1:算术操作符2:移位操作符(移动的是二进制序列中的补码)2.1:知识补充(原码,反码,补码与二进制)2.2:左移操作符(<<)2.2:右移操作符(>>)2.2.1:逻辑右移2.2.2:算术右移 3:位操作符(运算用的是二进制位的补码)3.1:按位与操作符(&)3.2:按位或操作符(|)3.3:…

五大架构风格之一:数据流风格

数据流风格详细介绍 系统架构数据流风格是一种软件体系结构风格&#xff0c;它强调了系统内部不同部分之间的数据流动。这种风格侧重于描述系统中的数据处理过程&#xff0c;以及数据是如何从一个组件传递到另一个组件的。以下是系统架构数据流风格的详细介绍&#xff1a; 1 基…

width:100% 与 width:auto 的区别

width:100% 与 width:auto 的区别 一、当两者的子元素没有 border 或 padding 或 margin 的时候 先看一下示例代码和效果图 <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevi…

【数据结构 03】循环队列

一、原理 循环队列从功能角度具有队列的性质&#xff0c;即遵从先进先出原则&#xff0c;但是其存储方式是顺序存储。 循环队列的存储空间大小通常都是固定的&#xff0c;通过前指针和尾指针的移动控制循环队列数据的增删。 特征&#xff1a;顺序存储、先进先出、容量有限&a…

从前有条街 脚本 辅助 跳一跳

最近沉迷从前有条街。。。即将弃坑。 天工时间长的难以忍受。还好跳一跳能获得快乐水。找了一圈没有可用的脚本&#xff0c;于是自己写。。。 autojsx编写的 需要开启辅助功能跟悬浮窗 具体自行研究。 支持自动开始 无限续盘。目前只适配了1800*2400分辨率 。花了半个小时写的…

LeetCode —— 17. 电话号码的字母组合

&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️&#x1f636;‍&#x1f32b;️…

树和二叉树基础

树和二叉树基础 1.1树的概念 树是在数据结构中第一次接触到的非线性结构。 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它 叫做树是因为它看起来像一棵倒挂的树&#xff0c;也就是说它是根朝上&am…

Kotlin 协程:深入理解 ‘lifecycleScope‘

Kotlin 协程&#xff1a;深入理解 ‘lifecycleScope’ Kotlin 协程是一种强大的异步编程工具&#xff0c;它提供了一种简洁、易读的方式来处理并发和异步操作。在 Kotlin 协程库中&#xff0c;lifecycleScope 是一个关键的概念&#xff0c;它允许我们将协程的生命周期绑定到 An…

基于SSM的高校班级同学录网站设计与实现(有报告)。Javaee项目,ssm项目。

演示视频&#xff1a; 基于SSM的高校班级同学录网站设计与实现&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm项目。 项目介绍&#xff1a; Javaee项目&#xff0c;采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&…

【C++】构造函数和析构函数详解

目录 前言 类中的六个默认成员函数 构造函数 概念 特性 析构函数 概念 特性&#xff1a; 前言 类中的六个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编…

好用的IDEA插件,免费!

今天给大家推荐一款IDEA插件&#xff1a;Apipost-Helper-2.0&#xff0c;写完代码IDEA内一键生成API文档&#xff0c;无需安装、打开任何其他软件&#xff1b;写完代码IDEA内一键调试&#xff0c;无需安装、打开任何其他软件&#xff1b;生成API目录树&#xff0c;双击即可快速…

利用二分法及不动点迭代求解非线性方程(MatLab)

一、问题描述 利用二分法及不动点迭代求解非线性方程。 二、实验目的 掌握二分法及不动点迭代的算法原理&#xff1b;能分析两种方法的收敛性&#xff1b;能熟练编写代码实现利用二分法及不动点迭代来求解非线性方程。 三、实验内容及要求 二分法 (1) 编写代码计算下列数字…

1990-2021年各省绿色金融指数数据(含原始数据+测算结果)

1990-2021年全国各省绿色金融指数数据&#xff08;含原始数据结果&#xff09; 1、时间&#xff1a;1990-2021年 2、指标&#xff1a;地区、年份、该省环保项目信贷总额&#xff08;亿元&#xff09;、全省信贷总额&#xff08;亿元&#xff09;、绿色信贷、环境污染治理投资…

应用keras建立ANN模型.

介绍&#xff1a; Keras是一个开源的神经网络库&#xff0c;它基于Python语言&#xff0c;并能够在多个深度学习框架上运行&#xff0c;包括TensorFlow、Theano和CNTK。Keras提供了一种简洁而高层次的API&#xff0c;使得用户能够快速构建、训练和部署神经网络模型。 Keras的设…

【算法与数据结构】198、213、337LeetCode打家劫舍I, II, III

文章目录 一、198、打家劫舍二、213、打家劫舍 II三、337、打家劫舍III三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、198、打家劫舍 思路分析&#xff1a;打家劫舍是动态规划的的经典题目。本题的难点在于递归公式…
最新文章