您的位置:首页 > 数据库 > MySQL

MySql数据库的连接和事务处理

2016-08-16 23:22 761 查看
在写聊天工具的服务端的时候,需要使用到数据库对客户端相关信息的存储,例如用户信息、用户相关的好友信息、用户所加入的群,讨论组、聊天时的离线消息,消息的历史记录等。用户在对相应的操作时候,后台数据库要进行实时的更新。本次主要描述使用QT库进行MySql数据的连接和相关的事务处理。

1. MySql数据库连接

QSqldatabase进行对数据库的连接。QT使用驱动程序与MySql的接口进行通信。

(1)Qsqldatabase类提供了addDatabase(constQString &type, const QString &connectionName = QLatin1String(defaultConnection ))函数将type类型的数据库添加到连接列表。第一个参数为所要连接的数据库类型,MySql为QMYSQL。第二个为连接数据库的名称。如果缺省该参数,该连接为默认连接。使用Qsqldatabase::database()获取该默认连接。

(2)使用setDatabaseName()、setUserName()、setPassword()和setHostName()进行数据库的相关设置。

(3)使用open()函数进行物理连接。

bool IMDatabaseCtrl::CreatConnection() {

if (m_db -> isOpen())  // 是否已经连接数据库
return true;
if (QSqlDatabase::contains("chatdb")) // 数据库连接列表中是否包含mysql
m_db = QSqlDatabase::database("chatdb");  // 连接列表存在,获取该数据库
else {
m_db = QSqlDatabase::addDatabase("QMYSQL");  //添加到数据库连接列表
if (m_db)
m_db -> setDatabaseName("chatdb");   // 设置数据库名称
}
if (m_db) {
m_db -> setUserName("root");
m_db -> setPassword("123456");
m_db -> setHostName(QLatin1String("localhost"));
if (!m_db -> open()) { // 连接是否成功
m_db -> close();
return false;
}
else
return true;
}
}

2. 事务处理

QSqlQuery进行相应的事务的处理。在事务完成后,例如select执行完毕,需要使用QsqlQuery::commit()或者QsqlQuery::rollback()结束当前事务。

QsqlQuery::commit:提交当前事务。将该事务所做的更新在数据库中持久保存。在事务被提交后,一个新的事务自动开始。

QSqlQuery::rollback():回滚当前事务。撤销该事务中所有SQL语句对数据库的更新。

(1)创建数据表

实例化QSqlQuery一个对象query,并且传入QSqldatabase的对象,此时会调用QSqlQuery::QSqlQuery(QSqlDatabasedb)构造函数,完成query的初始化,说明对象query对db所连接的数据库进行相关事务。

static const QString CREATE_TABLE_USERINFORMATION_SQL =
"create table UserInformation ("
"userID   varchar(10)"
"head     int"
"nickName varchar(20)"
"password varchar(15)"
"sex      char(4)"
"birthday varchar(20)"
"question varchar(50)"
"answer   varchar(20)"
"name     varchar(10)"
"phone    int"
"address  varchar(20)"
"regDate  varchar(20)"
"status   int"
"primary key (userID))";

static const QString CREATE_TABLE_USERFRIENDS_SQL =
"create table UserFriends ("
"userID     varchar(10)"
"friendID   varchar(10)"
"groupName  varchar(20)"
"remarkName varchar(10)"
"primary key (userID, friendID)"
"foreign key (friendID) references UserInformation) ";
bool IMDatabaseCtrl::createTable() {

if (!CreatConnection())
return false;

QSqlDatabase::database().transaction(); // 初始化事务
QSqlQuery query(*m_db);
// 创建数据表
query.exec(CREATE_TABLE_USERINFORMATION_SQL);
query.exec(CREATE_TABLE_USERFRIENDS_SQL);

QSqlDatabase::database().commit();  // 提交事务
return true;
}

(2)select查询操作

