Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Последний раз редактировалось damager82 01 май 2017, 16:41, всего редактировалось 12 раз.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Спасибо за статью, пригодилась.
Вот еще в тему http://www.enterra.ru/blog/android_issues_with_sqlite/, тоже кое-что полезного взять можно.
Вот еще в тему http://www.enterra.ru/blog/android_issues_with_sqlite/, тоже кое-что полезного взять можно.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Спасибо, хороший материал! Добавлю ссылку в урок.eugene78 писал(а):Спасибо за статью, пригодилась.
Вот еще в тему http://www.enterra.ru/blog/android_issues_with_sqlite/, тоже кое-что полезного взять можно.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Спасибо большое! Отличный урок.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
тут вроде надоЭто очень важно! Т.е. если вы открыли транзакцию, выполнили какие-либо действия и не закрыли транзакцию, то все операции будут считаться успешными и изменения будут внесены в БД. Поэтому закрытие транзакции необходимо выполнять и finally нам это гарантирует.
Это очень важно! Т.е. если вы открыли транзакцию, выполнили какие-либо действия и не закрыли транзакцию, то все операции будут считаться неуспешными и изменения не будут внесены в БД. Поэтому закрытие транзакции необходимо выполнять и finally нам это гарантирует.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Да, чето я фигню написал какую-то ... Спасибо за наблюдательность! Пофиксилalex6999 писал(а): тут вроде надоЭто очень важно! Т.е. если вы открыли транзакцию, выполнили какие-либо действия и не закрыли транзакцию, то все операции будут считаться неуспешными и изменения не будут внесены в БД. Поэтому закрытие транзакции необходимо выполнять и finally нам это гарантирует.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Получается, расположение метода setTransactionSuccessful() может быть любым между открытием и закрытием транзакции?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 мы вставляли уже после подтверждения успешности транзакции, запись вставилась, вошла в эту транзакцию.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Получается так. Но, походу, это не приветствуется, т.к. в хелпе есть такой текст: "Do not do any more database work between calling this and calling endTransaction."d79 писал(а):Получается, расположение метода setTransactionSuccessful() может быть любым между открытием и закрытием транзакции?
Пожалуй, надо мне отметить это в уроке.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Так же смогу сказать что, например, вставка записей (к примеру 1к) проходит быстрее в транзакции чем без.
Кстати актуально не только для SQLite
Кстати актуально не только для SQLite
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Интересен такой момент: а что если делать SQLiteOpenHelper синглетоном?
Вроде работает нормально, и можно методы доступа синхронизировать. Вопрос только в том, надо ли закрывать SQLiteOpenHelper?
После каждого обращения делать закрытие накладно, но если никогда не закрывать (...close()), то что будет при убивании всех экземпляров активити, работающих с этим Хелпером?
Я так понимаю, что умная система должна сама убить (закрыть) Хелпер, как она закрывает например все in\outStream при выходе. Или же статический объект будет висеть вечно? Как вариант, можно запоминать время последнего обращения к хелперу, и если оно больше скажем 5 минут, то хелпер уничтожается. И при запросе воссаздается заново.
Вроде работает нормально, и можно методы доступа синхронизировать. Вопрос только в том, надо ли закрывать SQLiteOpenHelper?
После каждого обращения делать закрытие накладно, но если никогда не закрывать (...close()), то что будет при убивании всех экземпляров активити, работающих с этим Хелпером?
Я так понимаю, что умная система должна сама убить (закрыть) Хелпер, как она закрывает например все in\outStream при выходе. Или же статический объект будет висеть вечно? Как вариант, можно запоминать время последнего обращения к хелперу, и если оно больше скажем 5 минут, то хелпер уничтожается. И при запросе воссаздается заново.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Это будет велосипедом, для этого есть СontentProvider, который является синглтоном и все это берет на себя.Prospekt писал(а):Интересен такой момент: а что если делать SQLiteOpenHelper синглетоном?
Вроде работает нормально, и можно методы доступа синхронизировать. Вопрос только в том, надо ли закрывать SQLiteOpenHelper?
После каждого обращения делать закрытие накладно, но если никогда не закрывать (...close()), то что будет при убивании всех экземпляров активити, работающих с этим Хелпером?
Я так понимаю, что умная система должна сама убить (закрыть) Хелпер, как она закрывает например все in\outStream при выходе. Или же статический объект будет висеть вечно? Как вариант, можно запоминать время последнего обращения к хелперу, и если оно больше скажем 5 минут, то хелпер уничтожается. И при запросе воссаздается заново.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Гы,
У многих есть неравнодущее к некоторым аспектам программирования, некоторые видят все мировое зло в несоблюдении правил отступа, некоторые считают мастерское владение дебагером сутью программирования, а товарищ neoksi помещан на КонтентПровайдерах. Прямо через пост.
За ответ спасибо, но как-то это не то.
КП определенно хороши, но хочется вариант поминиатюрней. Хотя определенно большая часть правда в вашем посте содержится. Как я понимаю, Вы предлагаете все обращения к БД делать исключительно через КП?
И всеже если взяться за ответку и прикрутить 2 колеса. Ну хотя бы как вариант.
У многих есть неравнодущее к некоторым аспектам программирования, некоторые видят все мировое зло в несоблюдении правил отступа, некоторые считают мастерское владение дебагером сутью программирования, а товарищ neoksi помещан на КонтентПровайдерах. Прямо через пост.
За ответ спасибо, но как-то это не то.
КП определенно хороши, но хочется вариант поминиатюрней. Хотя определенно большая часть правда в вашем посте содержится. Как я понимаю, Вы предлагаете все обращения к БД делать исключительно через КП?
И всеже если взяться за ответку и прикрутить 2 колеса. Ну хотя бы как вариант.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Тут нужно учесть, что SQLite однопоточная БД и очередность запросов отдана на откуп программистам пишущим приложения.damager82 писал(а):Получается так. Но, походу, это не приветствуется, т.к. в хелпе есть такой текст: "Do not do any more database work between calling this and calling endTransaction."d79 писал(а):Получается, расположение метода setTransactionSuccessful() может быть любым между открытием и закрытием транзакции?
Пожалуй, надо мне отметить это в уроке.
1) Метод beginTransaction() отправляет в движок SQL команду скапливать запросы и не обрабатывать их;
2) Метод setTransactionSuccessful() отправляет в движок SQL команду, что блок запросов завершен;
3) Метод endTransaction() отправляет в движок SQL команду, распарсить и обработать запросы, которые были указанны в блоке транзаксации.
Если между 2 и 3 методом отправить ещё н-ное кол-во запросов, то они будут немедленно обработаны и запишутся в файл БД до обработки блока транзаксации. Но может возникнуть ситуация, когда этими запросами будет блокирован на запись файл БД, к которому затребует доступ блок транзаксации, что в свою очередь приведет к возникновению исключения доступа к файлу.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Я понимаю это, но ведь такие ограничения остаются и для ContentProvider-ов. Большинство примеров БД - это маленькие базы с одной таблицей, с мелкими методами getItem() getAll() insertItem() updateItem() deleteItem() и эти методы можно сделать синхронизированными виду малости исполняемого кода. (Не повлияет на скорость).
Согласитесь, что во множестве случаев легче иметь простенький вариант решения, а городить 3-4 таблицы, связанных между собой - это редкость. Пока встречал варианты только простых БД.
Согласитесь, что во множестве случаев легче иметь простенький вариант решения, а городить 3-4 таблицы, связанных между собой - это редкость. Пока встречал варианты только простых БД.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
ProspektProspekt писал(а):Гы,
У многих есть неравнодущее к некоторым аспектам программирования, некоторые видят все мировое зло в несоблюдении правил отступа, некоторые считают мастерское владение дебагером сутью программирования, а товарищ neoksi помещан на КонтентПровайдерах. Прямо через пост.
За ответ спасибо, но как-то это не то.
КП определенно хороши, но хочется вариант поминиатюрней. Хотя определенно большая часть правда в вашем посте содержится. Как я понимаю, Вы предлагаете все обращения к БД делать исключительно через КП?
И всеже если взяться за ответку и прикрутить 2 колеса. Ну хотя бы как вариант.
Программируя на другом языке и работая с SQLite, я уже сталкивался с проблемой разграничения доступа к однопоточной БД из разных потоков программы, и честно, это была ещё та головомойка. Тут же, разработчики Андроида предусмотрели механизм, который все делает за нас, да, для понимания начального он сложен. Плюс КП дает свои плюшки, к примеру автоматическое обновление данных в отображаемых элементах при изменении их в БД. Я призываю его использовать, так как в конечном итоге он упрощает жизнь и не надо будет искать, где же и почему вдруг возникло исключение, когда два потока приложения одновременно решили поработать с БД.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
По всей видимости есть необходимость в уроке "ContentProvider vs других вариантов" при работе с БД.
Какие плюсы он дает? Да комбинация ContentProvider и BroadCastResiever позволяют автоматически обнавлять данные в приложении и даже в GUI.
Какие плюсы он дает? Да комбинация ContentProvider и BroadCastResiever позволяют автоматически обнавлять данные в приложении и даже в GUI.
Возможно в сложных случаях это действительно головомойка, но в большинстве случаев БД в Android - это всего лишь прокладка между программой и жестким диском (или какой он там). Прогеров ломает самим считывать данные с диска и сохранять их там, поэтому используются минимум из функционала БД. Сложности возникают при полноценном юзаньи БД, как например программы на серверном оборудовании, а тут -то где можно черту ногу поломать в 3-х соснах. Я вроде не глупый, но представить ситуацию такую не могу для Android-а. Поделитесь плиз, для моего собственного развития.Согласитесь, что во множестве случаев легче иметь простенький вариант решения, а городить 3-4 таблицы, связанных между собой - это редкость. Пока встречал варианты только простых БД.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Prospekt
Если вы работаете с данными только из одной точки, к примеру из одной активити, то да, тут можно напрямую без КП обойтись. Но как только вы начинаете работать с данными из разных точек, активити, сервисы и ресиверы, то становится необходимым создание КП для централизации процесса и избегания проблем.
Возьмем абстрактный пример:
Есть программа будильник, которая хранит назначенные будильники в БД (это одна таблица) и ими можно управлять из активити. Но у нас программа с супер мега функцией, если послать на телефон смс в определенном формате, то она может активировать или дезактировать будильник на определенный день (реализуется через БроадкастРесивер).
И так наступает час Х, когда наш пользователь открыл активити и работает с настройкой будильника на субботу, а в тот же момент ему приходит супер смс от жены с требованием отключить будильник на субботу. Без КП, я даже не хочу гадать, какая ошибка может выскочить, при одновременном сохранении данных Пользователем и Ресивером, но с КП проблем не возникнет.
Если вы работаете с данными только из одной точки, к примеру из одной активити, то да, тут можно напрямую без КП обойтись. Но как только вы начинаете работать с данными из разных точек, активити, сервисы и ресиверы, то становится необходимым создание КП для централизации процесса и избегания проблем.
Возьмем абстрактный пример:
Есть программа будильник, которая хранит назначенные будильники в БД (это одна таблица) и ими можно управлять из активити. Но у нас программа с супер мега функцией, если послать на телефон смс в определенном формате, то она может активировать или дезактировать будильник на определенный день (реализуется через БроадкастРесивер).
И так наступает час Х, когда наш пользователь открыл активити и работает с настройкой будильника на субботу, а в тот же момент ему приходит супер смс от жены с требованием отключить будильник на субботу. Без КП, я даже не хочу гадать, какая ошибка может выскочить, при одновременном сохранении данных Пользователем и Ресивером, но с КП проблем не возникнет.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
а разве synchronized не решит эту проблему, ну если синхронизировать запросы к данным?
Хотя конечно да, все равно придется БроадкастРесивер ставить, чтобы не было рассогласования между данными программы и бд.
Ладно, уговорили, может и стоит все запросы через КП делать. особых минусов, кроме объема кода нет + права на доступ выставлять.
Хотя конечно да, все равно придется БроадкастРесивер ставить, чтобы не было рассогласования между данными программы и бд.
Ладно, уговорили, может и стоит все запросы через КП делать. особых минусов, кроме объема кода нет + права на доступ выставлять.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Вопрос не очень важный, просто по методике. Зачем в методе read проверять курсор на null? Разве может возникнуть такая ситуация? db.query все равно вернет Cursor, даже с нулем записей. А проверку мы и так сделаем в c.moveToFirst.
Re: Урок 38. Транзакции в SQLite. Небольшой FAQ по SQLite.
Что-то не сходится, если они действительно будут немедленно обработаны и запишутся в файл БД до обработки блока транзаксации, то почему в примере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