1. 目标
我们使用sqlite3来存储歌曲、播放列表等信息,实现以下功能:
-
连接数据库
-
增删改查
-
事务
2. 实现
创建一个database模块,包含Database类:
// database.pri
QT += sql
HEADERS += \
$$PWD/database.h
SOURCES += \
$$PWD/database.cpp
2.1 连接数据库
sqlite需要传入db文件的路径:
// database.h
class Database {
public:
Database();
virtual ~Database();
bool init(const QString &path);
private:
std::unique_ptr<QMutex> m_mutex;
QString m_name = "";
};
// database.cpp
bool Database::init(const QString& path) {
QMutexLocker locker(m_mutex.get());
if (!m_name.isEmpty()) {
qWarning() << "database initialized";
return true;
}
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName(path);
db.open();
if (db.isOpen()) m_name = path;
return db.isOpen();
}
2.2 增删改查
本质上还是通过执行sql语句,实现数据的增删改查,Qt将sql操作的功能封装成了QSqlQuery类,QSqlQuery可以直接执行sql语句,如:
QVariantList Database::getPlaylist() {
QSqlQuery query(QSqlDatabase::database(m_name));
QString sql = "SELECT * FROM playlist where name=\"test\"";
if (!query.exec(sql)) {
qCritical() << query.lastError();
return QVariantList();
}
...
}
另外QSqlQuery也支持占位符形式的语句(Oracle样式的 :columnName和ODBC样式的?):
QVariantList Database::getPlaylist() {
QSqlQuery query(QSqlDatabase::database(m_name));
query.prepare("SELECT * FROM playlist where name=:name");
query.bindValue(":name", "test");
if (!query.exec()) {
qCritical() << query.lastError();
return QVariantList();
}
...
}
2.3 事务
QtSqlDatabase也支持事务操作,在批量处理sql语句操作时,保持了数据的一致性和完整性,流程如下:
代码如下:
bool Database::addSongList(const QVariantList &list) {
if (!m_db.transaction()) {
qCritical() << "transaction failed: " << m_db.lastError().text();
return false;
}
QSqlQuery query(QSqlDatabase::database(m_name));
for (auto &item : list) {
QVariantMap map = item.toMap();
query.prepare(
"INSERT INTO song (id, path) VALUES (:id, :path)");
query.bindValue(":id", QUuid::createUuid().toString(QUuid::Id128));
query.bindValue(":path", map["path"].toString());
query.exec();
}
if (!m_db.commit()) {
qCritical() << "commit failed: " << m_db.lastError().text();
if (!m_db.rollback()) qCritical() << "rollback failed: " << m_db.lastError().text();
return false;
}
return true;
}
PS: 代码已经开源在github:linqiaqun/music-player: A cross platform music player (github.com) 欢迎star/fork/issue