QT C++实践|超详细数据库的连接和增删改查操作|附源码

news2024/10/7 16:15:29

0:前言

🪧 什么情况需要数据库?

  • 1 大规模的数据需要处理(比如上千上万的数据量)
  • 2 需要把数据信息存储起来,无论是本地还是服务上,而不是断电后数据信息就消失了。

如果不是上面的原因化,一般可以使用数组来处理。

 🪧一般常使用的数据库驱动是MYSQLQSQLITE。二者区别在于,前者用于服务器存储信息,后者用于本地存储信息。并且QSQLITE主要用于嵌入式,占用资源非常低,占用内存小,通常几百k就搞定。’

这里博主因为对MySQL熟悉一些,就使用MySQL来进行数据库的连接

一、Mysql的安装

因为我们项目的方案是程序的运行以及相关数据的存储都在一台主机上,所以不论打不打包。首先要在主机上安装Mysql的。Mysql的安装教程我参考的是这个:MySQL安装和配置教程(超详细版本)

安装好后,利用命令行或其他工具在MySQL中创建一个存储项目数据的数据库,方便之后使用QT用代码对数据库进行连接、建表和增删改查的操作:

  • Win+r打开cmd:输入命令“mysql -u root -p”,按下回车键
  • 输入MySQL密码,按下回车键
  • 创建数据库
create database [if not exists] 数据库名 [default charset 字符集] [collate 排序规则];

注意:不要忘记末尾的分号

二、通过ODBC连接MySQL数据库

官方解释:
ODBC(Open Database Connectivity,开放数据库互连)提供了一种标准的API(应用程序编程接口)方法来访问数据库管理系统(DBMS)。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC。ODBC的设计者们努力使它具有最大的独立性和开放性:与具体的编程语言无关,与具体的数据库系统无关,与具体的操作系统无关。
简单的说就是我的qt中含有ODBC的驱动:
在这里插入图片描述
所以利用ODBC去使用MySQL的数据库

2.1:下载ODBC

官网

在这里插入图片描述

选择和qt编译器相同的字节比如我的qt使用的是64字节的

下载完成后,点卡下载下来的.msi文件并运行:

在这里插入图片描述
下载一直点击next
在这里插入图片描述

选择custom,表示自定义安装(以便修改安装位置)

在这里插入图片描述
在这里插入图片描述

最后一直点击next然后再install即可,等待安装好后即可。

安装好之后,关闭窗口,搜索ODBC,并运行程序:
在这里插入图片描述

2.2:使用ODBC连接MySQL数据库

添加MySQL的DSN

在这里插入图片描述

红色的可以随便填,是自己对于ODBC驱动的描述,粉色的是MySQL的用户名和密码,数据库选择你在MySQL中创建的数据库名字即可:
在这里插入图片描述

点击Test,测试是否能够成功连接;如果出现下图说明连接成功

在这里插入图片描述

然后点击应用确定进行添加:
在这里插入图片描述

2.3:qt通过ODBC连接MySQL

现在main.cpp中加入下面代码测试一下能不能在qt中连接成功:

QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
    db.setHostName("127.0.0.1");
    db.setPort(3306);
    db.setDatabaseName("是你在ODBC中创建的Data source name");
    db.setUserName("用户名");
    db.setPassword("密码");
    bool ok = db.open();
    if (ok){
        QMessageBox::information(this, "infor", "success");
    }
    else {
        QMessageBox::information(this, "infor", "open failed");
        qDebug()<<"error open database because"<<db.lastError().text();
    }

Tips:这里可能会报错:VS2019 C1083 无法打开包括文件: “QSqlDatabase”

是vs里面项目配置的问题。
看到这个错误应该是没有dll,然后sql很容易想到数据库,所以在qt模块里添加,比较方便。
在这里插入图片描述
在这里插入图片描述

不出意外运行程序可以成功连接:
在这里插入图片描述

之后在主机进行安装时,除了打包程序,应该还需要安装对应的Mysql和ODBC

2.4:qt通过ODBC操作数据库

连接上数据库一般就是使用数据库,进行对数据库的增删改查。
这里有三种方法。

🪧 首先单独建立一个头文件来处理数据库连接,如建立头文件connection.h:

#ifndef CONNECTION_H
#define CONNECTION_H

#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>

