当前位置: 首页 > news >正文

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, "错误", "数据表查询错误,错误信息\n"+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, "错误", "记录更新错误\n"+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, "错误", "插入记录错误\n"+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, "错误", "删除记录出现错误\n"+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, "提示", "涨工资计算完毕");
}

相关文章:

QT数据库(三):QSqlQuery使用

QSqlQuery 简介 QSqlQuery 是能运行任何 SQL 语句的类&#xff0c;如 SELECT、INSERT、UPDATE、DELETE 等 SQL 语句。所以使用 QSqlQuery 几乎能进行任何操作&#xff0c;例如创建数据表、修改数据表的字段定义、进行数据统计等。如果运行的是 SELECT 语句&#xff0c;它查询…...

【机器学习】在向量的流光中,揽数理星河为衣,以线性代数为钥,轻启机器学习黎明的瑰丽诗章

文章目录 线性代数入门&#xff1a;机器学习零基础小白指南前言一、向量&#xff1a;数据的基本单元1.1 什么是向量&#xff1f;1.1.1 举个例子&#xff1a; 1.2 向量的表示与维度1.2.1 向量的维度1.2.2 向量的表示方法 1.3 向量的基本运算1.3.1 向量加法1.3.2 向量的数乘1.3.3…...

设计模式详解(十一):模板方法——Template Method

Template Method 设计模式 1. 概述 Template Method 是一种行为设计模式&#xff0c;它定义了一个算法的框架&#xff0c;并允许子类在不改变算法结构的前提下重新定义算法中的某些步骤。 在 Template Method 模式中&#xff1a; 父类&#xff08;抽象类&#xff09;定义了…...

使用 DeepSpeed 微调 OPT 基础语言模型

文章目录 OPT 基础语言模型Using OPT with DeepSpeedmain.py 解析1、导入库和模块2、解析命令行参数3、main 函数3.1 设备与分布式初始化3.2 模型与数据准备3.3 定义评估函数3.4 优化器与学习率调度器设置3.5 使用 deepspeed 进行模型等初始化3.6 训练循环3.7 模型保存 4、dsch…...

DPDK用户态协议栈-TCP Posix API 2

