Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Обсуждение уроков
Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение damager82 » 01 дек 2011, 03:00

В этом уроке:

- используем транзакции при работе с БД

Click here to read this article!
Последний раз редактировалось damager82 01 май 2017, 16:41, всего редактировалось 12 раз.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

eugene78
Сообщения: 1
Зарегистрирован: 10 май 2012, 07:57

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение eugene78 » 10 май 2012, 08:09

Спасибо за статью, пригодилась.
Вот еще в тему http://www.enterra.ru/blog/android_issues_with_sqlite/, тоже кое-что полезного взять можно.

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение damager82 » 10 май 2012, 09:49

eugene78 писал(а):Спасибо за статью, пригодилась.
Вот еще в тему http://www.enterra.ru/blog/android_issues_with_sqlite/, тоже кое-что полезного взять можно.
Спасибо, хороший материал! Добавлю ссылку в урок.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

icamys
Сообщения: 22
Зарегистрирован: 07 май 2012, 00:32

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение icamys » 18 май 2012, 22:35

Спасибо большое! Отличный урок.

alex6999
Сообщения: 13
Зарегистрирован: 29 май 2012, 18:50

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение alex6999 » 04 июн 2012, 10:44

Это очень важно! Т.е. если вы открыли транзакцию, выполнили какие-либо действия и не закрыли транзакцию, то все операции будут считаться успешными и изменения будут внесены в БД. Поэтому закрытие транзакции необходимо выполнять и finally нам это гарантирует.
тут вроде надо
Это очень важно! Т.е. если вы открыли транзакцию, выполнили какие-либо действия и не закрыли транзакцию, то все операции будут считаться неуспешными и изменения не будут внесены в БД. Поэтому закрытие транзакции необходимо выполнять и finally нам это гарантирует.

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение damager82 » 04 июн 2012, 11:20

alex6999 писал(а): тут вроде надо
Это очень важно! Т.е. если вы открыли транзакцию, выполнили какие-либо действия и не закрыли транзакцию, то все операции будут считаться неуспешными и изменения не будут внесены в БД. Поэтому закрытие транзакции необходимо выполнять и finally нам это гарантирует.
Да, чето я фигню написал какую-то ... Спасибо за наблюдательность! Пофиксил
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

Аватара пользователя
d79
Сообщения: 2
Зарегистрирован: 30 авг 2012, 15:29

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение d79 » 30 авг 2012, 15:46

void myActions() {
db = dbh.getWritableDatabase();
delete(db, "mytable");
db.beginTransaction();
insert(db, "mytable", "val1");
db.setTransactionSuccessful();
insert(db, "mytable", "val2");
db.endTransaction();
insert(db, "mytable", "val3");
read(db, "mytable");
dbh.close();
}
Обратите внимание - несмотря на то, что val2 мы вставляли уже после подтверждения успешности транзакции, запись вставилась, вошла в эту транзакцию.
Получается, расположение метода setTransactionSuccessful() может быть любым между открытием и закрытием транзакции?

Аватара пользователя
damager82
Администратор
Сообщения: 1383
Зарегистрирован: 07 янв 2012, 11:32
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение damager82 » 05 сен 2012, 09:37

d79 писал(а):Получается, расположение метода setTransactionSuccessful() может быть любым между открытием и закрытием транзакции?
Получается так. Но, походу, это не приветствуется, т.к. в хелпе есть такой текст: "Do not do any more database work between calling this and calling endTransaction."

Пожалуй, надо мне отметить это в уроке.
Добро пожаловать на форум сайта StartAndroid
ИзображениеИзображение

SoLVeX
Сообщения: 15
Зарегистрирован: 21 фев 2012, 19:11
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение SoLVeX » 03 фев 2013, 17:39

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

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение Prospekt » 07 мар 2013, 08:45

Интересен такой момент: а что если делать SQLiteOpenHelper синглетоном?
Вроде работает нормально, и можно методы доступа синхронизировать. Вопрос только в том, надо ли закрывать SQLiteOpenHelper?
После каждого обращения делать закрытие накладно, но если никогда не закрывать (...close()), то что будет при убивании всех экземпляров активити, работающих с этим Хелпером?
Я так понимаю, что умная система должна сама убить (закрыть) Хелпер, как она закрывает например все in\outStream при выходе. Или же статический объект будет висеть вечно? Как вариант, можно запоминать время последнего обращения к хелперу, и если оно больше скажем 5 минут, то хелпер уничтожается. И при запросе воссаздается заново.

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение neoksi » 07 мар 2013, 08:54

