У меня есть одноэлементный класс для управления доступом к базе данных из нескольких потоков. Класс должен отвечать следующим требованиям:Класс для синхронизации доступа к базе данных
- Операции с одновременным чтением могут выполняться одновременно, но запись должна быть эксклюзивной (другие записи или записи не записываются).
- Одно соединение должно использоваться повторно для нескольких запросов (внутри потока).
- Каждый поток должен иметь свое собственное подключение к базе данных.
- Интерфейс не должен раскрывать детали реализации и только разоблачить доступ к ресурсам (таким образом, клиент не знает, является ли это работа с базой данных, файлов или памяти)
Мое текущее решение использует QReadWriteLock
, который заботится о синхронизации , однако все потоки используют одно соединение с базой данных, что небезопасно. Ниже приведен упрощенный вариант.
class ResourceManager
{
public:
bool initialize(const QString& databasePath);
bool shutdown();
static ResourceManager& get()
{
static ResourceManager instance;
return instance;
}
QByteArray getResource(int resourceId)
{
QReadLocker locker(m_lock);
QSqlQuery query(m_db);
// ...
}
bool setResource(int resourceId, QByteArray data)
{
QWriteLocker locker(m_lock);
QSqlQuery query(m_db)
// ...
}
private:
QSqlDatabase m_db;
QReadWriteLock m_lock;
}
Моя идея заключается в том, чтобы реализовать какой-то кэш соединений, как следующее:
QHash<ThreadHandle, QString> m_connectionCache; // thread handle - connection name
// then
if (!m_connectionCache[QThread::currentThread]) // Create new connection
QSqlQuery query(m_connectionCache[QThread::currentThread]);
Проблема здесь в том, что я не могу думать о хорошей очистке механизма, который бы избавиться соединений, которые больше не нужны, поэтому карта будет расти вместе с каждым новым потоком.
Кажется, это хорошая идея? Любые другие предложения?
Кажется, что требуемая синхронизация должна быть реализована в БД, а не клиенте. Что происходит, когда у вас несколько экземпляров этого приложения? Синхронизация, которую вы строите здесь, неэффективна. –
Приложение гарантировано для одного экземпляра. Также я ограничен движком sqlite. – jaho
В вашем примере вы кешируете 'QString', но не соединения. Если я не против 'QSqlDatabase', это соединение, поэтому вы можете кэшировать их – borisbn