Проблема с добавлением данных в SQLite

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 16.04.2014 18:57:15

Здравствуйте!
Следующая проблема возникла.
Кратко: После закрытия программы, работающей с БД - модификации БД не сохраняются. Гуглил усердно, возможно, не там. Но гуглил!)

Подробно:
Начал знакомство с SQLite, установил всё, как в вики написано. Изначально тыкался в компонент TSQLite3DataSet, затем понял, что в нем не реализовать нормальный SQL (в нем SQL запросы выполнялись лишь после перезапуска программы, не нашёл выхода, возможно, я туп :( ). Решил попробовать с TSQLite3Connection в связки с TSQLQuery. Базу данных создал через SQlite Manager (доп. к огнеЛису, все остальные админки показалось кривым или просто толком не работали, а эта - прелесть).

Вот структура единственной таблицы:
Код: Выделить всё
CREATE TABLE "users" ("id" INTEGER PRIMARY KEY  NOT NULL ,"id_us" CHAR NOT NULL  DEFAULT (null) ,"FirName" CHAR NOT NULL  DEFAULT (null) ,"PatName" CHAR DEFAULT (null) ,"SurName" CHAR NOT NULL  DEFAULT (null) ,"NickName" CHAR DEFAULT (null) );


Вот INSERT запрос:
Код: Выделить всё
     
      SQLQuery.Close;
      SQLQuery.SQL.Clear; //со времён дельфи привычка закрывать и очищать
      SQLQuery.SQL.Text:='INSERT INTO users (ID_us,FirName,PatName,SurName,NickName ) VALUES("23342777", "Ivan","Ivanovich", "IVanov", "Vanya")';
      SQLQuery.ExecSQL;
      SQLQuery.SQL.text:='SELECT * FROM users'; // без возобновления селектА - Квери не хочет активироваться, а без активации не вызвать ApplyUpdates
      SQLQuery.Active:=true;
      SQLQuery.ApplyUpdates; // Гугл говорит, что именно эта команда должна записать данные из кеша в файл БД
   


В итоге - ДБГрид, связанный с Квери всё выводит, но после перезапуска в базе ничего нет и сам файл БД, судя по времени изменения, не трогается.

Прошу подсказать выход и не пинать, если ответ очевиден, бился долго..
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение hinst » 16.04.2014 19:07:23

Попробуйте метод Commit вместо ApplyUpdates
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 16.04.2014 19:12:26

hinst Пробовал, попробовал ещё (а вдруг?=Р). Вызывает класс исключения "EDatabaseError" с сообщением "database is locked".

зы: само собой SQLTransaction.Commit, а не у Квери, ибо у Квери такого и нет)
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение hinst » 16.04.2014 19:17:23

Ну так значит надо разблокировать базу. Перезапустить сервер, например

Добавлено спустя 3 минуты 4 секунды:
Я вообще с sqldb работаю так:
Код: Выделить всё
transaction := TSQLTransaction.Create(nil);
transaction.DataBase := connection;
connection.ExecuteDirect('insert ... ...');
transaction.Commit;
transaction.Free;

Вот так вот у меня делается. И работает. Без Query. Должно по идее работать и для SQLite
Аватара пользователя
hinst
энтузиаст
 
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 16.04.2014 19:29:15

hinst, ваш метод даже во время работы программы не выдал результата :(

Про перезапустить сервер не совсем понял, как это сделать в случае с SQLite?
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение sign » 17.04.2014 06:21:37

Бросайте свой лайт и переходите на MySQL.
И к нему есть замечательная бесплатная студия - dbForge Studio.
sign
энтузиаст
 
Сообщения: 1131
Зарегистрирован: 30.08.2009 09:20:53

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 17.04.2014 07:37:30

sign, тут уже дело принципа было. Хотелось уж очень разобраться. К тому же, лайт вроде как тоже популярен и много где пользуется до сих пор.

Кажется разобрался. По крайней мере нашёл работающий метод :)
Работает вот так:
Код: Выделить всё
      SQLQuery.Close;
      SQLQuery.SQL.Clear;
      SQLQuery.SQL.Text:='INSERT INTO users (ID_us,FirName,PatName,SurName,NickName ) VALUES("23342777", "Иван9911","Иванович", "Иванов", "Ванька")';
      SQLQuery.ExecSQL;
      SQLTransaction.CommitRetaining;   

