2015-02-17 5 views
0

У меня есть одноэлементный класс для управления доступом к базе данных из нескольких потоков. Класс должен отвечать следующим требованиям:Класс для синхронизации доступа к базе данных

  1. Операции с одновременным чтением могут выполняться одновременно, но запись должна быть эксклюзивной (другие записи или записи не записываются).
  2. Одно соединение должно использоваться повторно для нескольких запросов (внутри потока).
  3. Каждый поток должен иметь свое собственное подключение к базе данных.
  4. Интерфейс не должен раскрывать детали реализации и только разоблачить доступ к ресурсам (таким образом, клиент не знает, является ли это работа с базой данных, файлов или памяти)

Мое текущее решение использует 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]); 

Проблема здесь в том, что я не могу думать о хорошей очистке механизма, который бы избавиться соединений, которые больше не нужны, поэтому карта будет расти вместе с каждым новым потоком.

Кажется, это хорошая идея? Любые другие предложения?

+0

Кажется, что требуемая синхронизация должна быть реализована в БД, а не клиенте. Что происходит, когда у вас несколько экземпляров этого приложения? Синхронизация, которую вы строите здесь, неэффективна. –

+0

Приложение гарантировано для одного экземпляра. Также я ограничен движком sqlite. – jaho

+0

В вашем примере вы кешируете 'QString', но не соединения. Если я не против 'QSqlDatabase', это соединение, поэтому вы можете кэшировать их – borisbn

ответ

0

соединения является их подъездом имен, но вы передаете QString конструктору QSqlQuery «s и эта строка рассматриваются как SQL-запрос, но не имя соединения.

К счастью, QSqlDatabase содержит необходимый вам кеш. Он доступен для чтения QSqlDatabase::connectionNames и для записи QSqlDatabase::addDatabase

+0

Как ссылаться на соединение или где хранить кеш, на самом деле не проблема. Это время жизни соединения. Я использую свой собственный кеш или 'QSqlDatabase', я буду добавлять новые соединения с каждым потоком, не удаляя их. – jaho

Смежные вопросы