[ 转载]Qt数据库操作(附MFC sqlite c++ wrapper)

举报
Amrf 发表于 2019/01/06 23:38:21 2019/01/06
【摘要】 https://www.cnblogs.com/xia-weiwen/p/6806709.htmlhttps://blog.csdn.net/xiaoaid01/article/details/17998013http://shouce.jb51.net/qt-beginning/28.html第23篇 数据库(三)利用QSqlQuery类执行SQL语句导语SQL即结构化查询语言,是关系数据...

https://www.cnblogs.com/xia-weiwen/p/6806709.html

https://blog.csdn.net/xiaoaid01/article/details/17998013

http://shouce.jb51.net/qt-beginning/28.html

第23篇 数据库(三)利用QSqlQuery类执行SQL语句

导语

SQL即结构化查询语言,是关系数据库的标准语言。前面两节中已经在Qt里利用QSqlQuery类执行了SQL语句,这一节我们将详细讲解该类的使用。需要说明,因为我们重在讲解Qt中的数据库使用,而非专业的讲解数据库知识,所以不会对数据库中的一些知识进行深入讲解。

环境:Windows Xp + Qt 4.8.4+Qt Creator2.6.2

目录

  • 一、创建数据库连接

  • 二、操作结果集

  • 三、在SQL语句中使用变量

  • 四、批处理操作

  • 五、事务操作

正文

一、创建数据库连接

前面我们是在主函数中创建数据库连接,然后打开并使用。实际中为了明了方便,一般将数据库连接单独放在一个头文件中。下面来看一个例子。

1.新建Qt Gui应用,项目名称为myquery,基类为QMainWindow,类名为MainWindow。完成后打开myquery.pro并将第一行代码更改为:

QT       += coregui sql

然后保存该文件。

2.向项目中添加新的C++头文件,名称为connection.h,然后打开该文件,更改如下:

#ifndef CONNECTION_H#define CONNECTION_H#include <QMessageBox>#include <QSqlDatabase>#include <QSqlQuery>static bool createConnection(){
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");    if (!db.open()) {
       QMessageBox::critical(0, qApp->tr("Cannot open database"),
           qApp->tr("Unable to establisha database connection."
                     ), QMessageBox::Cancel);       return false;
    }
    QSqlQuery query;
    query.exec("create table student (id int primary key, "
               "name varchar(20))");
    query.exec("insert into student values(0, 'first')");
    query.exec("insert into student values(1, 'second')");
    query.exec("insert into student values(2, 'third')");
    query.exec("insert into student values(3, 'fourth')");
    query.exec("insert into student values(4, 'fifth')");    return true;
}#endif // CONNECTION_H

在这个头文件中我们添加了一个建立连接的函数,使用这个头文件的目的就是要简化主函数中的内容。这里先创建了一个SQLite数据库的默认连接,设置数据库名称时使用了“:memory:”,表明这个是建立在内存中的数据库,也就是说该数据库只在程序运行期间有效,等程序运行结束时就会将其销毁。当然,大家也可以将其改为一个具体的数据库名称,比如“my.db”,这样就会在项目目录中创建该数据库文件了。下面使用open()函数将数据库打开,如果打开失败,则弹出提示对话框。最后使用QSqlQuery创建了一个student表,并插入了包含idname两个属性的五条记录,如下图所示。其中,id属性是int类型的,“primary key”表明该属性是主键,它不能为空,而且不能有重复的值;而name属性是varchar类型的,并且不大于20个字符。这里使用的SQL语句都要包含在双引号中,如果一行写不完,那么分行后,每一行都要使用两个双引号引起来。

需要注意,代码中的query没有进行任何指定就可以操作前面打开的数据库,这是因为现在只有一个数据库连接,它就是默认连接,这时候所有的操作都是针对该连接的。但是如果要同时操作多个数据库连接,就需要进行指定了,这方面内容可以参考《Qt Creator快速入门》的第17章。

3.下面我们到main.cpp中调用连接函数。

#include "mainwindow.h"#include <QApplication>#include "connection.h"int main(int argc, char *argv[]){    QApplication a(argc, argv);    if (!createConnection())           return 1;

    MainWindow w;
    w.show();    return a.exec();
}