static bool createConnection(){
    //连接第一个数据库
    //QMYSQL
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "connection1");//需要使用的数据库驱动和联检建立的名称(方便建立多个数据库连接【使用不同的数据库时】区分)
    db.setHostName("127.0.0.1");//连接地址
    db.setUserName("root");//数据库账户
    db.setPassword("root");//密码
    db.setPort(8889);//端口
    //test_majiang.db
    db.setDatabaseName("test_majiang");//需要用到的数据库

    if (!db.open()) {//如果数据库连接失败,则弹出
        //critical(QWidget *parent, const QString &title,
        //const QString &text,
        //QMessageBox::StandardButtons buttons = Ok,
        //QMessageBox::StandardButton defaultButton = NoButton)
           QMessageBox::critical(0, "Cannot open database",
                                 "Unable to establish a database connection", QMessageBox::Cancel);
           return false;
       }

    return true;
}

#endif // CONNECTION_H

如果需要移除一个数据库连接,可以使用:

 QSqlDatabase::close();//关闭数据库
 QSqlDatabase::removeDatabase();//移除该连接

2.4.1:使用QSqlQuery

头文件

#include "connection.h"
#include <QVariant>
#include <QSqlDriver>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlError>
  • 使用数据库前的准备:
    //创建数据库连接
    if(!createConnection()) return 1;//返回情况可以替换,视不同情况而定
	//指定某个数据库连接
    QSqlDatabase db2 = QSqlDatabase::database("connection1");
  • 开始对数据进行操作:
    首先创建QSqlQuery 对象,然后进行操作。
    QSqlDatabase db2 = QSqlDatabase::database("connection2");
    QSqlQuery query2(db2);
  • 进行创表和插入值:
   // qDebug() << "connection2:";
   //创建表,并插入值
       query2.exec("create table student (id int primary key,"
               "name varchar(20))");
    query2.exec("insert into student values(0, 'Mike')");
    query2.exec("insert into student values(1, 'Lili')");
    query2.exec("insert into student values(2, 'Jame')");
  • 批量处理
    上面的单条插入语句明显比较麻烦,可以使用批量插入数据:
    query2.exec("insert into student(id,name) values(3,'Qinsong')");//单挑操作

    //名称绑定
    query2.prepare("insert into student(id, name) values(:id, :name)");
    int idValue = 4;
    QString nameValue = "Songjiang";
    query2.bindValue(":id", idValue);//绑定数据
    query2.bindValue(":name", nameValue);
    query2.exec();//执行

    //位置绑定
    query2.prepare("insert into student(id, name) values(?, ?)");
    int idValue2 = 5;
    QString nameValue2 = "LingChong";
    query2.addBindValue(idValue2);//绑定数据
    query2.addBindValue(nameValue2);
    if(!query2.execBatch()) qDebug() <<"位置绑定:" <<query2.lastError() <<endl;//如果执行不成功执行

    //批量处理
    query2.prepare("insert into student(id, name) values(?,?)");
    QVariantList ids;
    ids << 6 << 7 << 8;
    query2.addBindValue(ids);
    QVariantList names;
    names << "Qinghua" << "Nanda" << "Zhongkeda";
    query2.addBindValue(names);
    if(!query2.execBatch()) qDebug() << query2.lastError()<< endl;

  • 进行查询并输出查询结果:
    query2.exec("select * from student");//执行sql语句
    while(query2.next()){
        qDebug()<< query2.value(0).toInt() << query2.value(1).toString();
    }
  • 查看数据驱动支持特性
    查看当前数据库是否是支持某特性,比如当前记录的索引数(即结果条数):
    int numRows;
    if(db2.driver()->hasFeature(QSqlDriver::QuerySize)){//是否该特性
        qDebug()<< "has feature:query size";
        numRows = query2.size();
    }else{
        qDebug() << "no feature:query size";
        query2.last();
        numRows = query2.at() + 1;//使用at,需要之前使用quey2.next()遍历所有select搜索后的结果,而使用query2.size()则不需要
    }
    
    //此处执行上面的查询操作,下面的操作才有意义
    qDebug() << "row number: " << numRows;
    //指向索引为1的记录,即第二条记录
    query2.seek(1);
    //返回当前索引值
    qDebug() << "current index:" << query2.at();
    //获得当前行的记录
    QSqlRecord record = query2.record();

    //获得记录中"id"和"name"两个字段的值
    int id = record.value("id").toInt();
    QString name = record.value("name").toString();
    qDebug() <<"id" << id << "name:" <<name;

    //获得索引为1的字段,即第二个字段
    QSqlField field = record.field(1);

    //输出字段名和字段值,结果为"name"和"MaLiang"
    qDebug() << "second field:" << field.name()
             << "field value:" << field.value().toString();

  • 事务(使数据操作变为原子性)
    如果中间有一步sql操作执行出错,则全部sql操作都不执行。
    QSqlDatabase db2 = QSqlDatabase::database("connection2");
    QSqlDatabase::database().transaction();//开始(类似于mutex线程锁)
    QSqlQuery query(db2);//此语句必须在上面一条语句的后面
    //执行sql操作
    QSqlDatabase::database().commit();//结束

