Рубрики
4. Полезняшки Java

Заметка об экспериментах со SnappyDB (NoSQL KeyValue DB под Android)

Небольшая заметка про SnappyDB. Это NoSQL база данных под Android, которая базируется на LevelDB и алгоритме сжатия Snappy.

LevelDB - это key-value база данных. Написана Google-ом для каких-то своих мега проектов.
Snappy - метод сжатия данных, сбалансированный на скорость (т.е. приоритет быстрота, а не степень сжатия). Также написана Google-ом.

Авторы SnappyDB на своем блоге приводят очень привлекательный график сравнивая скорость работы SnappyDB с SQLite.

Все это конечно очень и очень заманчиво, но лично меня она заинтересовала не поэтому. Дело не в скорости и даже не в том, что какие-то части этой БД делал Сам Google, а в более-менее нормальном API.

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

Конечно по-хорошему можно использовать API Preferenes или SQLite, но в некоторых случаях это не очень удобно.
В частности у SQLite несколько громоздкий API, а в preferences нет удобных методов для сложных выборок по ключам.

Упоминая более-менее нормальное API я имел в виду следующее. Вот что нужно сделать чтобы получить значение по ключу в Preferences (Android API).

  SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
  String username = sharedPref.getString("name", "");

Вот что нужно сделать чтобы получить значение по ключу в Snappy DB.

  DB db = DBFactory.open(context); 
  String username =  db.get("name");

Другими словами, API не такое "многословное" как стандартное Android API.

При этом если есть несколько записей ("name:0","name:1","name:2" и т.д.), то их можно получить как-то так:

  db.findKeys("name:");

Такое "из коробки" в Preferences сделать пока невозможно.

Поэтому мне показалось, что Snappy DB это удобно. Можно использовать например в таких задачах как:
- Сохранить справочников кодов и их описание
- Запоминать время работы каких-то специальных команд или хранить данные по мониторингу
- Идентификатор пользователя и его профиль (например в XML или JSON формате)

В общем все было хорошо, пока не наткнулся на одну приставку под Android TV, на которой был установлен Android M. Так вот, на этом устройстве Snappy DB внезапно стала работать с ошибками. Поскольку БД нативная, а желания дебажить сишный код у меня в последнее время нет, пришлось отказаться от ее использования в текущих проектах.

Рубрики
Java

Заметки по Derby DB

Нельзя сказать, что к Derby DB у меня особо теплые отношения. Первое знакомство с ней произошло много лет назад, когда на работе возникла идея прикрутить Derby вместо полноценной базы данных, чтобы проще было готовить демку программы к выставке. Идея была в том, что если взять легковесную встраиваемую базу, то тогда развертывание демонстрационного дистрибутива сильно упростится — скопировал файлики и ничего настраивать не нужно (в отличие от Оракла). В случае если нам нужен всего-лишь выставочный демонстрационный образец ПО такое решение было вполне оправдано. Почему выбор пал в тот момент именно на дерби думаю сейчас мало уже кто вспомнит.
В итоге конечно всё прикрутить получилось, но скорость работы базы на тот момент оставляла желать лучшего. Возможно где-то я был не прав (был молодым и неопытным), а возможно и сама база была "юной" и не достаточно расторопной. derby_db_logo

С тех пор прошло много времени, Derby уже давно поставляется вместе с JDK под именем Java DB, поэтому думаю в жизни многих Java-программистов также возникали случаи совместной работы с этой удивительной базой данных. Собственно поэтому решил описать некоторые её капризы и особенности. Сразу хочу заметить, что эту БД использую в жизни не так часто и возможно именно поэтому ее поведение меня иногда удивляет.

1.Кидается исключениями при отключении.

Чтобы отключить БД в embedded режиме, нужно в JDBC-URL прописать "jdbc:derby:;shutdown=true". Если всё нормально, в вас обязательно при отключении кинут исключением SQLException с кодом XJ015. К этому нужно привыкнуть и не пугаться.

