QT数据库(三):QSqlQuery使用

QSqlQuery 简介

QSqlQuery 是能运行任何 SQL 语句的类,如 SELECT、INSERT、UPDATE、DELETE 等 SQL

语句。所以使用 QSqlQuery 几乎能进行任何操作,例如创建数据表、修改数据表的字段定义、进行数据统计等。如果运行的是 SELECT 语句,它查询出的数据可以作为一个数据集,但是并不能作为模型/视图结构中的数据模型。

QSqlTableModel 和 QSqlQueryModel 一般用于基于记录的操作,如数据浏览和修改,而 QSqlQuery 能通过运行 SQL 语句实现对数据进行批量修改。

QSqlQuery 类中常用的函数如下表所示:

创建QSqlQuery对象(构造函数)

QSqlQuery(const QSqlDatabase &db)

QSqlQuery(const QString &query = QString(), const QSqlDatabase &db = QSqlDatabase())

创建 QSqlQuery 对象时可以传递 SQL 语句和数据库连接,如果不传递任何参数,就表示不设

置 SQL 语句,并使用默认的数据库连接。

SQL 语句的设置和运行

1、直接使用exec(QString)接口函数

QSqlQuery query; 
query.exec("SELECT * FROM employee"); //查询数据
query.exec("UPDATE employee SET Salary=6000 where Gender='女'"); //更新数据

2、使用带参数的SQL语句(适合动态生成)

可以使用函数 prepare()设置带有参数的 SQL 语句,然后用函

数 bindValue()设置 SQL 语句中的各参数值,再用函数 exec()运行 SQL 语句。

QSqlQuery query; 
query.prepare("SELECT empNo, Name, Gender, Salary FROM employee " " WHERE Gender =:sex AND Salary >=:salary"); 
query.bindValue(":sex", "男"); 
query.bindValue(":salary", 5000); 
query.exec();

bindValue()函数的原型定义如下:

void QSqlQuery::bindValue(const QString &placeholder, const QVariant &val, QSql::ParamType paramType = QSql::In)

其中,placeholder 是 SQL 语句中用于占位的参数名;val 是参数的值;paramType 是参数类型,默认值为 QSql::In,表示传递给数据库的值。若 paramType 设置为 QSql::Out,表示该参数是一个返回值,在运行函数 exec()后,这个参数会被数据库返回的值覆盖。

还有另一种参数形式的 bindValue()函数,其原型定义如下:

void QSqlQuery::bindValue(int pos, const QVariant &val, QSql::ParamType paramType = QSql::In)

其中,参数 pos 是占位符位置序号,第一个参数位置序号为 0;val 是参数值;paramType 是参数

类型,默认值为 QSql::In。

在使用?或":参数名"作为占位符时可以用按序号设置参数的形式:

QSqlQuery query; 
query.prepare("UPDATE employee SET Department=?, Salary=? WHERE EmpNo =?"); 
query.bindValue(0, "技术部"); 
query.bindValue(1, 5000); 
query.bindValue(2, 2006); 
query.exec();QSqlQuery query; 
query.prepare("SELECT empNo, Name, Gender, Salary FROM employee " " WHERE Gender =:sex AND Salary >=:salary"); 
query.bindValue(0 "男"); 
query.bindValue(1, 5000); 
query.exec();

使用?占位时,还可以使用addBindValue()按顺序添加参数值:

QSqlQuery query; 
query.prepare("UPDATE employee SET Department=?, Salary=? WHERE EmpNo =?"); 
query.addBindValue("技术部"); 
query.addBindValue(6000); 
query.addBindValue(1007); 
query.exec();

其中addBindValue()函数原型定义如下(无需给出占位符的序号):

void QSqlQuery::addBindValue(const QVariant &val, QSql::ParamType paramType = QSql::In)

记录移动

如果 QSqlQuery 运行的是 SELECT 语句,会返回一个数据集,并且有一个当前行。first()、

previous()、next()、last()等函数可用于进行当前行的移动。函数 record()返回当前行的记录,其函数原型定义如下:QSqlRecord QSqlQuery::record()