4.我们往界面上添加一个按钮来实现查询操作。双击mainwindow.ui文件进入设计模式。然后将一个Push Button拖到界面上,并修改其显示文本为“查询”。效果如下图所示。

5.在查询按钮上点击鼠标右键,选择“转到槽”,然后选择clicked()单击信号槽并点击确定,如下图所示。

6.将槽的内容更改如下:

void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.exec("select * from student");    while(query.next())
    {
       qDebug() << query.value(0).toInt()
                                      << query.value(1).toString();
    }
}

7.在mainwindow.cpp文件中添加头文件:

#include <QSqlQuery>#include <QDebug>

8.运行程序,然后按下查询按钮,在应用程序输出窗口将会输出结果,效果如下图所示。

二、操作结果集

在前面的程序中,我们使用query.exec("select * from student");查询出表中所有的内容。其中的SQL语句“select * from student”“*”号表明查询表中记录的所有属性。而当query.exec("select * from student");这条语句执行完后,我们便获得了相应的执行结果,因为获得的结果可能不止一条记录,所以称之为结果集。

结果集其实就是查询到的所有记录的集合,在QSqlQuery类中提供了多个函数来操作这个集合,需要注意这个集合中的记录是从0开始编号的。最常用的操作有:

  • seek(int n) :query指向结果集的第n条记录;

  • first() :query指向结果集的第一条记录;

  • last() :query指向结果集的最后一条记录;

  • next() :query指向下一条记录,每执行一次该函数,便指向相邻的下一条记录;

  • previous() :query指向上一条记录,每执行一次该函数,便指向相邻的上一条记录;

  • record() :获得现在指向的记录;

  • value(int n) :获得属性的值。其中n表示你查询的第n个属性,比方上面我们使用“select * from student”就相当于“select id, name from student”,那么value(0)返回id属性的值,value(1)返回name属性的值。该函数返回QVariant类型的数据,关于该类型与其他类型的对应关系,可以在帮助中查看QVariant。

  • at() :获得现在query指向的记录在结果集中的编号。

需要特别注意,刚执行完query.exec("select *from student");这行代码时,query是指向结果集以外的,我们可以利用query.next()使得 query指向结果集的第一条记录。当然我们也可以利用seek(0)函数或者first()函数使query指向结果集的第一条记录。但是为了节省内存开销,推荐的方法是,在query.exec("select * from student");这行代码前加上query.setForwardOnly(true);这条代码,此后只能使用next()seek()函数。

下面我们通过例子来演示一下这些函数的使用。将槽更改如下:

void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.exec("select * from student");
    qDebug() << "exec next() :";    //开始就先执行一次next()函数,那么query指向结果集的第一条记录
    if(query.next())
    {       //获取query所指向的记录在结果集中的编号
       int rowNum = query.at();       //获取每条记录中属性(即列)的个数
       int columnNum = query.record().count();       //获取"name"属性所在列的编号,列从左向右编号,最左边的编号为0
       int fieldNo = query.record().indexOf("name");       //获取id属性的值,并转换为int型
       int id = query.value(0).toInt();       //获取name属性的值
       QString name = query.value(fieldNo).toString();       //将结果输出
       qDebug() << "rowNum is : " << rowNum
                 << " id is : " << id
                 << " name is : " << name
                 << " columnNum is : " << columnNum;
    }//定位到结果集中编号为2的记录,即第三条记录,因为第一条记录的编号为0
    qDebug() << "exec seek(2) :";    if(query.seek(2))
    {
       qDebug() << "rowNum is : " << query.at()
                 << " id is : " << query.value(0).toInt()
                 << " name is : " << query.value(1).toString();
    }    //定位到结果集中最后一条记录
    qDebug() << "exec last() :";    if(query.last())
    {
       qDebug() << "rowNum is : " << query.at()
                 << " id is : " << query.value(0).toInt()
                 << " name is : " << query.value(1).toString();
    }
}

最后在mainwindow.cpp中添加#include <QSqlRecord>头文件包含,运行程序,点击查询按钮,输出结果如下图所示。

三、在SQL语句中使用变量