tcp posix api send发送 ssize_t nsend(int sockfd, const void *buf, size_t len, __attribute__((unused))int flags) {ssize_t length 0;void* hostinfo get_host_fromfd(sockfd);if (hostinfo NULL) {return -1;}struct ln_tcp_stream* stream (struct ln_tcp_stream…...

打造微信小程序中的视频播放交互体验:videoUI组件库实战

本文还有配套的精品资源&#xff0c;点击获取 简介&#xff1a;本项目介绍如何利用 videoUI 组件库在微信小程序中实现视频切换播放和全屏播放功能。涵盖微信小程序开发基础、 <video> 组件使用、视频切换逻辑、全屏播放实现以及 videoUI 库的应用。为开发者提供…...

Django REST framework(DRF)在处理不同请求方法时的完整流程

文章目录 一、POST 请求创建对象的流程二、GET 请求获取对象列表的流程三、GET 请求获取单个对象的流程四、PUT/PATCH 请求更新对象的流程五、自定义方法的流程自定义 GET 方法自定义 POST 方法 一、POST 请求创建对象的流程 请求到达视图层 方法调用&#xff1a; dispatch说明…...

【Hive】-- hive 3.1.3 伪分布式部署(单节点)

1、环境准备 1.1、版本选择 apache hive 3.1.3 apache hadoop 3.1.0 oracle jdk 1.8 mysql 8.0.15 操作系统:Mac os 10.151.2、软件下载 https://archive.apache.org/dist/hive/ https://archive.apache.org/dist/hadoop/ 1.3、解压 tar -zxvf apache-hive-4.0.0-bin.tar…...

unity 雷达

unity 雷达 首先去商店下载TouchScript插件 导入的时候勾选Enable TUIO 然后把预制体Cursors和TouchManager拖上 最后把TuioInput这个脚本挂上 脚本上的端口号尽量不改...

Visual Studio 2022 安装和管理 GitHub Copilot

&#x1f380;&#x1f380;&#x1f380;【AI辅助编程系列】&#x1f380;&#x1f380;&#x1f380; Visual Studio 使用 GitHub Copilot 与 IntelliCode 辅助编码Visual Studio 安装和管理 GitHub CopilotVisual Studio 使用 GitHub Copilot 扩展Visual Studio 使用 GitHu…...

Python从0到100(七十三):Python OpenCV-OpenCV实现手势虚拟拖拽

前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Python爬虫、Web开发、 计算机视觉、机器学习、神经网络以及人工智能…...

利用notepad++删除特定关键字所在的行

1、按组合键Ctrl H&#xff0c;查找模式选择 ‘正则表达式’&#xff0c;不选 ‘.匹配新行’ 2、查找目标输入 &#xff1a; ^.*关键字.*\r\n (不保留空行) ^.*关键字.*$ (保留空行)3、替换为&#xff1a;&#xff08;空&#xff09; 配置界面参考下图&#xff1a; ​​…...

Alan Chhabra:MongoDB AI应用程序计划(MAAP) 为客户提供价值

MongoDB全球合作伙伴执行副总裁 Alan Chhabra 每当有人向我问询MongoDB&#xff0c;我都会说他们很可能在不觉之间已经与MongoDB有过交集。事实上&#xff0c;包括70%财富百强在内的许多世界领先企业公司都在使用MongoDB。我们在MongoDB所做的一切都是为了服务客户&#xff0c…...

FFmpeg 实战解复用与复用

FFmpeg FFmpeg 是一个功能强大、广泛使用的多媒体处理工具,可以处理音频、视频、字幕以及多种容器格式的操作。它支持解码、编码、复用、解复用、流式传输、过滤等功能。以下是关于 FFmpeg 的一些核心信息和操作说明: 核心组件 FFmpeg 是由以下几个主要库组成的: libavcode…...

数据结构(顺序表)JAVA方法的介绍

前言 在 Java 中&#xff0c;集合类&#xff08;Collections&#xff09;是构建高效程序的核心组件之一&#xff0c;而 List 接口作为集合框架中的重要一员&#xff0c;是一个有序、可重复的元素集合。与 Set 接口不同&#xff0c;List 保证了元素的顺序性&#xff0c;并允许存…...

电商商品详情API接口(item get)数据分析上货

电商商品详情API接口&#xff08;item get&#xff09;在数据分析与商品上货方面发挥着重要作用。以下是对这两个方面的详细探讨&#xff1a; 一、数据分析 数据源获取&#xff1a; 商品详情API接口提供了丰富的数据源&#xff0c;包括商品的标题、价格、库存、描述、图片、用…...

supervisor使用详解

0、介绍 supervisor 是一个用 Python 编写的客户端/服务器系统&#xff0c;它允许用户在类 UNIX 操作系统&#xff08;如 Linux&#xff09;上监控和控制进程。supervisor 并不是一个分布式调度框架&#xff0c;而是一个进程管理工具&#xff0c;它可以用来启动、停止和重启程…...

结合开源低代码-microi吾码 阿里云建桶,以及minio文件转移阿里云oss

前言 最近在工作中&#xff0c;碰到一开始一个小程序的照片和视频都放在公司的minio服务器上存储。但日积月累的&#xff0c;而且这个客户的访问量也大&#xff0c;照片和视频每天的存储空间也很大&#xff0c;这每天也是比不菲的费用&#xff0c;而且也会加慢后台的访问速度。…...

如何为IntelliJ IDEA配置JVM参数

在使用IntelliJ IDEA进行Java开发时&#xff0c;合理配置JVM参数对于优化项目性能和资源管理至关重要。IntelliJ IDEA提供了两种方便的方式来设置JVM参数&#xff0c;以确保你的应用程序能够在最佳状态下运行。本文将详细介绍这两种方法&#xff1a;通过工具栏编辑配置和通过服…...

关于SQL注入的面试题及经验分享

Q&#xff1a;简述数据库的存储引擎 A&#xff1a;数据库存储引擎是数据库底层软件组织&#xff0c;数据库管理系统&#xff08;DBMS&#xff09;使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能&#xff0c;使用不…...

ISP(Image Signal Processor)——HDR技术总结

传统多帧融合技术 拍摄一系列不同曝光时长的图像帧&#xff08;LDR&#xff09;&#xff0c;然后使用融合算法进行融合成HDR图像。 融合算法可以分为两种 基于照度图估计的融合 基于照度估计需要拟合相机响应函数&#xff0c;详细可以参考如下论文&#xff1a; Recovering H…...

Python字符串及正则表达式(十):字符串常用操作、字符串编码转换

前言&#xff1a;在编程的世界里&#xff0c;字符串无处不在。它们是构建用户界面、存储数据、进行通信的基础元素。无论是财务系统的总账报表、电子游戏的比赛结果&#xff0c;还是火车站的列车时刻表&#xff0c;这些信息最终都需要以文本的形式呈现给用户。这些文本的背后&a…...

测试工程师八股文04|计算机网络 和 其他

一、计算机网络 1、http和https的区别 HTTP和HTTPS是用于在互联网上传输数据的协议。它们都是应用层协议&#xff0c;建立在TCP/IP协议栈之上&#xff0c;用于客户端&#xff08;如浏览器&#xff09;和服务器之间的通信。 ①http和https的主要区别在于安全性。http是一种明…...

Codeforces Global Round 27的C题

题目大意 给定一个n,n>5 ans0 ans&a1|a2&a3|a4&a5...an,数组a是一个排列 下标是奇数让ans对其进行&操作,否则进行|操作,求ans能达到的最大值. 分奇偶来讨论,在n为奇数的情况下,最后一次操作是|,在n为偶数的情况下,最后一次操作是&. n二进制最高位的计算…...

【Linux】Nginx一个域名https一个地址配置多个项目【项目实战】

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…...

第36次CCF计算机软件能力认证 梦境巡查

梦境巡查 刷新 时间限制&#xff1a; 1.0 秒 空间限制&#xff1a; 512 MiB 相关文件&#xff1a; 题目目录 题目背景 传说每当月光遍布西西艾弗岛&#xff0c;总有一道身影默默守护着居民们的美梦。 题目描述 梦境中的西西艾弗岛由 &#xfffd;1n1 个区域组成。梦境…...

[机器学习]AdaBoost(数学原理 + 例子解释 + 代码实战)

AdaBoost AdaBoost&#xff08;Adaptive Boosting&#xff09;是一种Boosting算法&#xff0c;它通过迭代地训练弱分类器并将它们组合成一个强分类器来提高分类性能。 AdaBoost算法的特点是它能够自适应地调整样本的权重&#xff0c;使那些被错误分类的样本在后续的训练中得到…...

传统零售商商业升级的核心动机及与互联网业务融合的探索——以 AI 智能名片 S2B2C 商城小程序源码为例

摘要&#xff1a;本文旨在探讨传统零售商尝试商业升级的核心动机&#xff0c;并以 AI 智能名片 S2B2C 商城小程序源码为典型案例&#xff0c;分析互联网业务模式如何助力传统零售商转型。通过剖析传统零售增长模式的局限以及互联网业务在增长速度、迭代试错和用户需求洞察方面的…...

飞牛 fnos docker镜像部署OpenSpeedtest宽带网速测试教程

penSpeedTest是一个跨平台的网络测速应用&#xff0c;支持不同操作系统的浏览器&#xff0c;无需安装额外软件或插件。您可以在iPhone、iPad、Android设备、Windows和Linux系统的电脑、手机和平板上直接测试设备与NAS之间的宽带速度。 通过这个可以排查出设备与NAS之间的传输速…...

【C++】list

OK&#xff0c;最近浅浅学习了STL的list&#xff0c;有兴趣不妨垂阅&#xff01; 目录 1.constructor 2.assign 3.insert 4.erase 5. reverse 6.swap 7.merge 8.unique 9.splice 10.小知识 同样的&#xff0c;使用list 需要包含一个头文件<list>。<list&g…...

keepalive的高可用集群

一、keepalived概述 1.keepalive的工作原理 keepalive是专门为了lvs集群开发出来的&#xff0c;但是适用场景不仅仅局限于lvs。而且keepalive为后台的真实服务器做了一个健康检查&#xff0c;当服务不可用时&#xff0c;会自动的移除ipvs的转发策略&#xff0c;服务恢复时&…...

HTTP 协议报文结构 | 返回状态码详解

注&#xff1a;本文为 “HTTP 历史 | 协议报文结构 | 返回状态码” 相关文章合辑。 未整理去重。 HTTP 历史 wangjunliang 最后更新: 2024/3/16 上午10:29 超文本传输协议(英语:HyperTextTransferProtocol,缩写:HTTP)是 万维网(World Wide Web)的基础协议&#xff61;自 蒂姆…...

如何保证开源AI呼入机器人和AI呼出机器人的服务质量?

如何保证开源AI呼入机器人和AI呼出机器人的服务质量&#xff1f; 确保开源AI呼入机器人和AI呼出机器人的服务质量是企业成功部署这些智能系统的关键。高质量的服务不仅能够提高客户满意度&#xff0c;还能增强企业的市场竞争力。以下是实现这一目标的几个关键策略和技术措施&a…...

C++day7

#include <iostream>using namespace std; template <class T> class mylist{ public:struct Link{T val;Link* next;Link* front;};//增void insert(T val);//删void remove(T val);//改mylist& operator[](int index);//排序void Sort();//遍历void show();/…...

docker搭建Redis集群及哨兵(windows10环境,OSS Cluster)

一、基本概念 Redis:即 "Remote DIctionary Server" &#xff0c;翻译为“远程字典服务器”。从字面意义上讲&#xff0c;它指的是一个远程的字典服务&#xff0c;意味着它是一个可以远程访问的服务&#xff0c;主要用于存储键值对&#xff08;key-value pairs&…...

第8章 搬移特性

8.1 搬移函数 模块化是优秀软件设计的核心所在&#xff0c;好的模块化能够让我在修改程序时只需理解程序的一小部分。为了设计出高度模块化的程序&#xff0c;我得保证互相关联的软件要素都能集中到一块&#xff0c;并确保块与块之间的联系易于查找、直观易懂。同时&#xff0c…...

[IT项目管理]项目时间管理(本章节3w字爆肝)

七.项目时间管理 7.1 项目进度的重要性 为什么要重视项目进度&#xff1a;在项目进行的过程之中会遇到变故。但是不论项目中发生了什么&#xff0c;时间总是在流逝&#xff0c;就可能会导致项目不可以在规定的时间完成。 7.2可能影响项目进度的因素 有员工离职个人的工作方…...

k8s中设置annotation的方法总结

k8s中设置annotation的方法总结 annotation是什么 在 Kubernetes 中&#xff0c;Annotations 是一种用于向 Kubernetes 对象附加非标识性元数据的机制。 annotation有什么用 annotation与 Labels 类似&#xff0c;但有一些关键区别和特定用途。 常用于存储与对象相关的配置…...

第19天:信息收集-Web应用源码获取闭源备份开发泄漏WebPack打包资源搜索ICO定位

#知识点 1、信息收集-Web应用-源码获取-已知指纹&未知指纹 2、信息收集-Web应用-源码获取-泄漏问题&发现指纹 一、参考文章&#xff1a; https://www.secpulse.com/archives/124398.html https://mp.weixin.qq.com/s/QgLDdaefXlZtvlSiFQShZw 二、源码泄漏原因&#xff…...

uniapp小程序的锚点定位(将页面滚动到目标位置)

小程序中&#xff0c;a页面跳转到b页面&#xff0c;跳转后滚动定位到b页面的特定位置。 1.uni.pageScrollTo传递一个scrollTop参数可以滚动到特定位置。2.可以通过 uni.createSelectorQuery()等获取定位元素的位置信息。3.uni.getSystemInfoSync()获取设备的导航栏和状态栏高度…...

py脚本部署到服务器定时启动

py脚本部署到服务器定时启动 一、准备好你的脚本二、把脚本放到服务器三、在服务器创建脚本所需要的环境1、安装 Miniconda&#xff08;如果不想安装 Anaconda 或 Miniconda&#xff0c;可以直接使用 Python 的venv模块创建虚拟环境&#xff0c;但安装 Conda 会更方便管理不同版…...

相机不动,机构动作----Hands Eyes

最近在研究 手眼标定&#xff0c;发现大家都需付费&#xff0c;搞啥子&#xff0c;说好的开源。。。 以相机在上固定不动&#xff0c;机械手为 EPSON_Robot 为例&#xff0c;详细的一步一步实例操作指引 EPSON_Robot 的192.168.0.1 2004 Server 详细操作步骤 1. 启动程序 运…...

Jdk1.7到Jdk1.8 HashMap 发生了什么变化(底层)

从JDK 1.7到JDK 1.8&#xff0c;HashMap在底层实现上发生了显著的变化&#xff0c; 主要体现在数据结构、链表插入方式、哈希算法、扩容机制以及并发性方面。 以下是具体的变化点&#xff1a; 1. 数据结构的变化 JDK 1.7&#xff1a;HashMap的底层数据结构是数组单向链表。…...

微积分复习笔记 Calculus Volume 2 - 4.2 Direction Fields and Numerical Methods

4.2 Direction Fields and Numerical Methods - Calculus Volume 2 | OpenStax...

java后端环境配置

因为现在升学了&#xff0c;以前本来想毕业干java的&#xff0c;很多java的环境配置早就忘掉了&#xff08;比如mysql maven jdk idea&#xff09;&#xff0c;想写个博客记录下来&#xff0c;以后方便自己快速搭建环境 JAVA后端开发配置 环境配置jdkideamavenMySQLnavicate17…...

Unity UI Button 事件优先级调整技术方案

Unity UI Button 事件优先级调整技术方案 在 Unity 项目开发过程中&#xff0c;针对 UI Button 的事件执行顺序控制是一个常见需求。本文详细阐述两种将新添加事件置于第一个执行位置的方法&#xff0c;旨在为开发者提供全面且专业的技术参考。 一、基于反射机制的事件插入方…...

【从零开始入门unity游戏开发之——C#篇04】栈(Stack)和堆(Heap),值类型和引用类型,以及特殊的引用类型string

文章目录 知识回顾一、栈&#xff08;Stack&#xff09;和堆&#xff08;Heap&#xff09;1、什么是栈和堆2、为什么要分栈和堆3、栈和堆的区别栈堆 4、总结 二、值类型和引用类型1、那么值类型和引用类型到底有什么区别呢&#xff1f;值类型引用类型 2、总结 三、特殊的引用类…...

PHP排序算法:数组内有A~E,A移到C或者C移到B后排序,还按原顺序排序,循环

效果 PHP代码 public function demo($params){function moveNext($arr){$length count($arr);$lastElement $arr[$length - 1];for ($i $length - 1; $i > 0; $i--) {$arr[$i] $arr[$i - 1];}$arr[0] $lastElement;return $arr;}function moveAndReplace($array, $from…...

keepalived的高可用集群

keepalived的概念 keepalived的工作原理 基于vrrp实现的调度器高可用方案 keepalived的配置实验 先在调度服务器上安装keepalived和ipvsadm apt -y install keepalived ipvsadm 复制keepalived的配置文件到/etc/keepalived/目录下 cp /usr/share/doc/keepalived/samples/keep…...

基于单片机的农田灌溉系统(论文+源码)

1.系统设计 本系统主要实现如下目标&#xff1a; 1&#xff0e;可以实时监测土壤湿度&#xff1b; 2&#xff0e;土壤湿度太低时&#xff0c;进行浇水操作&#xff1b; 3&#xff0e;可以按键设置湿度的触发阈值&#xff1b; 4. 可以实现远程操控 5&#xff0e;可以实现手…...