среда, 23 ноября 2011 г.

Berkeley DB Java Edition, ч.1

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

  • нечто заточенное под хранение произвольных объектов с заранее неизвестной структурой. Т.е. в идеале - объектно-ориентированная БД, или просто key-value хранилище
  • нечто компактное, но потенциально расширяемое. Поднимать на недорогом (на дорогой нет денег) хостинге серьезную БД задача не для слабонервных. Это в любом случае не просто "с нуля", в том числен и с нуля знаний. MySQL в минимальном варианте я конечно подниму, но как раз MySQL мне не очень подойдет по п.1. Да и он достаточно прожорлив в плане ресурсов

По всей видимости мне нужна компактная "embedded" БД и после некоторых поисков я остановился на Berkeley DB. Она не совсем проходит по первому пункту, БД не объектно-ориентированная. Но собственно мне не так много этого объектно-ориентированного функционала и нужно. Т.е. не помешает, но ставить ради этого отдельный сервер БД я не готов.

Посмотрел еще всякие разные объектные БД, в том числе и встраиваемые в приложения, но либо откровенное не то, либо нехорошие отзывы, либо лицензия не подходящая. Попробую познакомиться поближе с BDB JE и обойти ее ограничения, которые начали всплывать практически сразу.

java.lang.IllegalArgumentException: An entity class may not be derived from another entity class

У меня сложная иерархия объектов, но хранить их нужно единообразно. Т.е. получив некоторый ключ, я не знаю заранее, объекту какого типа он соответствует. Для примера:

class Ship {
 ArrayList<Equipment> equipment;
}

Equipment это может быть и Gun и PowerGenerator и бог знает что еще. Если у меня есть необходимость хранить их как отдельные Entity (а такая необходимость в общем случае у меня есть), а не просто как часть Ship, то возникают некоторые сложности. А именно - Gun, PowerUnit и GoodOnlyKnowsWhatElse - это отдельные Entity и записать их вместе и просто получить потом по значению ключа одним запросом нельзя. Т.е:

PrimaryIndex<Key,Equipment> gunindex = store.getPrimaryIndex(Key.class,Equipment.class)

Gun gun=new Gun();
PowerUnit pu=new PowerUnit();
index.put(gun); // вылетит Exception

если же я сделаю

PrimaryIndex<Key,Gun> gunindex = store.getPrimaryIndex(Key.class,Gun.class)

PrimaryIndex<Key,PowerUnit> puindex = store.getPrimaryIndex(Key.class,PowerUnit.class)

то и записывать и получать я их потом буду отдельно:
gunindex.put(gun);
puindex.put(pu);
gun=gunindex.get(key);
pu=puindex.get(key);
а как я уже сказал - я не знаю заранее к чему относится key, т.е. придется делать обращение ко всем индексам чтобы выяснить к какому относится данный key. Либо закладывать в key информацию о типе объекта и выбирать нужный index.
Есть другой путь
Даже 2. Первый - использовать Base API вместо Direct Persistent Layer. Не вдаваясь в подробности - это возможность закопаться глубоко в недра БД и делать с ней все что захочется. Никаких надстроек, чистая работа с key-value и не важно что именно в них находится. По сути это ядро БД, на которое можно накрутить свою надстройку которая будет делать то что нужно и так как нужно именно вам. Но возни будет много.
Второй путь проще. Делаем обертку:
@Entity
class Item {
  @PrimaryKey
  Key key;
  Equipment data;
  public Item() {}
  public Item(Equipment dt) {
     data=dt;
     key=dt.getKey();
     }
}
а классы Gun, PowerUnit и GoodOnlyKnowsWhatElse помечаем как @Persistent и реализуем в них метод getKey. В результате мы имеем избыточность в данных, но зато все они вставляются и извлекаются единообразно как Item, чтобы у него там внутри не было. Можно добавить еще вторичный ключ который задает тип хранимого объекта. - избыточность возрастет еще, но можно будет выбирать объекты по их типу
Update: Все это бред
Ларчик открылся просто.
Есди у меня есть иерархия объектов, но я хочу хранить их вместе, то я должен пометить базовый класс как @Entity, а его потомки  - как @Persistent.
Тогда не нужны никакие левые обертки.

Комментариев нет:

Отправить комментарий