1.我们先来看一个例子。首先在设计模式往界面上添加一个Spin Box部件,如下图所示。

2.将查询按钮槽里面的内容更改如下:

void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;    int id = ui->spinBox->value();
    query.exec(QString("select name from student where id =%1")
               .arg(id));
    query.next();
    QString name = query.value(0).toString();
    qDebug() << name;
}

这里使用了QString类的arg()函数实现了在SQL语句中使用变量,我们运行程序,更改Spin Box的值,然后点击查询按钮,效果如下图所示。

3.其实在QSqlQuery类中提供了数据绑定同样可以实现在SQL语句中使用变量,虽然它也是通过占位符来实现的,不过使用它形式上更明了一些。下面先来看一个例子,将查询按钮槽更改如下:

void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.prepare("insert into student (id, name) "
                  "values (:id, :name)");
    query.bindValue(0, 5);
    query.bindValue(1, "sixth");
    query.exec();
    query.exec("select * from student");
    query.last();    int id = query.value(0).toInt();
    QString name = query.value(1).toString();
    qDebug() << id << name;
}

这里在student表的最后又添加了一条记录。然后我们先使用了prepare()函数,在其中利用了“:id”“:name”来代替具体的数据,而后又利用bindValue()函数给idname两个属性赋值,这称为绑定操作。其中编号0和1分别代表“:id”“:name”,就是说按照prepare()函数中出现的属性从左到右编号,最左边是0 。

特别注意,在最后一定要执行exec()函数,所做的操作才能被真正执行。运行程序,点击查询按钮,可以看到前面添加的记录的信息。这里的“:id”“:name”,叫做占位符,这是ODBC数据库的表示方法,还有一种Oracle的表示方法就是全部用“?”号。例如:

query.prepare("insert into student(id, name) "
                  "values (?, ?)");
query.bindValue(0, 5);
query.bindValue(1, "sixth");
query.exec();

也可以利用addBindValue()函数,这样就可以省去编号,它是按顺序给属性赋值的,如下:

query.prepare("insert into student(id, name) "
                  "values (?, ?)");
query.addBindValue(5);
query.addBindValue("sixth");
query.exec();

当用ODBC的表示方法时,我们也可以将编号用实际的占位符代替,如下:

query.prepare("insert into student(id, name) "
                      "values (:id, :name)");
query.bindValue(":id", 5);
query.bindValue(":name", "sixth");
query.exec();

以上各种形式的表示方式效果是一样的。

4.下面我们演示一下通过绑定操作在SQL语句中使用变量。更改槽函数如下:

void MainWindow::on_pushButton_clicked()
{
    QSqlQuery query;
    query.prepare("select name from student where id = ?");    int id = ui->spinBox->value();
    query.addBindValue(id);
    query.exec();
    query.next();
    qDebug() << query.value(0).toString();
}

运行程序,可以实现通过Spin Box的值来进行查询。

四、批处理操作

当要进行多条记录的操作时,我们就可以利用绑定进行批处理。将槽更改如下:

void MainWindow::on_pushButton_clicked()
{
    QSqlQuery q;
    q.prepare("insert into student values (?, ?)");
    QVariantList ints;
    ints << 10 << 11 << 12 << 13;
    q.addBindValue(ints);
    QVariantList names;    // 最后一个是空字符串,应与前面的格式相同
        names << "xiaoming" << "xiaoliang"
                      << "xiaogang" << QVariant(QVariant::String);
    q.addBindValue(names);    if (!q.execBatch()) //进行批处理,如果出错就输出错误
       qDebug() << q.lastError();    //下面输出整张表
    QSqlQuery query;
    query.exec("select * from student");    while(query.next())
    {       int id = query.value(0).toInt();
       QString name = query.value(1).toString();
       qDebug() << id << name;
    }
}

然后需要在mainwindow.cpp上添加头文件包含:#include <QSqlError>。我们在程序中利用列表存储了同一属性的多个值,然后进行了值绑定。最后执行execBatch()函数进行批处理。注意程序中利用QVariant(QVariant::String)来输入空值NULL,因为前面都是QString类型的,所以这里要使用QVariant::String 使格式一致化。 运行程序,效果如下图所示:

五、事务操作

事务可以保证一个复杂的操作的原子性,就是对于一个数据库操作序列,这些操作要么全部做完,要么一条也不做,它是一个不可分割的工作单位。在Qt中,如果底层的数据库引擎支持事务,那么QSqlDriver::hasFeature(QSqlDriver::Transactions)会返回true。可以使用QSqlDatabase::transaction()来启动一个事务,然后编写一些希望在事务中执行的SQL语句,最后调用QSqlDatabase::commit()或者QSqlDatabase::rollback()。当使用事务时必须在创建查询以前就开始事务,例如:

QSqlDatabase::database().transaction();
QSqlQuery query;
query.exec("SELECT id FROMemployee WHERE name = 'Torild Halvorsen'");if (query.next()) {    int employeeId = query.value(0).toInt();
    query.exec("INSERT INTO project(id, name, ownerid) "
               "VALUES (201, 'ManhattanProject', "
               + QString::number(employeeId) + ')');
}
QSqlDatabase::database().commit();

结语

对执行SQL语句我们就介绍这么多,其实Qt中提供了更为简单的不需要SQL语句就可以操作数据库的方法,我们在下一节讲述这些内容。

涉及到的源码:

https://www.devbean.net/2013/06/qt-study-road-2-database/

Qt 学习之路 2(55):数据库操作

豆子 2013年6月14日 Qt 学习之路 2 79条评论


Qt 提供了 QtSql 模块来提供平台-独立的基于 SQL 的数据库操作。这里我们所说的“平台-独立”,既包括操作系统平台,又包括各个数据库平台。另外,我们强调了“基于 SQL”,因为 NoSQL 数据库至今没有一个通用查询方法,所以不可能提供一种通用的 NoSQL 数据库的操作。Qt 的数据库操作还可以很方便的与 model/view 架构进行整合。通常来说,我们对数据库的操作更多地在于对数据库表的操作,而这正是 model/view 架构的长项。


Qt 使用QSqlDatabase表示一个数据库连接。更底层上,Qt 使用驱动(drivers)来与不同的数据库 API 进行交互。Qt 桌面版本提供了如下几种驱动:

 驱动数据库
QDB2IBM DB2 (7.1 或更新版本)
QIBASEBorland InterBase
QMYSQLMySQL
QOCIOracle Call Interface Driver
QODBCOpen Database Connectivity (ODBC) – Microsoft SQL Server 及其它兼容 ODBC 的数据库
QPSQLPostgreSQL (7.3 或更新版本)
QSQLITE2SQLite 2
QSQLITESQLite 3
QSYMSQL针对 Symbian 平台的SQLite 3
QTDSSybase Adaptive Server (自 Qt 4.7 起废除)

不过,由于受到协议的限制,Qt 开源版本并没有提供上面所有驱动的二进制版本,而仅仅以源代码的形式提供。通常,Qt 只默认搭载 QSqlite 驱动(这个驱动实际还包括 Sqlite 数据库,也就是说,如果需要使用 Sqlite 的话,只需要该驱动即可)。我们可以选择把这些驱动作为 Qt 的一部分进行编译,也可以当作插件编译。

如果习惯于使用 SQL 语句,我们可以选择QSqlQuery类;如果只需要使用高层次的数据库接口(不关心 SQL 语法),我们可以选择QSqlTableModelQSqlRelationalTableModel。本章我们介绍QSqlQuery类,在后面的章节则介绍QSqlTableModelQSqlRelationalTableModel

在使用时,我们可以通过

C/C++

1 lines

QSqlDatabase::drivers();

找到系统中所有可用的数据库驱动的名字列表。我们只能使用出现在列表中的驱动。由于默认情况下,QtSql 是作为 Qt 的一个模块提供的。为了使用有关数据库的类,我们必须早 .pro 文件中添加这么一句:

QT += sql

这表示,我们的程序需要使用 Qt 的 core、gui 以及 sql 三个模块。注意,如果需要同时使用 Qt4 和 Qt5 编译程序,通常我们的 .pro 文件是这样的:

Plain Text

2 lines

QT += core gui sql
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

