Se eu tiver vários leitores de banco de dados, que são basicamente instâncias do SQLite que abrem o arquivo db no modo "leitura", é normal que um único gravador que abre o db no modo "criação" não consiga liberar uma transação até que todos os leitores fechem o banco de dados?
Estou tentando descobrir se é um comportamento normal do sqlite ou um bug/limitação de uma biblioteca sqlite específica que estou usando.
Não entendo por que um escritor precisaria esperar que os leitores parassem de usar o arquivo de banco de dados. Não faz sentido para mim, porque os leitores não podem alterar os dados.
Não. Não é normal que seu redator não possa liberar uma transação até que todos os leitores saiam do banco de dados.
Isso levanta uma questão: como abrir o arquivo de banco de dados?
O mecanismo sqlite tem a capacidade de abrir o banco de dados no modo somente leitura: https://www.sqlite.org/c3ref/open.html
Os sinalizadores padrão (terceiro parâmetro), no entanto, são
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
.Se você tiver um aplicativo abrindo arquivo em normal
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE
. E vários aplicativos abrindo emSQLITE_OPEN_READONLY
modo , então o writer não deve esperar pelos leitores. Ele nem saberá sobre eles.Se puder, tente fazer suas consultas com
sqlite3
a ferramenta console. Ela tem uma--readonly
opção que realmente abrirá o arquivo de banco de dados em modo somente leitura.Entretanto, se você não estiver trabalhando em C, mas em alguma vinculação de linguagem, pode ser que o arquivo seja sempre aberto normalmente e depois alternado para o modo somente leitura no nível de vinculação.
De um ponto de vista formal, a
select
declaração pode colocar um bloqueio em um esquema de tabela, de modo que um usuário não pode fazeralter table
enquanto outro usuário está selecionando a partir dele. Mas é o único bloqueio real que o leitor pode colocar em uma tabela.O único bloqueio que ele
sqlite
faz no modo somente leitura é impedir que o arquivo do banco de dados seja excluído.Também pode ser bom ler sobre o modo de cache compartilhado: https://www.sqlite.org/sharedcache.html O que pode ser feito em alguns casos e também tem a capacidade de interferir nas transações se elas forem baseadas no mesmo cache.
Porque cada transação do SQLite — implícita ou explícita — bloqueia o arquivo de banco de dados.
Você pode testar isso executando o SQLite3 em duas sessões de terminal diferentes conectando-se ao mesmo arquivo de banco de dados SQLite. O comportamento exato depende de vários detalhes, especialmente da opção " Write-Ahead Logging " (WAL). Novamente, veja Transactions
Os escritores não "liberam" transações; eles ou fazem commit ou rollback. Se um escritor tenta fazer commit de uma instrução insert, por exemplo, e outro processo tem uma transação select aberta--ou seja, está "lendo o banco de dados"--o escritor obtém esse erro na minha máquina.
Além do que Mike disse, em relação aos seus pensamentos sobre:
Claro, mas os escritores alteram o banco de dados e, se um leitor estiver lendo dados e alterar alguns desses dados, resultados inesperados serão possíveis para os leitores.
Por exemplo, se a consulta de leitura estiver no meio da varredura de cada linha em um índice, faria sentido para um escritor que deseja atualizar um valor de chave que mudaria a posição de uma linha naquele índice ter que esperar até que o leitor termine de varrer o índice. Caso contrário, é possível que o leitor releia a mesma linha de dados duas vezes, retornando resultados imprecisos. Isso seria conhecido como uma leitura não repetível.
Outro problema que pode ocorrer é um ready sujo, em que o leitor ainda não terminou de escanear o índice, um escritor faz uma alteração em uma linha, o leitor então lê essa linha e a transação do escritor é revertida (desfeita/não confirmada), resultando em dados lidos pelo leitor que nunca foram salvos no banco de dados, causando imprecisões.
Esses exemplos muito simplificados são algumas das razões pelas quais os leitores geralmente bloqueiam escritores, além de escritores também bloquearem leitores. Há um conceito de níveis de isolamento e simultaneidade otimista que permite que escritores e leitores não bloqueiem um ao outro ao operar simultaneamente nos mesmos dados. Mas a capacidade de usar esses recursos varia na implementação de cada sistema de banco de dados, e não tenho certeza se o SQLite oferece um recurso para isso.