При этом, в SQLTransaction должно быть Action:=caCommit. Если вылазит "database is locked" - переактивируем SQLTransaction, т.е. Active в false, затем обратно в true (только её, после переактивации выключится и Квери, если его включить - снова ловим ошибку).
Так всё работает и сохраняется. По крайней мере пока. Ура-ура! :D
Вдохновился написанным вот здесь.

Добавлено спустя 5 минут 15 секунд:
С просто "SQLTransaction.Commit" так же работает.
По сути, товарищ hinst был прав и с перезапуском и с Коммитом, только до меня не сразу дошло, как это реализовать. У меня там ещё селекты были лишними и т.д. В данном методе активировать ничего не надо и поэтому на отсутствие выборки оно не ругается.
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение Vadim » 17.04.2014 09:56:43

Leonius_Bad
Для вставки, изменения, удаления записей использовать SQLQuery необязательно. Специально для таких команд у TSQLite3Connection есть метод ExecuteDirect(). Компонентом Transaction можно не пользоваться. В качестве примера:
Код: Выделить всё
query:='INSERT INTO users (ID_us,FirName,PatName,SurName,NickName ) VALUES("23342777", "Иван9911","Иванович", "Иванов", "Ванька")';
SQLite3Connection.ExecuteDirect('BEGIN TRANSACTION');
SQLite3Connection.ExecuteDirect(query);
//А теперь - ВНИМАНИЕ: этим же методом запоминаем изменения :-)
SQLite3Connection.ExecuteDirect('COMMIT TRANSACTION');
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 17.04.2014 15:16:25

Vadim
Спасибо большое, учту:)

У меня вот еще вопрос по транзакциям возник. В моем случае (когда с квери и тд, код из пред.сообщения), где начало транзакции? Конец понятно - коммит. А начало?
И еще: в чем таки разница Commit и CommitRetaining? Гугл утверждает, что просто Коммит - завершение транзакции и запись данных, второе же - просто запись данных, но открытая транзакция продолжается. Так ли оно?
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение Vadim » 17.04.2014 18:41:17

Leonius_Bad писал(а):где начало транзакции?

В Вашем случае транзакция начинается автоматически. За операциями следит компонент Transaction, а вот завершать транзакцию лучше вручную (точнее говоря - явным образом в коде), т.к. надо предварительно проверить, что все компоненты транзакции выполнили то, что от них ожидалось. Для примера - стандартная банковская транзакция перевода денег с одного счёта на другой:
1. Проверить, есть счёт источник;
2. Проверить, есть ли на счёте-источнике нужная сумма;
3. Проверить, есть ли счёт-получатель;
4. Списать со счёта источника нужную сумму;
5. Зачислить на счёт-получатель нужную сумму.
Только при выполнении всех 5 пунктов транзакция считается завершённой.
Leonius_Bad писал(а): в чем таки разница Commit и CommitRetaining?

Commit - завершает транзакцию совсем, а CommitRetaining не совсем. :-) К примеру, если существовал курсор в БД, то Commit закроет и его, CommitRetaining нет.
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 19.04.2014 08:27:34

Vadim, вроде понял. Во всяком случае пока))

Возникла еще одна похожая проблема. А именно очередное не сохранение. На этот раз параметров к Квери (пока пользую таки его, раз уж начал). Пока проект в Лазарусе открыт - всё ок, стоит закрыть - все аккуратно прописанные в свойстве params значения исчезают. Задам программно при запуске, но всё же - в чём беда?
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение Vadim » 21.04.2014 06:20:38

А куда и как именно Вы заносите параметры запроса? Не сохраняются сами параметры или значения, которые Вы присваиваете этим параметрам?
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 22.04.2014 12:50:41

Vadim в инспекторе объектов свойство Params. Не сохраняются сами параметры (при перезапуске Лазаруса значение сбрасывается в ноль). Решил соответствующим кодом при старте программы.
Код: Выделить всё
   SQLQuery.Params.CreateParam(ftString, 'idus', ptUnknown);
   SQLQuery.Params.CreateParam(ftString, 'FName', ptUnknown);
//и так далее