2.4.2:使用QSqlQueryModel查询模型

优势:

  • 这是基于sql查询的只读模型,编写sql语句变得容易。

文件头:

#include <QSqlQueryModel>

核心代码:

  QSqlDatabase db = QSqlDatabase::database("connection1");

    QSqlQueryModel *model = new QSqlQueryModel(this);


    model->setQuery("select * from student", db);
    model->setHeaderData(0, Qt::Horizontal, tr("学号"));
    model->setHeaderData(1, Qt::Horizontal, tr("姓名"));
    model->setHeaderData(2, Qt::Horizontal, tr("课程"));

    QTableView *view = new QTableView(this);
    view->setModel(model);

    setCentralWidget(view);

2.4.3:使用QSqlTableModel表格模型⭐

先上结果
在这里插入图片描述

优势:

  • 编译的代码很容易适应其他的数据源,例如后面如果要使用xml文件来存储数据,只需要更换数据模型。

  • 提供了一次只能操作一个sql表的读/写模型,可以浏览和修改独立的sql表,并且只需编写很少的代码,无需了解sql语句。

  • 1 准备
    头文件:

#include <QSqlTableModel>
    QSqlTableModel* model;//创建对象指针
  • 2 进行操作:
    QSqlDatabase db = QSqlDatabase::database("connection1");
    model = new QSqlTableModel(this, db);//由于在窗口的类中创建对象,因此实例化对象时,使用this指针(指向操作函数的指针)作为父对象

    model->setTable("student");
    model->select();//执行
    //设置编辑策略
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);//对所有模型改变立即用到数据库
    ui->tableView->setModel(model);
  • UI设计:
    在这里插入图片描述

  • 对应槽函数:

// 提交修改按钮
void MainWindow::on_pushButton_clicked()
{
    // 开始事务操作
    model->database().transaction();
    if (model->submitAll()) {
        if(model->database().commit()) // 提交
            QMessageBox::information(this, tr("tableModel"),
                                     tr("数据修改成功!"));
    } else {
        model->database().rollback(); // 回滚
        QMessageBox::warning(this, tr("tableModel"),
                             tr("数据库错误: %1").arg(model->lastError().text()),
                             QMessageBox::Ok);
    }
}

// 撤销修改按钮
void MainWindow::on_pushButton_2_clicked()
{
    model->revertAll();
}

// 查询按钮,进行筛选
void MainWindow::on_pushButton_5_clicked()
{
    QString name = ui->lineEdit->text();

    // 根据姓名进行筛选,一定要使用单引号
    model->setFilter(QString("name = '%1'").arg(name));
    model->select();
}

// 显示全表按钮
void MainWindow::on_pushButton_6_clicked()
{
    model->setTable("student");
    model->select();
}

// 按id升序排列按钮
void MainWindow::on_pushButton_7_clicked()
{
    //id字段,即第0列,升序排列
    model->setSort(0, Qt::AscendingOrder);
    model->select();

}

// 按id降序排列按钮
void MainWindow::on_pushButton_8_clicked()
{
    model->setSort(0, Qt::DescendingOrder);
    model->select();

}
// 删除选中行按钮
void MainWindow::on_pushButton_4_clicked()
{
    // 获取选中的行
    int curRow = ui->tableView->currentIndex().row();

    // 删除该行
    model->removeRow(curRow);
    int ok = QMessageBox::warning(this,tr("删除当前行!"),
                                  tr("你确定删除当前行吗?"), QMessageBox::Yes, QMessageBox::No);
    if(ok == QMessageBox::No)
    { // 如果不删除,则撤销
        model->revertAll();
    } else { // 否则提交,在数据库中删除该行
        model->submitAll();
    }

}
// 添加记录按钮
void MainWindow::on_pushButton_3_clicked()
{
    // 获得表的行数
    int rowNum = model->rowCount();
    int id = 10;

    // 添加一行
    model->insertRow(rowNum);
    model->setData(model->index(rowNum, 0), id);

    // 可以直接提交
    //model->submitAll();
}