Prospekt писал(а):Интересен такой момент: а что если делать SQLiteOpenHelper синглетоном?
Вроде работает нормально, и можно методы доступа синхронизировать. Вопрос только в том, надо ли закрывать SQLiteOpenHelper?
После каждого обращения делать закрытие накладно, но если никогда не закрывать (...close()), то что будет при убивании всех экземпляров активити, работающих с этим Хелпером?
Я так понимаю, что умная система должна сама убить (закрыть) Хелпер, как она закрывает например все in\outStream при выходе. Или же статический объект будет висеть вечно? Как вариант, можно запоминать время последнего обращения к хелперу, и если оно больше скажем 5 минут, то хелпер уничтожается. И при запросе воссаздается заново.
Это будет велосипедом, для этого есть СontentProvider, который является синглтоном и все это берет на себя.

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение Prospekt » 07 мар 2013, 09:21

Гы,
У многих есть неравнодущее к некоторым аспектам программирования, некоторые видят все мировое зло в несоблюдении правил отступа, некоторые считают мастерское владение дебагером сутью программирования, а товарищ neoksi помещан на КонтентПровайдерах. Прямо через пост.

За ответ спасибо, но как-то это не то.
КП определенно хороши, но хочется вариант поминиатюрней. Хотя определенно большая часть правда в вашем посте содержится. Как я понимаю, Вы предлагаете все обращения к БД делать исключительно через КП?
И всеже если взяться за ответку и прикрутить 2 колеса. Ну хотя бы как вариант.

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение neoksi » 07 мар 2013, 09:27

damager82 писал(а):
d79 писал(а):Получается, расположение метода setTransactionSuccessful() может быть любым между открытием и закрытием транзакции?
Получается так. Но, походу, это не приветствуется, т.к. в хелпе есть такой текст: "Do not do any more database work between calling this and calling endTransaction."

Пожалуй, надо мне отметить это в уроке.
Тут нужно учесть, что SQLite однопоточная БД и очередность запросов отдана на откуп программистам пишущим приложения.

1) Метод beginTransaction() отправляет в движок SQL команду скапливать запросы и не обрабатывать их;
2) Метод setTransactionSuccessful() отправляет в движок SQL команду, что блок запросов завершен;
3) Метод endTransaction() отправляет в движок SQL команду, распарсить и обработать запросы, которые были указанны в блоке транзаксации.

Если между 2 и 3 методом отправить ещё н-ное кол-во запросов, то они будут немедленно обработаны и запишутся в файл БД до обработки блока транзаксации. Но может возникнуть ситуация, когда этими запросами будет блокирован на запись файл БД, к которому затребует доступ блок транзаксации, что в свою очередь приведет к возникновению исключения доступа к файлу.

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение Prospekt » 07 мар 2013, 09:38

Я понимаю это, но ведь такие ограничения остаются и для ContentProvider-ов. Большинство примеров БД - это маленькие базы с одной таблицей, с мелкими методами getItem() getAll() insertItem() updateItem() deleteItem() и эти методы можно сделать синхронизированными виду малости исполняемого кода. (Не повлияет на скорость).
Согласитесь, что во множестве случаев легче иметь простенький вариант решения, а городить 3-4 таблицы, связанных между собой - это редкость. Пока встречал варианты только простых БД.

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение neoksi » 07 мар 2013, 09:40

Prospekt писал(а):Гы,
У многих есть неравнодущее к некоторым аспектам программирования, некоторые видят все мировое зло в несоблюдении правил отступа, некоторые считают мастерское владение дебагером сутью программирования, а товарищ neoksi помещан на КонтентПровайдерах. Прямо через пост.

За ответ спасибо, но как-то это не то.
КП определенно хороши, но хочется вариант поминиатюрней. Хотя определенно большая часть правда в вашем посте содержится. Как я понимаю, Вы предлагаете все обращения к БД делать исключительно через КП?
И всеже если взяться за ответку и прикрутить 2 колеса. Ну хотя бы как вариант.
Prospekt
Программируя на другом языке и работая с SQLite, я уже сталкивался с проблемой разграничения доступа к однопоточной БД из разных потоков программы, и честно, это была ещё та головомойка. Тут же, разработчики Андроида предусмотрели механизм, который все делает за нас, да, для понимания начального он сложен. Плюс КП дает свои плюшки, к примеру автоматическое обновление данных в отображаемых элементах при изменении их в БД. Я призываю его использовать, так как в конечном итоге он упрощает жизнь и не надо будет искать, где же и почему вдруг возникло исключение, когда два потока приложения одновременно решили поработать с БД.

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение Prospekt » 07 мар 2013, 10:01