2.Режим использования RAM (In-memory).

У Derby есть не плохой экспериментальный режим, когда она работает в памяти.
Удобно использовать для создания временного окружения (чтобы не удалять созданные файлы и директории) или в различных jUnit-тестах.
Опять таки все делается через URL, например для создания пишем: "jdbc:derby:memory:myDB;create=true".

При этом если вы сделаете shutdown, но не потушите JVM, то ваша БД не почистится. Чтобы удалить данные из памяти нужно сделать сделать drop (jdbc:derby:memory:myDB;drop=true), который сам сделает shutdown:
You can shut down an in-memory database using the shutdown=true attribute before you drop the database, but this is optional. Dropping the database also performs the shutdown.

3.JRE7u51

В JRE7u51 поменялись ограничение в настройках безопасности. Поэтому при запуске дерби в сетевом режиме могут валиться исключения AccessControlException.
На официальной странице oracle предлагается решение, в котором необходимо настроить собственный security.policy файл, чтобы в нем был доступ к порту (по-умолчанию 1527). Например так:

grant {
    permission java.net.SocketPermission "localhost:1527", "listen";
};

Хорошая пошаговая инструкция на странице администрирования.

Рубрики
Java

OrderBy или OrderColumn

Между JPA аннотациями OrderBy и OrderColumn существует огромная разница.

Рубрики
3. Инструментарий

oracle xe + ru. >_< Rrrr!

Нужно было поставить Oracle XE на Windows XP (RU).
Все нормально качается с официального сайта.
Установка супер-простая (по сравнению с обычной установкой оракла).

Пользователь по-умолчанию: system
SID по-умолчанию: XE
Панель управления доступна через на порту 8080.

Админка работает, SQLPlus подключается и уже казалось, что счастье так близко.

Если вы попытаетесь подключиться через JDBC, напоритесь на эпохальный баг с NLS.
Достаточно в Google вбить: oracle xe nls и вы увидите огромное множество советов по решению этой проблемы.
Вариантов уйма: править в реестре, менять локаль, выполнять магические команды в оракле, использовать специальный jdbc-драйвера от другой версии.

Все это конечно очень весело, но мне интересно, когда-нибудь Oracle подправит это баг или нет?... Это же ужасно.

Рубрики
2. Теория программирования

деревья и реляционные базы данных. вложенные множества.

Для работы с древовидными (иерархическими) структурами в первую очередь следует постараться понять какие действия будут осуществляться часто, а какие эпизодически.

Цель статьи не описать все возможные способы хранения таких данных,  а в сжатом виде виде описать два часто встречающихся  подхода и область их наилучшего применения.

1.  Узел хранит информацию о родителе. Это  классика.

CREATE TREE_NODE (ID INT ..., PARENT_ID INT, ...);

Все очень просто -  узел хранит идентификатор родительского узла. Самая простая схема.

Такую схему удобно использовать когда:

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

Другой вариант использования, когда в основном  требуются выборки на уровне одного поколения - получить список  "детей" у данного узла или получить информацию о родителе. Например, если мы используем асинхронное получение узлов в дереве.  Тогда дерево отображается не сразу, а после нажатия пользователем на соответствующий узел, после которого идет обращение к веб-серверу на получение данных. Например, как это выглядит в  Ext GWT (GXT).

Кстати, в некоторых базах данных существует уже готовые механизмы для работы с деревьями. В частности в ORACLE это CONNECT BY.

2. Вложенные множества.  Узел хранит в себе информацию о своем расположение в дереве.

CREATE TREE_NODE (ID INT ...,  LEFT INT...,  RIGHT INT...) ;

О вложенных множествах написано сейчас в интернете уже предостаточно. Основную идею можно понять из картинки.

и следующего SQL запроса (получение всей ветки для C.1):

SELECT id FROM tree WHERE left <= 5  AND right => 6 ORDER BY left; -- в итоге получим узлы A, B.2, C.1