三、项目实战

connection.h是负责连接数据库和创建表的头文件:

#ifndef CONNECTION_H
#define CONNECTION_H

#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QDebug>
#pragma execution_character_set("utf-8"); 

static bool createConnection() {
    //连接第一个数据库
    //QMYSQL
    QSqlDatabase db = QSqlDatabase::addDatabase("QODBC", "connection1");//需要使用的数据库驱动和联检建立的名称(方便建立多个数据库连接【使用不同的数据库时】区分)
    db.setHostName("127.0.0.1");//连接地址
    db.setUserName("root");//数据库账户
    db.setPassword("55667788");//密码
    db.setPort(3306);//端口
    //test.db
    db.setDatabaseName("test");//需要用到的数据库

    if (!db.open()) {//如果数据库连接失败,则弹出
        //critical(QWidget *parent, const QString &title,
        //const QString &text,
        //QMessageBox::StandardButtons buttons = Ok,
        //QMessageBox::StandardButton defaultButton = NoButton)
        QMessageBox::critical(0, "Cannot open database",
            "Unable to establish a database connection", QMessageBox::Cancel);
        return false;
    }
    else {
        QMessageBox::information(NULL, "infor", "link success");
    }
    //下面来创建表
    //如果MySQL数据库中已经存在同名的表,则下面代码不会执行
    QSqlQuery query2(db);
    
   
    // qDebug() << "connection2:";
//创建表,并插入值
    query2.exec("create table student (id int primary key,"
        "name varchar(20))");
    query2.exec("insert into student values(0, 'Mike')");
    query2.exec("insert into student values(1, 'Lili')");
    query2.exec("insert into student values(2, 'Jame')");

}

#endif // CONNECTION_H

Admin是操作数据库的管理界面:
在这里插入图片描述
Admin.h:

#pragma once

#include <QMainWindow>
#include "ui_Admin.h"
#include <QSqlTableModel>
#pragma execution_character_set("utf-8"); 

class Admin : public QMainWindow
{
	Q_OBJECT

public:
	Admin(QWidget *parent = nullptr);
	~Admin();
	QSqlTableModel* model;//创建对象指针


private:
	Ui::AdminClass ui;

private slots:
	void on_add_clicked();
	void on_modify_clicked();
	void on_del_clicked();
	void on_rollback_clicked();
	void on_show_all_clicked();
};

Admin.cpp:

#include "Admin.h"
#include <qmessagebox.h>
#include <QSqlDatabase>
#include <QMessageBox>
#include <qsqlerror.h>
#include "connection.h"
#include <QSqlTableModel>

Admin::Admin(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	if (!createConnection()) {
		return;
	}
    QSqlDatabase db = QSqlDatabase::database("connection1");
    model = new QSqlTableModel(this, db);//由于在窗口的类中创建对象,因此实例化对象时,使用this指针(指向操作函数的指针)作为父对象

    model->setTable("student");
    model->select();//执行
    QTableView* view = new QTableView;
    view->setModel(model);

    // 你可以根据你数据库表的实际列名进行设置
    QHeaderView* header = view->horizontalHeader();
    header->setModel(model);
    header->setSectionResizeMode(QHeaderView::Stretch);

    // 设置显示名称,从0开始计数
    model->setHeaderData(0, Qt::Horizontal, tr("列名1"));
    model->setHeaderData(1, Qt::Horizontal, tr("列名2"));
    model->setHeaderData(2, Qt::Horizontal, tr("列名3"));
    //设置编辑策略
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);//对所有模型改变立即用到数据库
    ui.tableView->setModel(model);


}

Admin::~Admin()
{}

// 添加记录按钮
void Admin::on_add_clicked()
{
    // 获得表的行数
    int rowNum = model->rowCount();
    int id = 10;

    // 添加一行
    model->insertRow(rowNum);
    model->setData(model->index(rowNum, 0), id);

    // 可以直接提交
    //model->submitAll();
}

// 删除选中行按钮
void Admin::on_del_clicked()
{
    // 获取选中的行
    int curRow = ui.tableView->currentIndex().row();

    // 删除该行
    model->removeRow(curRow);
    int ok = QMessageBox::warning(this, tr("删除当前行!"),
        tr("你确定删除当前行吗?"), QMessageBox::Yes, QMessageBox::No);
    if (ok == QMessageBox::No)
    { // 如果不删除,则撤销
        model->revertAll();
    }
    else { // 否则提交,在数据库中删除该行
        model->submitAll();
    }

}
// 撤销修改按钮
void Admin::on_rollback_clicked()
{
    model->revertAll();
}