通过用户的好友ID来查询该好友的相关信息。在UserFriends表中外键为friendID,可通过该外键索引到UserInformation表中和主键userID相等的一个元组,所以SQL语句如下:

static const QString SEARCH_FRIENDS_IN_USERFRIENDS_USERINFORMATION_SQL =
"select UserFriends.friendID, UserFriends.groupName, "
"UserInformation.nickName, UserFriends.remarkName"
"UserInformation.status, UserInformation.head"
"from UserInformation, UserFriends"
"where UserFriends.friendID = ?"
"and UserInformation.userID = UserFriends.friendID;";

在SQL中采用了占位符,目的是绑定变量,这样可以减少数据SQL的硬解析,所以执行效率会提高不少。硬解析简言之即一条SQL语句没有被运行过,处于首次运行,则需要对其进行语法分析,语义识别,跟据统计信息生成最佳的执行计划,然后对其执行。

例如下一条SQL语句

select * fromUserInformation where userID = 1;
如果要对很多userID的信息进行查询,会写很多相同的SQL的语句,而且每条语句都要被数据库解析一次,这样比较浪费资源。因此将1换成占位符 ? ,无论userID后面的值如何都不要重复解析。

QSqlQuery中提供了QSqlQuery::prepare()和QSqlQuery::addBindValue()函数或者QSqlQuery::bindValue()进行变量的绑定。

有如下绑定方法:

//使用命名占位符名称绑定:
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)");
query.bindValue(":id", 1001);
query.bindValue(":forename", "Bart");
query.bindValue(":surname", "Simpson");
query.exec();

//使用命名占位符位置绑定:
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (:id, :forename, :surname)");
query.bindValue(0, 1001);
query.bindValue(1, "Bart");
query.bindValue(2, "Simpson");
query.exec();

//使用位置参数占位符位置绑定:
QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (?, ?, ?)");
query.bindValue(0, 1001);
query.bindValue(1, "Bart");
query.bindValue(2, "Simpson");
query.exec();

QSqlQuery query;
query.prepare("INSERT INTO person (id, forename, surname) "
"VALUES (?, ?, ?)");
query.addBindValue(1001);
query.addBindValue("Bart");
query.addBindValue("Simpson");
query.exec();

在查询到一个有确定元组个数的结果集中使用next进行向下索引。

a.如果结果集被定位在第一个记录之前,刚刚执行完一个查询就处于这种状态,那么可以用此函数来检索第一个记录。

b.如果结果集被定位在最后一个记录之后,那么什么都不会改变,返回FALSE。

c.如果结果集被定位在中间,此函数可以检索下一个记录。

最后将查询到的结果保存到变量。使用value返回域 i 的值。用SELECT 语句的文本,域被从左到右编号,比如:在"select forename, surname from people",域0是forename 而域1 是surname。

int IMDatabaseCtrl::searchFriendSimpleInformationByID(const QString &id,
FriendInformation &friInf)
{
if (!CreatConnection())
return GET_FRIEND_FAIL;

QSqlDatabase::database().transaction();
QSqlQuery query(*m_db);
query.prepare(SEARCH_FRIENDS_IN_USERFRIENDS_USERINFORMATION_SQL);
query.addBindValue(id);

query.exec();
QSqlDatabase::database().commit();

if (!query.isActive()) {
m_db -> close();
return GET_FRIEND_FAIL;
}

if (query.size() <= 0) {
m_db -> close();
return GET_FRIEND_FAIL;
}

if (query.isSelect()) {
if (query.next()) {
friInf.m_userID = query.value(0).toString();
friInf.m_groupName = query.value(1).toString();
friInf.m_nickname = query.value(2).toString();
friInf.m_remarkName = query.value(3).toString();
friInf.m_status = query.value(4).toInt();
friInf.m_headPortrait = query.value(5).toInt();

return GET_FRIEND_SUCCESS;
}
}

return GET_FRIEND_FAIL;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据库 MySQL QT