По всей видимости есть необходимость в уроке "ContentProvider vs других вариантов" при работе с БД.
Какие плюсы он дает? Да комбинация ContentProvider и BroadCastResiever позволяют автоматически обнавлять данные в приложении и даже в GUI.
Согласитесь, что во множестве случаев легче иметь простенький вариант решения, а городить 3-4 таблицы, связанных между собой - это редкость. Пока встречал варианты только простых БД.
Возможно в сложных случаях это действительно головомойка, но в большинстве случаев БД в Android - это всего лишь прокладка между программой и жестким диском (или какой он там). Прогеров ломает самим считывать данные с диска и сохранять их там, поэтому используются минимум из функционала БД. Сложности возникают при полноценном юзаньи БД, как например программы на серверном оборудовании, а тут -то где можно черту ногу поломать в 3-х соснах. Я вроде не глупый, но представить ситуацию такую не могу для Android-а. Поделитесь плиз, для моего собственного развития.

Аватара пользователя
neoksi
Сообщения: 712
Зарегистрирован: 26 июл 2012, 10:42
Контактная информация:

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение neoksi » 07 мар 2013, 10:23

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

Возьмем абстрактный пример:
Есть программа будильник, которая хранит назначенные будильники в БД (это одна таблица) и ими можно управлять из активити. Но у нас программа с супер мега функцией, если послать на телефон смс в определенном формате, то она может активировать или дезактировать будильник на определенный день (реализуется через БроадкастРесивер).
И так наступает час Х, когда наш пользователь открыл активити и работает с настройкой будильника на субботу, а в тот же момент ему приходит супер смс от жены с требованием отключить будильник на субботу. Без КП, я даже не хочу гадать, какая ошибка может выскочить, при одновременном сохранении данных Пользователем и Ресивером, но с КП проблем не возникнет.

Prospekt
Сообщения: 41
Зарегистрирован: 30 май 2012, 23:06

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение Prospekt » 07 мар 2013, 10:37

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

Ладно, уговорили, может и стоит все запросы через КП делать. особых минусов, кроме объема кода нет + права на доступ выставлять.

insider
Сообщения: 13
Зарегистрирован: 30 ноя 2012, 19:40

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение insider » 11 мар 2013, 18:19

Вопрос не очень важный, просто по методике. Зачем в методе read проверять курсор на null? Разве может возникнуть такая ситуация? db.query все равно вернет Cursor, даже с нулем записей. А проверку мы и так сделаем в c.moveToFirst.

mmvds
Сообщения: 14
Зарегистрирован: 23 июл 2012, 18:31

Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.

Сообщение mmvds » 15 апр 2013, 14:29

neoksi писал(а): 1) Метод beginTransaction() отправляет в движок SQL команду скапливать запросы и не обрабатывать их;
2) Метод setTransactionSuccessful() отправляет в движок SQL команду, что блок запросов завершен;
3) Метод endTransaction() отправляет в движок SQL команду, распарсить и обработать запросы, которые были указанны в блоке транзаксации.

Если между 2 и 3 методом отправить ещё н-ное кол-во запросов, то они будут немедленно обработаны и запишутся в файл БД до обработки блока транзаксации. Но может возникнуть ситуация, когда этими запросами будет блокирован на запись файл БД, к которому затребует доступ блок транзаксации, что в свою очередь приведет к возникновению исключения доступа к файлу.
Что-то не сходится, если они действительно будут немедленно обработаны и запишутся в файл БД до обработки блока транзаксации, то почему в примере

Код: Выделить всё

void myActions() {
    db = dbh.getWritableDatabase();
    delete(db, "mytable");
    db.beginTransaction();
    insert(db, "mytable", "val1");
    db.setTransactionSuccessful();
    insert(db, "mytable", "val2");
    db.endTransaction();
    insert(db, "mytable", "val3");
    read(db, "mytable");
    dbh.close();
  }
Вывод был таким:

Код: Выделить всё

val1
val2
val3
а не таким?

Код: Выделить всё

val2
val1
val3

Ответить