// 提交修改按钮
void Admin::on_modify_clicked()
{
    // 开始事务操作
    model->database().transaction();
    if (model->submitAll()) {
        if (model->database().commit()) // 提交
            QMessageBox::information(this, tr("tableModel"),
                tr("数据修改成功!"));
    }
    else {
        model->database().rollback(); // 回滚
        QMessageBox::warning(this, tr("tableModel"),
            tr("数据库错误: %1").arg(model->lastError().text()),
            QMessageBox::Ok);
    }
}
// 显示全表按钮
void Admin::on_show_all_clicked() {
    model->setTable("student");
    model->select();
}

功能正常:
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计算机网络-典型网络组网架构

前面基本网络知识已经能够满足中小企业的需要了&#xff0c;今天来看下一些基本网络组网架构。 首先网络是分层架构&#xff0c;从接入层到汇聚层再到核心层&#xff0c;然后接入运营商出口。内部包括有线网络、无线网络&#xff0c;出口一般可以使用路由器或者防火墙进行安全防…

人才测评工具 找准需求才能测出效果

怎么挖掘人才&#xff1f;怎么利用人才&#xff1f; 让每个员工发挥出最大的优势&#xff1f; 让每个员工奋斗在最适合的岗位&#xff1f; 每个HRer都考虑过&#xff0c;每个HR也都有自己独特的见解。 1、找准测评目的 我们都希望测评是全面的&#xff0c;360度的。要是仔…

有多少成年人学英语,全靠八卦和腹肌?

昨个儿&#xff0c;“知识大航海”群里针对老龄化问题讨论的非常激烈。 我挺喜欢这种氛围的&#xff0c;只要大家不将争论上升到地域歧视人身攻击就可以。 很多事情没有绝对的对与错&#xff0c;经过计论&#xff0c;能够开悟心智&#xff0c;这未尝不是一件好事呀。 最后&…

“平民化”非结构数据处理

在全球信息产业高速发展的背景下&#xff0c;IDC预测&#xff0c;2018 到 2025 年之间&#xff0c;全球产生的数据量将会从 33 ZB 增长到 175 ZB&#xff0c; 复合增长率27%&#xff0c;其中超过 80%的数据都会是处理难度较大的非结构化数据&#xff0c;如文档、文本、图形、图…

32-树-在每个树行中找最大值

这是树的第32篇算法&#xff0c;力扣链接。 给定一棵二叉树的根节点 root &#xff0c;请找出该二叉树中每一层的最大值。 示例1&#xff1a; 输入: root [1,3,2,5,3,null,9] 输出: [1,3,9] 层级遍历似乎天生适合解这道题&#xff1a; func largestValues(root *TreeNode) []…

实例:NX二次开发抽取平面以及标准柱面中心线

一、概述 最近体验许多外挂&#xff0c;包括胡波外挂、星空外挂及模圣等都有抽取面的中心线&#xff0c;由于刚刚学习&#xff0c;我尝试看看能不能做出来&#xff0c;本博客代码没有封装函数&#xff0c;代码有待改进&#xff0c;但基本可以实现相应的功能。 二、案例实现的功…

浅谈MySQL的B树索引与索引优化

MySQL的MyISAM、InnoDB引擎默认均使用B树索引&#xff08;查询时都显示为“BTREE”&#xff09;&#xff0c;本文讨论两个问题&#xff1a; 为什么MySQL等主流数据库选择B树的索引结构&#xff1f;如何基于索引结构&#xff0c;理解常见的MySQL索引优化思路&#xff1f; 为什…

火锅底料加工厂污废水如何处理达标排放

火锅底料加工厂作为食品加工行业的一员&#xff0c;其生产过程中不可避免地会产生大量的污废水。为了保护环境和维护公共健康&#xff0c;火锅底料加工厂应当采取措施对污废水进行处理&#xff0c;使其达到国家相关排放标准。那么&#xff0c;火锅底料加工厂污废水该如何处理才…

ffmpeg单张图片生成固定时长的视频

ffmpeg -r 25 -f image2 -loop 1 -i fps_1.jpg -vcodec libx264 -pix_fmt yuv420p -s 1080*1920 -r 25 -t 30 -y fps.mp4这个命令将 fps_1.jpg 图片转换为一个 30 秒长的视频&#xff0c;分辨率为 1920x1080&#xff0c;帧率为 25 帧/秒&#xff0c;并使用 libx264 编码器进行压…

