我之前写代码的时候,网上收集资料的时候,发现qt连接数据库编程有两种方式,一种是qt下自己的库文件,还有一种是自己写,就是自己是自己的基类。

  我采用的是第二种,就是自己写类

步骤:QT里面调用数据库的库文件,这个是设置路径window下的数据库是:



找到安装路径下的库文件,然后添加路径进来就可以了

在这个里面添加路径,加上这个命令就可以了。linux下则添加:


LIBS += -lmysqlclient


这个主要看编译环境,linux和window的编译可以理解成,和系统没有关系,是qt库的问题,比如qt4的工程用qt5来编译也有少量这种情况,人家有可能为了规范更改了文件名,也有可能为了扩展增加了某些文件,你在不同的系统或者不同的版本,说白了就是不同的安装包安装的qt有可能缺少或者增加某些文件。主要是库文件的调用问题。

 

 

我们要建立一个mymysql的基类

然后再mymysql里面添加


#include <windows.h> #include <C:/mysql/include/mysql.h>


这个是window的头文件,还有这两个顺序不能错,否则编译不能通过。


 


linux下使用mysql.h的方法 #include <mysql/mysql.h>


这个是linux定义头文件的方法,采用相对路径

 

int mymysql::sql_connect(const char *Hostname, const char *User, const char *Password, const char *DBName)
{
    connection = mysql_real_connect(&mysql, Hostname, User, Password, DBName, 0, 0,0);
    if (connection == NULL)
    {
        memset(buf, 0, sizeof(buf));
        strcpy(buf, mysql_error(&mysql));
        //QMessageBox::information(0, "", mysql_error(&mysql));
        return -1;
    }else
    {
        mysql_query(connection, "set names utf8");
        return 0;
    }

}

mysql_real_connect()
此函数尝试与运行在主机上的MySQL数据库引擎建立连接。 此函数成功完成之后,才能使用mysql的其他函数。 
函数原型: 
MYSQL *mysql_real_connect(MYSQL *mysql, const cahr *host, const cahr *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag) 
参数解释: 
mysql: 已有mysql结构的地址 
host: 主机名或者地址 
user:用户的MYSQL登陆ID 
passwd:用户的密码 
db:数据库的名称 
port:如果port不是0,其值将用作TCP/IP连接的端口号 
unix_socket:如果次参数不为空,该字符串描述了应使用的套接字或命名管道 
client_flag:通常为0

 

set names utf8指定了客户端和服务器之间传递字符的编码规则为UTF8。 这个必须要加,要不然可能会出现乱码和接受不到数据的现象。

 


mysql_error(&mysql)这个函数是打印乱码的信息,打个比方,我们登入数据库的时候,输出密码,就会返回错误信息(会指明哪里出错)


 

void mymysql::sql_disconnet()
{
    if (connection)
    {
        mysql_close(connection);
        connection = NULL;
    }
}

这个我们在注销登入的时候,就用这个函数,我们设置的注销登入的槽函数里面就放人这个函数就可以了。

int mymysql::sql_exec(const char *SQL)
{
    if (mysql_query(connection, SQL) != 0)
    {
        memset(buf, 0, sizeof(buf));
        strcpy(buf, mysql_error(&mysql));
        return -1;
    }
    return 0;
}

int mymysql::sql_open(const char *SQL, QStandardItemModel **p)
{
    if (mysql_query(connection, SQL) != 0)
    {
        memset(buf, 0, sizeof(buf));
        strcpy(buf, mysql_error(&mysql));
        return -1;
    }

    MYSQL_RES *result = mysql_store_result(connection);
    if (result == NULL)//没有查询结果
    {
        memset(buf, 0, sizeof(buf));
        strcpy(buf, mysql_error(&mysql));
        return -1;
    }

    int rowcount = mysql_affected_rows(connection);//这个函数返回SQL语句执行后又多少行
    int fieldcount = mysql_field_count(connection);//这个函数返回SQL语句执行后有多少列

    *p = new QStandardItemModel(rowcount, fieldcount);//根据SQL语句返回的行列总数,动态的建一个modul出来.
    MYSQL_FIELD *field;

    int i = 0;
    int j = 0;
    for(i = 0;i<fieldcount;i++)
    {
        field = mysql_fetch_field(result);
        (*p)->setHeaderData(i, Qt::Horizontal, field->name);
    }


    for(i = 0;i<rowcount;i++)//循环遍历每一行
    {
        MYSQL_ROW row = mysql_fetch_row(result);
        for(j = 0;j<fieldcount;j++)//循环遍历一行当中所有的列
        {
            (*p)->setData((*p)->index(i, j, QModelIndex()), row[j]);
        }
    }


    mysql_free_result(result);//释放通过mysql_store_result函数分配的内存空间
    return 0;
}

这里用的的函数是mysql_query,mysql_query()如果里面放的是查询之类的语句,那返回的是资源,说白了就是你要查的数据结果集;如果里面放的是增删改之类的语句,那返回的是true或者false了。所以下面要加判断函数。

void MainWindow::script_msg(const char *SQL)
{
    int res = 0;
    if ((strncmp(SQL, "SELECT", 6) == 0) || (strncmp(SQL, "select", 6) == 0))
    {
        QStandardItemModel *modul = NULL;
        res = db.sql_open(SQL, &modul);//如果是SELECT,那么执行sql_open这个函数

        QTableView *view1 = new QTableView;
        view1->setAttribute(Qt::WA_DeleteOnClose);//view在close的时候自动会delete,这个时候如果view有modul的话,这个modul会被view自动释放。
        mdiArea->addSubWindow(view1);
        view1->setStyleSheet("border-image: url(3.jpg);");//设置widget背景图片

        //view1继承自widget,如果没有modul,那么view不会显示任何数据.
        view1->setModel(modul);
        view1->show();
        mdiArea->activeSubWindow()->resize(width() - 100, height() - 100);


    }else
    {
        res = db.sql_exec(SQL);//如果用户执行的是非SELECT。那么执行sql_exec函数
    }

    if (res == -1)
    {
        QMessageBox::information(this, "执行失败", db.geterror());
    }else
    {
        QMessageBox::information(this, "提示", "执行成功");
    }
}

这里要区分select,查询操作的数据要给model----->>>view显示。

 

在里面有一个小技巧,就是数据库的数据怎么给model了,因为是两个不同的类,类与类传输数据的时候,一般是单向的,我们而且很少尽可能不去用友原,所以这里用来指针来传输数据。我们建立一个动态的view,应该怎么样去建立了,因为必须要有一个动态的model才行,可以找查找命令得到多少行和列:

 int rowcount = mysql_affected_rows(connection);//这个函数返回SQL语句执行后又多少行

  int fieldcount = mysql_field_count(connection);//这个函数返回SQL语句执行后有多少列

这样我们就可以用来个for循环嵌套一下就可以了,遍历所有的数据,然后数据在传给model。


(*p)->setData((*p)->index(i, j, QModelIndex()), row[j]);


这一条i,j代表行和列,然后填充数据。model和view之间传输要建立索引机制