Вот какой еще вопрос волнует и куда больше волнует, нежели не сохраняющиеся параметры.
Мне по заданию необходимо, чтобы несколько экземпляров программы имело доступ к одной БД. Для этих целей и была посоветована SQLite вместо привычных мне dbf-ок. Но вот засада. Сейчас вроде всё работает, всё прелестно, но вот эта самая мультиПользовательность не работает вообще.

Описываю ситуацию. Если выполняется INSERT в одном экземпляре программы, только один INSERT, после него ничего - всё работает. Этот же инсерт может выполняться хоть из 20 других экземпляров приложения в ту же самую базу данных - всё прекрасно.
Делаю таки вот так:
Код: Выделить всё
SQLQuery.Close;
      SQLQuery.SQL.Clear;
      SQLQuery.SQL.Text:='INSERT INTO users (ID_us,FirName,PatName,SurName,NickName ) VALUES(:idus, :FName,:PName, :SName, :NName)';
        if not SQLQuery.Prepared then
        SQLQuery.Prepare;
      SQLQuery.ParamByName('idus').AsString:=s;
      SQLQuery.ParamByName('FName').AsString:=Edit2.text; SQLQuery.ParamByName('PName').AsString:=Edit3.text;
      SQLQuery.ParamByName('SName').AsString:=Edit1.text; SQLQuery.ParamByName('NName').AsString:=Edit4.text;

      SQLQuery.ExecSQL;
      SQLTransaction.Commit;

Способ с SQLite3Connection.ExecuteDirect, описанный выше освоить не получилось, там какие-то странные вещи с параметрами (нельзя обратится к ним по имени и тд), не понял, как с ними работать + транзакция не хотела начинаться :( . Если совсем прижмет - еще попробую.. Но пока по старинке - с квери.
Дык вот, вышеописанный код, как уже сказал, работает прекрасно из кучи приложений, но если после него добавить SELECT, например стандартный:
Код: Выделить всё
    SQLQuery.Close;
      SQLQuery.SQL.Clear;
      SQLQuery.SQL.Text:='SELECT * from tests';
      SQLQuery.Open;
      SQLQuery.close; 

То всё, пиши "пропало". После попытки второго (и всех последующих, конечно) экземпляра приложения ИНСЕРТнуть что-нибудь - вылетает database is locked. Что я уже только не пробовал после этого СЕЛЕКТа, перезакрывал все транзакции, квери и Конекшены, закрывал все датаСеты. Ничего не помогает...
Как же разблочить БД после СЕЛЕКтов? (они мне нужны, ибо в БД не только вставляются новые записи). Я уже начитался того, что SQLite изначально полностью однопользовательская, но одновременно писатьчитать таки как-то можно.. Но разобраться в том, как - гугл не помог.

Добавлено спустя 42 минуты 29 секунд:
Метод тыка хоть и долгий, но очень часто таки даёт плоды.
В итоге, после того, как выборка выполненного SELECT уже не нужна, пишем
Код: Выделить всё
SQLQuery.ExecSQL;
SQLTransaction.Commit;

И у-аля! Всё работает.
Почти наверняка способ косой и через одно место, но работает же%)) По крайней мере пока. Если кто знает более разумное решение для обеспечения многопользовательности - ОЧЕНЬ прошу отписать сюда :)

Надеюсь, что и мои изыскания кому-нибудь когда-нибудь да помогут :D
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07

Re: Проблема с добавлением данных в SQLite

Сообщение vada » 22.04.2014 14:57:30

А почему вы не пользуетесь SQLTransaction.Begin или у SQLite нет начала транзакции? С этой СУБД не работал, но существует правило что сначала надо открыть транзакцию, потом комитель или откатиться в случае ошибки.
Что-то типа такого порядка:
Код: Выделить всё
BeginTransaction
{Select|Update|Insert|Delete}
{Commit|Rolback}

Или в SQLite не так?
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17

Re: Проблема с добавлением данных в SQLite

Сообщение Leonius_Bad » 23.04.2014 12:19:36

vada выше писали:
Vadim писал(а):В Вашем случае транзакция начинается автоматически. За операциями следит компонент Transaction
Leonius_Bad
новенький
 
Сообщения: 51
Зарегистрирован: 29.11.2012 19:18:07


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 90

Рейтинг@Mail.ru