数据中心GPU集群高性能组网技术分析

数据中心GPU集群组网技术是指将多个GPU设备连接在一起&#xff0c;形成一个高性能计算的集群系统。通过集群组网技术&#xff0c;可以实现多个GPU设备之间的协同计算&#xff0c;提供更大规模的计算能力&#xff0c;适用于需要大规模并行计算的应用场景。 常用的组网技术&…

HTML5+CSS3小实例:环绕小球弹性loading动画

实例:环绕小球弹性loading动画 技术栈:HTML+CSS 效果: 源码: 【HTML】 <!DOCTYPE html> <html lang="zh-CN"><head><meta charset="UTF-8" /><meta http-equiv="X-UA-Compatible" content="IE=edge&quo…

C# WPF编程-创建项目

1.创建新项目 选择“WPF应用程序”》“下一步” 2. 设置项目 设置项目名称&#xff0c;保存位置等参数>下一步 3.选择框架 4.项目创建成功 5.运行项目

Failed to build tree: parent link [base_link] of joint [lidar_joint] not found

参考&#xff1a; Failed to build tree: parent link [base_link] of joint 在古月居gazebo 的基础教程里&#xff0c;运行古月居的mbot的launch文件报错&#xff0c;小机器人不出现。 主要原因是提供的xacro文件的宏定义没有放在xacro的命名空间。 解决&#xff1a; 将<mb…

网络编程第二天

1.基于TCP的通信(面向连接的通信) 服务器代码实现&#xff1a; #include <myhead.h> #define IP "192.168.126.91" #define PORT 9999 int main(int argc, const char *argv[]) {//1、创建套接字int sfd-1;if((sfdsocket(AF_INET,SOCK_STREAM,0))-1){perror(…

ROS 2基础概念#2:节点(Node)| ROS 2学习笔记

ROS 2节点简介 节点是执行计算的进程。节点组合在一起形成一个图&#xff08;graph&#xff09;&#xff0c;并使用主题&#xff08;topic&#xff09;、服务&#xff08;service&#xff09;和参数服务器&#xff08;paramter server&#xff09;相互通信。这些节点旨在以细粒…

Ps:路径面板

Ps菜单&#xff1a;窗口/路径 Window/Paths “路径”面板 Paths Panel提供了一系列功能&#xff0c;使用户能够创建、编辑、保存和利用路径。 ◆ ◆ ◆ 路径分类 在“路径”面板上的路径可分为五大类。 常规路径 Saved Path 也称“已保存的路径”&#xff0c;指的是已经存储在…

【三维重建】【SLAM】SplaTAM:基于3D高斯的密集RGB-D SLAM

题目&#xff1a;SplaTAM: Splat, Track & Map 3D Gaussians for Dense RGB-D SLAM 地址&#xff1a;spla-tam.github.io 机构&#xff1a;CMU&#xff08;卡内基梅隆大学&#xff09;、MIT&#xff08;美国麻省理工&#xff09; 总结&#xff1a;SplaTAM&#xff0c;一个新…

MyBatis 学习(三)之 MyBatis 全局配置文件

目录 1 MyBatis 全局配置文件 2 properties 元素 3 setting 设置 4 typeAlianses 别名处理器 5 typeHandler 类型处理器 6 objectFacotry 对象工厂&#xff08;了解&#xff09; 7 plugins 插件&#xff08;了解&#xff09; 8 environments 运行环境 9 databaseIdPro…

如何对酒店开展科学的定岗定编——以酒店健身房、娱乐房为例

近年来&#xff0c;随着旅游行业的快速发展&#xff0c;也带动了酒店业的兴盛。酒店的经营效益不仅受益于旅游业&#xff0c;同时也受制于旅游行业。由于旅游业存在明显的季节性差异&#xff0c;旅游旺季客流量多、淡季客流量少&#xff0c;造成人员忙闲不均的问题。酒店行业也…

怎么恢复删除的文件?6种有效的数据恢复方法汇总!

怎么才能恢复被删掉的数据啊&#xff1f;现在都是数字化时代了&#xff0c;我们的电脑里装了好多重要数据&#xff0c;一旦丢了&#xff0c;可是会给我们的工作和生活带来极大的麻烦啊。所以&#xff0c;学几招有效的电脑数据恢复方法是挺有必要的。下面&#xff0c;我就给大家…