这两句也很明确:Qt 需要加载 core、gui 和 sql 三个模块,如果主板本大于 4,则再添加 widgets 模块。

下面来看一个简单的函数:

C/C++

15 lines

bool connect(const QString &dbName)
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
//    db.setHostName("host");
//    db.setDatabaseName("dbname");
//    db.setUserName("username");
//    db.setPassword("password");
    db.setDatabaseName(dbName);
    if (!db.open()) {
        QMessageBox::critical(0, QObject::tr("Database Error"),
                              db.lastError().text());
        return false;
    }
    return true;
}

我们使用connect()函数创建一个数据库连接。我们使用QSqlDatabase::addDatabase()静态函数完成这一请求,也就是创建了一个QSqlDatabase实例。注意,数据库连接使用自己的名字进行区分,而不是数据库的名字。例如,我们可以使用下面的语句:

C/C++

QSqlDatabase db=QSqlDatabase::addDatabase("QSQLITE", QString("con%1").arg(dbName));

此时,我们是使用addDatabase()函数的第二个参数来给这个数据库连接一个名字。在这个例子中,用于区分这个数据库连接的名字是QString("conn%1").arg(dbName),而不是 “QSQLITE”。这个参数是可选的,如果不指定,系统会给出一个默认的名字QSqlDatabase::defaultConnection,此时,Qt 会创建一个默认的连接。如果你给出的名字与已存在的名字相同,新的连接会替换掉已有的连接。通过这种设计,我们可以为一个数据库建立多个连接。

我们这里使用的是 sqlite 数据库,只需要指定数据库名字即可。如果是数据库服务器,比如 MySQL,我们还需要指定主机名、端口号、用户名和密码,这些语句使用注释进行了简单的说明。

接下来我们调用了QSqlDatabase::open()函数,打开这个数据库连接。通过检查open()函数的返回值,我们可以判断数据库是不是正确打开。

QtSql 模块中的类大多具有lastError()函数,用于检查最新出现的错误。如果你发现数据库操作有任何问题,应该使用这个函数进行错误的检查。这一点我们也在上面的代码中进行了体现。当然,这只是最简单的实现,一般来说,更好的设计是,不要在数据库操作中混杂界面代码(并且将这个connect()函数放在一个专门的数据库操作类中)。

接下来我们可以在main()函数中使用这个connect()函数:

C/C++

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    if (connect("demo.db")) {
        QSqlQuery query;
        if (!query.exec("CREATE TABLE student ("
                        "id INTEGER PRIMARY KEY AUTOINCREMENT,"
                        "name VARCHAR,"
                        "age INT)")) {
            QMessageBox::critical(0, QObject::tr("Database Error"),
                                  query.lastError().text());
            return 1;
        }
    } else {
        return 1;
    }
    return a.exec();
}

main()函数中,我们调用这个connect()函数打开数据库。如果打开成功,我们通过一个QSqlQuery实例执行了 SQL 语句。同样,我们使用其lastError()函数检查了执行结果是否正确。

注意这里的QSqlQuery实例的创建。我们并没有指定是为哪一个数据库连接创建查询对象,此时,系统会使用默认的连接,也就是使用没有第二个参数的addDatabase()函数创建的那个连接(其实就是名字为QSqlDatabase::defaultConnection的默认连接)。如果没有这么一个连接,系统就会报错。也就是说,如果没有默认连接,我们在创建QSqlQuery对象时必须指明是哪一个QSqlDatabase对象,也就是addDatabase()的返回值。

我们还可以通过使用QSqlQuery::isActive()函数检查语句执行正确与否。如果QSqlQuery对象是活动的,该函数返回 true。所谓“活动”,就是指该对象成功执行了exec()函数,但是还没有完成。如果需要设置为不活动的,可以使用finish()或者clear()函数,或者直接释放掉这个QSqlQuery对象。这里需要注意的是,如果存在一个活动的 SELECT 语句,某些数据库系统不能成功完成connect()或者rollback()函数的调用。此时,我们必须首先将活动的 SELECT 语句设置成不活动的。

创建过数据库表 student 之后,我们开始插入数据,然后将其独取出来:

C/C++

