博客文章

mysql预处理和封装

作者: andy.      时间: 2016-11-07 20:17:13

开始准备写一个比较完美的对MySql访问封装的C++类库,类似于ADO.NET的。但是后头发现我错了~~~但是还是有些有意思的东西。总结一下。

直接谈select的预处理,因为select对应着要把查询出来的数据读出来用。如果不需要预处理的话,直接mysql_query,然后通过mysql_store_result把数据读到本地就完成了。但是如果是预处理,然后使用mysql_store_result函数的话,就会...报错。不用预处理?参数化sql语句可是防止sql注入的最好方法呢。

select参数化后,获取查询结果的步骤有点儿麻烦。在执行完mysql_stmt_execute后,需要类似于mysql_stmt_bind_param绑定输入参数一样将结果绑定,然后通过mysql_stmt_store_result将结果保存到客户端的缓冲区,再通过mysql_stmt_fetch进行遍历。

举例:

MYSQL_BIND results[3];
my_bool is_null[3];
int ID;
char name[1024];
int age;
//对results(MYSQL_BIND)进行初始化

mysql_stmt_bind_result(stmt, results);//绑定结果
mysql_stmt_store_result(stmt);//将数据缓存到客户端

while(!mysql_stmt_fetch(stmt));//这儿遍历,每次遍历会将数据存入对应的ID、name、age里面

这儿写了一个类来,封装得不太好,将就看看。头部:

#ifndef SQLHELPER_H
#define SQLHELPER_H

#include <string>
#include <QStandardItemModel>

#include <windows.h>
#include "D:/Software/mysql/include/mysql.h"

//#include <mysql/mysql.h>

using namespace std;

class SqlHelper
{
public:
    SqlHelper(string _hostName, string _userName, string _password, string _dbName);
    ~SqlHelper();
    
    int connect();
    int ExecuteNonQuery(string cmdText, MYSQL_BIND * parameters);
    int ExecuteData(string cmdText, MYSQL_BIND * parameters, MYSQL_BIND *results, QStandardItemModel **data);
    void InitBind(MYSQL_BIND *bind, enum enum_field_types field_type, char * buffer, unsigned long *length, my_bool * is_null, unsigned long buffer_length);
    
    string getErrorStr() const;
    
private:
    void initData();
    
private:
    MYSQL * connection;
    MYSQL mysql;
private:
    string errorStr;
    string hostName;
    string userName;
    string password;
    string dbName;
};

#endif // SQLHELPER_H

引用头部那儿,其实开始准备写过跨平台得,ifndef什么什么的,引用对应位置的文件,后头懒了。。。。

实现部分,主要看ExecuteData部分。

#include "sqlhelper.h"

SqlHelper::SqlHelper(string _hostName, string _userName, string _password, string _dbName)
{
    mysql_init(&mysql);
    connection = NULL;
    
    hostName = _hostName;
    userName = _userName;
    password = _password;
    dbName = _dbName;
    
    connect();
}

SqlHelper::~SqlHelper()
{
    mysql_close(connection);
}

int SqlHelper::connect()
{
    connection = mysql_real_connect(&mysql, hostName.data(), userName.data(), password.data(), dbName.data(), 0, 0, 0);
    if(connection == NULL){
        errorStr = mysql_error(&mysql);
        return -1;
    }
    else
        mysql_query(connection, "set names utf8;");
    return 1;
}

int SqlHelper::ExecuteNonQuery(string cmdText, MYSQL_BIND *parameters)
{
    MYSQL_STMT * stmt;
    int result;
    
    stmt = mysql_stmt_init(connection);
    
    if(mysql_stmt_prepare(stmt, cmdText.data(), cmdText.length()))
        goto query_error;
    
    if(parameters)
        mysql_stmt_bind_param(stmt, parameters);
        
    if(mysql_stmt_execute(stmt))
        goto query_error;
    
    mysql_stmt_store_result(stmt);
    result = mysql_affected_rows(connection);
    mysql_stmt_close(stmt);
    return result;
query_error:
    errorStr = mysql_error(&mysql);
    return -1;
}