注意区分QSqlQueryModel也有该函数接口,record()可以带参数,不带参数返回的是字段名。

而在QSqlQuery中,record()没有任何参数,如果当前行是有效的,返回的 QSqlRecord 对象包含当前记录的数据,否则返回的是一条空记录。

使用函数 seek()可以定位到指定序号的记录,这个函数原型定义如下:

bool QSqlQuery::seek(int index, bool relative = false)

其中,参数 relative 表示绝对位置(false)或相对位置(true)。若 relative 为 false,参数 index 表示需要移动到的绝对位置,数据集的首记录位置为 0。若 relative 为 true,参数 index 表示相对于当前位置移动的行数,index 为正数表示向尾记录方向移动,index 为负数表示向首记录方向移动。

示例程序解读

主窗口构造函数

设置了tableView组件不能进行编辑(QSqlQueryModel获取的数据是只读的,因此与该模型关联的组件也应该设置成不可编辑),选择只能选择单行。

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);this->setCentralWidget(ui->tableView);ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);      //不能编辑ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);     //行选择ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);    //单行选择ui->tableView->setAlternatingRowColors(true);
}

打开数据表

创建QSqlQueryModel 类对象 qryModel,从数据表 employee 里查询除字段的数据,并作为界面上的视图组件 tableView 的数据模型。并创建选择模型,没有为currentRowChanged()信号设置槽函数,即不对记录移动进行处理。