if (connect("demo.db")) {
    QSqlQuery query;
    query.prepare("INSERT INTO student (name, age) VALUES (?, ?)");
    QVariantList names;
    names << "Tom" << "Jack" << "Jane" << "Jerry";
    query.addBindValue(names);
    QVariantList ages;
    ages << 20 << 23 << 22 << 25;
    query.addBindValue(ages);
    if (!query.execBatch()) {
        QMessageBox::critical(0, QObject::tr("Database Error"),
                              query.lastError().text());
    }
    query.finish();
    query.exec("SELECT name, age FROM student");
    while (query.next()) {
        QString name = query.value(0).toString();
        int age = query.value(1).toInt();
        qDebug() << name << ": " << age;
    }
} else {
    return 1;
}

依旧连接到我们创建的 demo.db 数据库。我们需要插入多条数据,此时可以使用QSqlQuery::exec()函数一条一条插入数据,但是这里我们选择了另外一种方法:批量执行。首先,我们使用QSqlQuery::prepare()函数对这条 SQL 语句进行预处理,问号 ? 相当于占位符,预示着以后我们可以使用实际数据替换这些位置。简单说明一下,预处理是数据库提供的一种特性,它会将 SQL 语句进行编译,性能和安全性都要优于普通的 SQL 处理。在上面的代码中,我们使用一个字符串列表 names 替换掉第一个问号的位置,一个整型列表 ages 替换掉第二个问号的位置,利用QSqlQuery::addBindValue()我们将实际数据绑定到这个预处理的 SQL 语句上。需要注意的是,names 和 ages 这两个列表里面的数据需要一一对应。然后我们调用QSqlQuery::execBatch()批量执行 SQL,之后结束该对象。这样,插入操作便完成了。

另外说明一点,我们这里使用了 ODBC 风格的 ? 占位符,同样,我们也可以使用 Oracle 风格的占位符:

C/C++

query.prepare("INSERT INTO student (name, age) VALUES (:name, :age)");

此时,我们就需要使用

C/C++

query.bindValue(":name", names);
query.bindValue(":age", ages);

进行绑定。Oracle 风格的绑定最大的好处是,绑定的名字和值很清晰,与顺序无关。但是这里需要注意,bindValue()函数只能绑定一个位置。比如

C/C++

query.prepare("INSERT INTO test (name1, name2) VALUES (:name, :name)");
// ...
query.bindValue(":name", name);

只能绑定第一个 :name 占位符,不能绑定到第二个。

接下来我们依旧使用同一个查询对象执行一个 SELECT 语句。如果存在查询结果,QSqlQuery::next()会返回 true,直到到达结果最末,返回 false,说明遍历结束。我们利用这一点,使用 while 循环即可遍历查询结果。使用QSqlQuery::value()函数即可按照 SELECT 语句的字段顺序获取到对应的数据库存储的数据。

对于数据库事务的操作,我们可以使用 QSqlDatabase::transaction() 开启事务,QSqlDatabase::commit() 或者QSqlDatabase::rollback() 结束事务。使用QSqlDatabase::database()函数则可以根据名字获取所需要的数据库连接。

MFC中的sqlite操作


GitHub - Hygens/UsersRegistrationSPA: .NET Core Web + Web API + SQLite3 + AngularJS(1.7.5) + Webpack + Automations
VC++、MFC Sqlite3数据库的使用 - 付栋 - 博客园
VC连接SQLite3的方法(MFC封装类) - 无幻 - CSDN博客
How to use sqlite library in mfc aplication?
SQLite3 MFC Wrapper - CodeProject
SQLite-with-MFC-in-Chinese/MFCwithSQLiteSample at master · Jia-Hong-Peng/SQLite-with-MFC-in-Chinese
SRombauts/SQLiteCpp: SQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper.
A small example program using SQLite with C++
A small example program using SQLite with C++
Jia-Hong-Peng/sqlite: sqlite
Jia-Hong-Peng/sqlite: sqlite
sqlite/sqlite at master · Jia-Hong-Peng/sqlite
SQLite-with-MFC-in-Chinese/MFCwithSQLiteSample at master · Jia-Hong-Peng/SQLite-with-MFC-in-Chinese

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。