2012-03-26 31 views
5

Piszę aplikację na Androida, która komunikuje się z zapleczem PHP. Backend db to SQLite 3. Problem polega na tym, że otrzymuję ten błąd sporadycznie PHP Warning: SQLite3::prepare(): Unable to prepare statement: 5, database is locked. Otwieram połączenie z bazą danych w każdym pliku PHP i zamykam je po zakończeniu skryptu. Myślę, że problem polega na tym, że jeden skrypt zablokował plik bazy danych podczas zapisywania do niego, a drugi skrypt próbował uzyskać do niego dostęp, co nie powiodło się. Jednym ze sposobów uniknięcia tego byłoby udostępnienie połączenia między wszystkimi skryptami php. Zastanawiałem się, czy jest jakikolwiek inny sposób uniknięcia tego?Baza danych zablokowana podczas próby uzyskania dostępu ze skryptu PHP

Edit: Jest to pierwszy plik:

<?php 
$first = SQLite3::escapeString($_GET['first']); 
$last = SQLite3::escapeString($_GET['last']); 
$user = SQLite3::escapeString($_GET['user']); 
$db = new SQLite3("database.db"); 
$insert = $db->prepare('INSERT INTO users VALUES(NULL,:user,:first,:last, 0 ,datetime())'); 
$insert->bindParam(':user', $user, SQLITE3_TEXT); 
$insert->bindParam(':first', $first, SQLITE3_TEXT); 
$insert->bindParam(':last', $last, SQLITE3_TEXT); 
$insert->execute(); 
?> 

Oto drugi plik:

<?php 
$user = SQLite3::escapeString($_GET['user']); 
$db = new SQLite3("database.db"); 
$checkquery = $db->prepare('SELECT allowed FROM users WHERE username=:user'); 
$checkquery->bindParam(':user', $user, SQLITE3_TEXT); 
$results = $checkquery->execute(); 
$row = $results->fetchArray(SQLITE3_ASSOC); 
print(json_encode($row['allowed'])); 
?> 
+0

Najpierw udostępnij kod –

+0

Kod dodany i opis więcej –

Odpowiedz

13

Po pierwsze, gdy skończysz z zasobu zawsze należy go zamknąć. Teoretycznie zostanie zamknięte, gdy zostanie zbuforowane, ale nie możesz polegać na tym, że PHP robi to od razu. Widziałem kilka baz danych (i innych rodzajów bibliotek), które zostały zablokowane, ponieważ nie wydałem jawnie zasobów.

$db->close(); 
unset($db); 

Po drugie, Sqlite3 zapewnia intensywny limit czasu. Nie jestem pewien, co to jest domyślne, ale jeśli chcesz poczekać kilka sekund na usunięcie blokady po wykonaniu zapytań, możesz tak powiedzieć. Limit czasu jest w milisekundach.

$db->busyTimeout(5000); 
+0

Naprawdę zapomniałem zamknąć połączenie. Dodano to i 'busyTimeout'. Teraz działa dobrze. Dzięki! –

+3

Mimo to mogą wystąpić problemy. Jeśli uzyskasz dostęp do tego samego pliku DB ze skryptu, gdy jest on nadal otwarty z innego skryptu (Ex: Ajax), to będziesz miał ten sam problem. – Alex

+0

Domyślna wartość to 60 sekund == 60000 milisekund. Jak 5000 zrobi coś pożytecznego? – TechJS

1

byłem coraz „baza danych zablokowana” przez cały czas, aż znalazłem pewne cechy sqlite3 należy ustawić za pomocą SQL specjalne instrukcje (czyli używając PRAGMA słowa kluczowego). Na przykład, co najwyraźniej rozwiązało mój problem z "bazą danych zablokowaną" było ustawienie parametru dziennik_dokumentu na "wal" (domyślnie jest to "usuń", jak podano tutaj: https://www.sqlite.org/wal.html (patrz Aktywacja i konfiguracja trybu WAL)).

Zasadniczo musiałem utworzyć połączenie z bazą danych i ustawić tryb dziennik z instrukcją SQL. Przykład:

<?php 
    $db = new SQLite3('/my/sqlite/file.sqlite3'); 
    $db->busyTimeout(5000); 
    // WAL mode has better control over concurrency. 
    // Source: https://www.sqlite.org/wal.html 
    $db->exec('PRAGMA journal_mode = wal;'); 
?> 

Nadzieję, że pomaga.

Powiązane problemy