int SqlHelper::ExecuteData(string cmdText, MYSQL_BIND *parameters, MYSQL_BIND *results, QStandardItemModel **data)
{
    MYSQL_STMT * stmt;
    MYSQL_RES * result;
    int rowCount;
    int columnCount;
    int i = 0;
    int j = 0;
    
    stmt = mysql_stmt_init(connection);
    
    if(mysql_stmt_prepare(stmt, cmdText.data(), cmdText.length()))
        goto select_error;
    
    if(parameters)
        mysql_stmt_bind_param(stmt, parameters);
    
    if(mysql_stmt_execute(stmt))
        goto select_error;
    
    result = mysql_stmt_result_metadata(stmt);
    if(!result)
        goto select_error;
    
    mysql_stmt_bind_result(stmt, results);
    mysql_stmt_store_result(stmt);
    
    rowCount = mysql_affected_rows(connection);
    columnCount = mysql_field_count(connection);
    
    *data = new QStandardItemModel(rowCount, columnCount);
    
    columnCount = 0;
    MYSQL_FIELD * field;
    while((field = mysql_fetch_field(result)) != NULL)
        (*data)->setHeaderData(columnCount++, Qt::Horizontal, field->name);
    
    i = 0;
    while(!mysql_stmt_fetch(stmt)){
        for(j = 0; j < columnCount; j++)
            if(results[j].buffer_type == MYSQL_TYPE_LONG)
                (*data)->setData((*data)->index(i, j,  QModelIndex()), QString::number(*(int * )results[j].buffer));
            else
                (*data)->setData((*data)->index(i, j,  QModelIndex()),(char * )results[j].buffer);
            i++;
    }
    mysql_free_result(result);
    mysql_stmt_close(stmt);
    
    return rowCount;
select_error:
    errorStr = mysql_error(&mysql);
    return -1;
}

void SqlHelper::InitBind(MYSQL_BIND *bind, enum_field_types field_type, char *buffer, unsigned long *length, my_bool *is_null, unsigned long buffer_length)
{
    memset(bind,0,sizeof(MYSQL_BIND));
    bind->buffer_type = field_type;
    bind->buffer = buffer;
    bind->length = length;
    bind->is_null = is_null;
    if(buffer_length!=0)
        bind[0].buffer_length = buffer_length;
}

void SqlHelper::initData()
{
    
}

string SqlHelper::getErrorStr() const
{
    return errorStr;
}

很简单的例子。最后测试部分的代码:

SqlHelper sqlHelper("192.168.1.201", "user1", "user1", "db1");

MYSQL_BIND results[3];
my_bool is_null[3];
int ID;
char name[1024];
int age;
sqlHelper.InitBind(&results[0], MYSQL_TYPE_LONG, (char *)&ID, NULL, &is_null[0], sizeof(int));
sqlHelper.InitBind(&results[1], MYSQL_TYPE_STRING, name, NULL, &is_null[1], 1024);
sqlHelper.InitBind(&results[2], MYSQL_TYPE_LONG, (char *)&age, NULL, &is_null[2], sizeof(int));

QTableView *view1 = new QTableView;
QStandardItemModel * model1;    
view1->setAttribute(Qt::WA_DeleteOnClose);
sqlHelper.ExecuteData("select * from student;", NULL,results, &model1);
view1->setModel(model1);
view1->show();

MYSQL_BIND bind;
memset(&bind,0 ,sizeof(bind));
int queryID = 1;
bind.buffer_type = MYSQL_TYPE_LONG;
bind.buffer = &queryID;
bind.buffer_length = sizeof(int);
QTableView *view2 = new QTableView;
QStandardItemModel * model2;    
view2->setAttribute(Qt::WA_DeleteOnClose);
sqlHelper.ExecuteData("select * from student where ID = ?;", &bind, results, &model2);
view2->setModel(model2);
view2->show();

直接看运行结果:

blob.png

表结构就是上一篇文章的那张表:

blob.png

完~