//打开数据表
void MainWindow::selectData()
{qryModel= new QSqlQueryModel(this);selModel= new QItemSelectionModel(qryModel,this);ui->tableView->setModel(qryModel);ui->tableView->setSelectionModel(selModel);qryModel->setQuery("SELECT empNo,Name, Gender, Birthday, Province, Department,""Salary FROM employee order by empNo");if (qryModel->lastError().isValid()){QMessageBox::information(this, "错误", "数据表查询错误,错误信息
"+qryModel->lastError().text());return;}QSqlRecord rec=qryModel->record();  //获取空记录,用于获取字段序号//    connect(theSelection,&QItemSelectionModel::currentRowChanged,//            this, &MainWindow::do_currentRowChanged);//设置字段显示标题qryModel->setHeaderData(rec.indexOf("empNo"),    Qt::Horizontal, "工号");qryModel->setHeaderData(rec.indexOf("Name"),     Qt::Horizontal, "姓名");qryModel->setHeaderData(rec.indexOf("Gender"),   Qt::Horizontal, "性别");qryModel->setHeaderData(rec.indexOf("Birthday"), Qt::Horizontal, "出生日期");qryModel->setHeaderData(rec.indexOf("Province"), Qt::Horizontal, "省份");qryModel->setHeaderData(rec.indexOf("Department"),   Qt::Horizontal, "部门");qryModel->setHeaderData(rec.indexOf("Salary"),       Qt::Horizontal, "工资");ui->actOpenDB->setEnabled(false);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actRecEdit->setEnabled(true);ui->actScan->setEnabled(true);
}

记录编辑对话框

由于主窗口中的tableView是只读的,因此为了实现对特定记录进行修改,需要创建一个记录编辑对话框,在主界面点击编辑记录会弹出来。

对话框类的内容如下:

#ifndef TDIALOGDATA_H
#define TDIALOGDATA_H#include    <QDialog>
#include    <QSqlRecord>QT_BEGIN_NAMESPACE
namespace Ui { class TDialogData; }
QT_END_NAMESPACEclass TDialogData : public QDialog
{Q_OBJECTprivate:QSqlRecord  m_record;    //保存一条记录的数据public:TDialogData(QWidget *parent = nullptr);~TDialogData();void    setUpdateRecord(QSqlRecord &recData);   //更新记录void    setInsertRecord(QSqlRecord &recData);   //插入记录QSqlRecord  getRecordData();     //获取界面输入的数据private slots:void on_btnClearPhoto_clicked(); //清除照片void on_btnSetPhoto_clicked();   //设置照片private:Ui::TDialogData *ui;
};#endif // TDIALOGDATA_H

QSqlRecord 类型的私有变量 m_record 用于保存一条记录的数据,插入一条记录时,程序创建对话框后要调用函数 setInsertRecord()初始化对话框的数据。编辑一条记录时,程序创建对话框后要调用函数 setUpdateRecord()初始化对话框的数据。调用对话框的程序可以在对话框的“确定”按钮被点击后,调用函数 getRecordData()获得对话框中输入的记录数据。

//编辑记录,更新记录数据到界面
void TDialogData::setUpdateRecord(QSqlRecord &recData)
{m_record=recData;    //记录存入私有变量ui->spinEmpNo->setEnabled(false);   //员工编号不允许编辑setWindowTitle("更新记录");//根据recData的数据更新界面显示ui->spinEmpNo->setValue(recData.value("empNo").toInt());ui->editName->setText(recData.value("Name").toString());ui->comboSex->setCurrentText(recData.value("Gender").toString());ui->editBirth->setDate(recData.value("Birthday").toDate());ui->comboProvince->setCurrentText(recData.value("Province").toString());ui->comboDep->setCurrentText(recData.value("Department").toString());ui->spinSalary->setValue(recData.value("Salary").toInt());ui->editMemo->setPlainText(recData.value("Memo").toString());QVariant    va=recData.value("Photo");if (!va.isValid())  //图片字段内容为空ui->LabPhoto->clear();else    //显示图片{QByteArray data=va.toByteArray();QPixmap pic;pic.loadFromData(data);ui->LabPhoto->setPixmap(pic.scaledToWidth(ui->LabPhoto->size().width()));}
}//插入记录,无需更新界面显示,但是要存储recData的字段结构
void TDialogData::setInsertRecord(QSqlRecord &recData)
{m_record=recData;    //保存recData到私有变量ui->spinEmpNo->setEnabled(true);    //插入的记录,员工编号允许编辑setWindowTitle("插入新记录");ui->spinEmpNo->setValue(recData.value("empNo").toInt());
}//点击"确定"按钮后,界面数据保存到记录变量mRecord
QSqlRecord TDialogData::getRecordData()
{m_record.setValue("empNo",   ui->spinEmpNo->value());m_record.setValue("Name",    ui->editName->text());m_record.setValue("Gender",  ui->comboSex->currentText());m_record.setValue("Birthday",ui->editBirth->date());m_record.setValue("Province",    ui->comboProvince->currentText());m_record.setValue("Department",  ui->comboDep->currentText());m_record.setValue("Salary",  ui->spinSalary->value());m_record.setValue("Memo",    ui->editMemo->toPlainText());//照片编辑时已经修改了mRecord的photo字段的值return  m_record; //以记录作为返回值
}

在主界面点击编辑或添加某条记录时,会传入QSqlRecord类型的引用recData,recData就是主界面与对话框通信的变量,主界面通过该数据向对话框传递用于显示,在对话框中更改了数据保存后会传递到主界面。

另外对于BLOB类型数据,这里为图像,需要为数据类型提供一个修改更新接口:

void TDialogData::on_btnClearPhoto_clicked()
{ //清除照片ui->LabPhoto->clear();m_record.setNull("Photo");   //Photo字段清空
}void TDialogData::on_btnSetPhoto_clicked()
{//设置照片QString aFile=QFileDialog::getOpenFileName(this,"选择图片文件","", "照片(*.jpg)");if (aFile.isEmpty())return;QByteArray data;QFile* file=new QFile(aFile);file->open(QIODevice::ReadOnly);data = file->readAll();file->close();m_record.setValue("Photo",data); //图片保存到Photo字段QPixmap pic;pic.loadFromData(data);ui->LabPhoto->setPixmap(pic.scaledToWidth(ui->LabPhoto->size().width()));
}

记录编辑

在主界面中当点击编辑(或者双击记录时)时,会获取当前记录的索引,然后创建一个上述的编辑对话框对记录进行编辑,根据索引在qryModel模型中拿到该记录,通过调用对话框的接口与该记录的引用就能实现对记录的修改。这里需要注意修改QSqlRecord的recData后需要通过QSqlQuery来执行SQL语句来更新到数据库。

void MainWindow::on_actRecEdit_triggered()
{//编辑当前记录int curRecNo=selModel->currentIndex().row();updateRecord(curRecNo);
}void MainWindow::on_tableView_doubleClicked(const QModelIndex &index)
{ //tableView上双击,编辑当前记录int curRecNo=index.row();updateRecord(curRecNo);
}void MainWindow::updateRecord(int recNo)
{ //更新一条记录QSqlRecord  curRec=qryModel->record(recNo); //获取数据模型的一条记录int empNo=curRec.value("EmpNo").toInt();    //获取EmpNoQSqlQuery query(DB);query.prepare("select * from employee where EmpNo = :ID");query.bindValue(":ID",empNo);query.exec();query.first();if (!query.isValid())   //无有效记录return;curRec=query.record();  //获取当前记录TDialogData    *dataDialog=new TDialogData(this); //创建对话框Qt::WindowFlags    flags=dataDialog->windowFlags();dataDialog->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //对话框固定大小dataDialog->setUpdateRecord(curRec);    //更新对话框的数据和界面int ret=dataDialog->exec();       //显示对话框if (ret==QDialog::Accepted){QSqlRecord  recData=dataDialog->getRecordData();    //获得对话框返回的记录query.prepare("update employee set Name=:Name, Gender=:Gender,"" Birthday=:Birthday,  Province=:Province,"" Department=:Department, Salary=:Salary,"" Memo=:Memo, Photo=:Photo "" where EmpNo = :ID");query.bindValue(":Name",    recData.value("Name"));query.bindValue(":Gender",  recData.value("Gender"));query.bindValue(":Birthday",recData.value("Birthday"));query.bindValue(":Province",recData.value("Province"));query.bindValue(":Department",  recData.value("Department"));query.bindValue(":Salary",  recData.value("Salary"));query.bindValue(":Memo",    recData.value("Memo"));query.bindValue(":Photo",   recData.value("Photo"));query.bindValue(":ID",      empNo);if (!query.exec())QMessageBox::critical(this, "错误", "记录更新错误
"+query.lastError().text());else{// Qt 6.5.1中修改QString str= qryModel->query().executedQuery();   //获取执行过的SQL语句qryModel->setQuery(str);     //重新执行SQL语句
//            qryModel->query().exec();   //数据模型重新查询数据,更新tableView显示}}delete dataDialog;      //删除对话框
}

函数 updateRecord()的输入参数 recNo 是数据模型 qryModel 当前记录的行号。程序先获取当 前记录的 EmpNo 字段的值,即工号,然后使用一个 QSqlQuery 对象从数据表里查询出关于这个员 工的所有字段的一条记录。由于 EmpNo 是数据表 employee 的主键字段,不允许出现重复,因此 只会查询出一条记录,查询出的这条完整记录被保存到变量 curRec 中。

程序创建对话框 dataDialog,调用函数 setUpdateRecord()将保存完整记录的 curRec 传递给对话框,对话框 dataDialog 以模态方式显示。如果点击“确定”按钮,程序再通过函数 getRecordData()

获取对话框编辑后的记录数据。

程序里使用 QSqlQuery 对象运行带有参数的 UPDATE 语句更新一条记录。更新成功后,数据库

需要将数据模型 qryModel 的 SQL 语句重新运行一次,这样才可以更新 tableView 的显示内容。

插入记录

与编辑记录类似,只是插入需首先用 QSqlQuery 对象 query 运行一条 SQL 语句“select * from employee where EmpNo = -1”, 这样不会查询到记录,其目的是得到一条空记录 curRec。创建对话框 dataDialog 后,我们调用对话框的函数 setInsertRecord()及传入的空记录初始化对话框的数据用于显示。

/插入记录
void MainWindow::on_actRecInsert_triggered()
{QSqlQuery query;query.exec("select * from employee where EmpNo =-1");   //实际查不出记录,只查询字段信息QSqlRecord curRec=query.record();   //获取当前记录,实际为空记录curRec.setValue("EmpNo",qryModel->rowCount()+3000);TDialogData    *dataDialog=new TDialogData(this);Qt::WindowFlags    flags=dataDialog->windowFlags();dataDialog->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //对话框固定大小dataDialog->setInsertRecord(curRec); //插入记录int ret=dataDialog->exec();if (ret==QDialog::Accepted){QSqlRecord  recData=dataDialog->getRecordData();query.prepare("INSERT INTO employee (EmpNo,Name,Gender,Birthday,Province,"" Department,Salary,Memo,Photo) "" VALUES(:EmpNo,:Name, :Gender,:Birthday,:Province,"" :Department,:Salary,:Memo,:Photo)");query.bindValue(":EmpNo",recData.value("EmpNo"));query.bindValue(":Name",recData.value("Name"));query.bindValue(":Gender",recData.value("Gender"));query.bindValue(":Birthday",recData.value("Birthday"));query.bindValue(":Province",recData.value("Province"));query.bindValue(":Department",recData.value("Department"));query.bindValue(":Salary",recData.value("Salary"));query.bindValue(":Memo",recData.value("Memo"));query.bindValue(":Photo",recData.value("Photo"));if (!query.exec())QMessageBox::critical(this, "错误", "插入记录错误
"+query.lastError().text());else //插入,删除记录后需要重新设置SQL语句查询{QString sqlStr=qryModel->query().executedQuery();   //执行过的SELECT语句qryModel->setQuery(sqlStr);         //重新查询数据}}delete dataDialog;
}

删除记录

从数据模型 qryModel 的当前记录获取工号,然后用一个 QSqlQuery 对象运行一条 DELETE

语句删除这条记录。删除记录后需要重新设置数据模型 qryModel 的 SQL 语句并查询数据,以更

新数据集和 tableView 的显示内容。

//删除当前记录
void MainWindow::on_actRecDelete_triggered()
{int curRecNo=selModel->currentIndex().row();QSqlRecord  curRec=qryModel->record(curRecNo); //获取当前记录if (curRec.isEmpty()) //当前为空记录return;int empNo=curRec.value("EmpNo").toInt();    //获取员工编号QSqlQuery query;query.prepare("delete  from employee where EmpNo = :ID");query.bindValue(":ID",empNo);if (!query.exec())QMessageBox::critical(this, "错误", "删除记录出现错误
"+query.lastError().text());else //插入,删除记录后需要重新设置SQL语句查询{QString sqlStr=qryModel->query().executedQuery();//  执行过的SELECT语句qryModel->setQuery(sqlStr);         //重新查询数据}
}

遍历记录

有两种方式,一种是使用了两个 QSqlQuery 变量,其中 qryEmpList 用于查询 EmpNo 和 Salary 这两个字段的全部记录,qryUpdate 用于运行一条带有参数的 UPDATE 语句,每次更新一条记录的 Salary 字段数据。qryEmpList 被设置为仅能前向移动,这样可以提高程序运行效率。

另一种方式是只需运行一条 SQL 语句,功能完全相同。

//涨工资,遍历记录
void MainWindow::on_actScan_triggered()
{
//遍历记录的方式
//    QSqlQuery qryUpdate;    //用于临时执行SQL语句
//    qryUpdate.prepare("UPDATE employee SET Salary=:Salary WHERE EmpNo = :ID");//    QSqlQuery qryEmpList;
//    qryEmpList.setForwardOnly(true);   //设置为仅能前向移动,提高查询性能
//    qryEmpList.exec("SELECT empNo,Salary FROM employee ORDER BY empNo");
//    qryEmpList.first();
//    while (qryEmpList.isValid()) //当前记录有效
//    {
//        int empID=qryEmpList.value("empNo").toInt();
//        float salary=1000+qryEmpList.value("Salary").toFloat();
//        qryUpdate.bindValue(":ID",empID);
//        qryUpdate.bindValue(":Salary",salary);
//        qryUpdate.exec();
//        qryEmpList.next();//移动到下一条记录,
//    }//    qryModel->query().exec();   //数据模型重新查询数据,更新tableView的显示
//    QMessageBox::information(this, "提示", "涨工资计算完毕");//    /直接执行SQL语句的方式QSqlQuery qryUpdate;qryUpdate.exec("UPDATE employee SET Salary=Salary+1000");//在Qt 6.5 中修改的代码QString str= qryModel->query().executedQuery();   //获取执行过的SQL语句qryModel->setQuery(str);     //重新执行SQL语句
//    qryModel->query().exec();   //数据模型重新查询数据,更新tableView的显示, Qt 6.2.1中的代码,用Qt 6.5编译有错误QMessageBox::information(this, "提示", "涨工资计算完毕");
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构(考研)

线性表 顺序表 顺序表的静态分配 //线性表的元素类型为 ElemType//顺序表的静态分配 #define MaxSize10 typedef int ElemType; typedef struct{ElemType data[MaxSize];int length; }SqList;顺序表的动态分配 //顺序表的动态分配 #define InitSize 10 typedef struct{El…

Unity DeepSeek API 聊天接入教程(0基础教学)

Unity DeepSeek API 聊天接入教程(0基础教学) 1.DeepSeek 介绍 DeepSeek是杭州深度求索人工智能基础技术研究有限公司推出的一款大语言模型。2025年1月20日&#xff0c;DeepSeek-R1正式上线&#xff0c;和当前市面上的主流AI相比&#xff0c;它在仅有极少标注数据的情况下&am…

PAT乙级真题 — 1090 危险品装箱(java)

集装箱运输货物时&#xff0c;我们必须特别小心&#xff0c;不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱&#xff0c;否则很容易造成爆炸。 本题给定一张不相容物品的清单&#xff0c;需要你检查每一张集装箱货品清单&#xff0c;判断它们是否能装在…

Navicat16安装教程(附安装包)2025最新版详细图文安装教程

文章目录 前言一、Navicat16安装包下载&#xff1f;二、安装步骤1.运行安装程序2.安装程序3.阅读许可协议4.选择安装位置5.选择附加任务6.准备安装7.完成安装8.使用设置 前言 Navicat 16 是一款好用的数据库管理软件&#xff0c;能让你轻松操作各类数据库。本教程会一步一步教…

论文阅读 DOES END-TO-END AUTONOMOUS DRIVING REALLY NEED PERCEPTION TASKS?

端到端的强势来袭&#xff0c;好久了~~~ 简单翻译&#xff1a;端到端真的需要感知任务嘛&#xff1f; code https://github.com/PeidongLi/SSR. https://arxiv.org/pdf/2409.18341 1. 摘要 端到端自动驾驶&#xff08;E2EAD&#xff09;方法通常依赖于监督式感知任务来提取显…

【记忆化搜索】矩阵中的最长递增路径

文章目录 329. 矩阵中的最长递增路径解题思路&#xff1a;暴搜 -> 记忆化搜索 329. 矩阵中的最长递增路径 329. 矩阵中的最长递增路径 ​ 给定一个 m x n 整数矩阵 matrix &#xff0c;找出其中 最长递增路径 的长度。 ​ 对于每个单元格&#xff0c;你可以往上&#xff…

获取某厂招聘岗位信息

今天方向一个爬虫案例&#xff0c;爬取某厂招聘岗位信息数据&#xff0c;通过程序可以学习pymysql的使用&#xff0c;通过pycharm工具获取数据&#xff0c;并且导入mysql数据库中。 1 导入必要的包 import requests import pymysql2 主体代码 class Baidu(object):def __init…

deepseek R1基本原理解读与系列论文简介

文章目录 前言一、deepseek R1发展史二、deepseek R1简介1、R1简介2、R1成功秘诀3、R1推理模型概念4、R1自我进化与顿悟时刻特点5、不同处理方法比较6、训练流程7、训练阶段8、R1的MLA结构9、R1的MOE结构10、R1的MTP结构11、R1的GRPO结构三、DeepSeek LLM Scaling Open-Source …

数据分析--数据清洗

一、数据清洗的重要性&#xff1a;数据质量决定分析成败 1.1 真实案例警示 电商平台事故&#xff1a;2019年某电商大促期间&#xff0c;因价格数据未清洗导致错误标价&#xff0c;产生3000万元损失医疗数据分析&#xff1a;未清洗的异常血压值&#xff08;如300mmHg&#xff…

【进阶】微服务

微服务架构 服务架构演变过程 单体应用架构 所有的功能都在一个项目中&#xff08;现在使用的就是单体架构&#xff09; 集群架构 把一个单体项目部署多个&#xff0c;使用Nginx进行负载均衡&#xff0c;根据负载均衡策略调用后端服务 不好的地方&#xff1a;有的服务访问…

浏览器开发者工具(F12)查看请求的响应体内容显示”无法加载响应数据: No resource with given identifier found“

背景 复习在 SSM&#xff08;Spring Spring MVC MyBatis&#xff09;框架中&#xff0c;点击登录请求后返回 JSON 格式的数据&#xff0c;出现只有登录失败的请求才有响应值&#xff0c;比如&#xff1a; {success: false, message: “没有此用户”, code: 400} 而成功的请求…

Mybatisplus自定义sql

文章目录 引言流程 引言 mybatisplus最擅长的将where里面的语句给简便化&#xff0c;而不用我们自己写标签来实现条件查询 但是很多公司规范我们将sql写在mapper层中&#xff0c;不能写在service中 而且一些语句查询的不同select count(*) xxx from xxx 也难以用mp来实现 如何…

级联选择器多选动态加载

一.级联展示 注&#xff1a;因为级联选择器这里是动态加载&#xff0c;因此如果上来选中一级就需要加载出后面三级的全部数据&#xff0c;依然会很卡&#xff0c;因此&#xff0c;和产品协商把一二级多选框去掉了&#xff0c;这样也避免了你选择一级不能实现子级被全部选中的问…

MySQL-事务隔离级别

事务有四大特性&#xff08;ACID&#xff09;&#xff1a;原子性&#xff0c;一致性&#xff0c;隔离性和持久性。隔离性一般在事务并发的时候需要保证事务的隔离性&#xff0c;事务并发会出现很多问题&#xff0c;包括脏写&#xff0c;脏读&#xff0c;不可重复读&#xff0c;…

【带你 langchain 双排系列教程】2. langchain 提示词工程应用实践

一、简介 提示词工程在利用 LangChain 与大型语言模型交互中起着关键作用&#xff0c;通过精心设计提示词&#xff0c;可以引导模型生成更准确、更符合预期的输出&#xff0c;从而提升应用的效果和用户体验。 二、基本提示词调用 可以使用 LangChain 提供的 PromptTemplate 来…

git删除本地分支

一、命令方式 1、查看本地分支 git branch 2、切换到一个不删除的分支 git checkout branch_name 3、强制删除分支 git branch -D local_branch_name 二、工具方式 1、选择"Browse references"&#xff0c;右键"Delete branch"

[Computer Vision]实验四:相机标定

目录 一、实验内容 二、实验过程及结果 2.1 实验代码 2.2 实验结果及分析 一、实验内容 了解针孔照相机的相关知识&#xff0c;实现相机标定。&#xff08;可使用提供的棋盘格或自行打印&#xff09; 可视化棋盘格关键点、匹配点数&#xff08;可加ransac&#xff09;输出…

C++笔记之标准库中用于处理迭代器的`std::advance`和`std::distance`

C++笔记之标准库中用于处理迭代器的std::advance和std::distance code review! 文章目录 C++笔记之标准库中用于处理迭代器的`std::advance`和`std::distance`一.`std::advance`函数原型参数说明使用场景示例代码示例 1:移动 `std::vector` 的随机访问迭代器示例 2:移动 `st…

【C++】36.C++IO流

文章目录 1. C语言的输入与输出2. 流是什么3. CIO流3.1 C标准IO流3.2 C文件IO流 4. stringstream的简单介绍 1. C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放在变量中。pri…

【抽象代数】1.2. 半群与群

群的定义 群非空集合二元运算性质 定义1. 设 为一个非空集合&#xff0c;上有二元运算&#xff0c;满足结合律&#xff0c;则称或为一个半群。 定义2. 设 为半群&#xff0c;若元素 满足 &#xff0c;则称 为 的左幺元&#xff08;右幺元&#xff1a;&#xff09;&#…