Упорство Полиглота было в новостях с некоторого времени. Начатый знаменитой записью Фаулера с конца 2011 года, я вижу еще более интересные идеи. Последним был внутренний студенческий проект компании, в котором мы использовали Scala в качестве бэкэнда, сохраняющего данные в MongoDB, Derby и Solar. Я не большой поклонник Scala и вспомнил растущую поддержку EclipseLink для баз данных NoSQL. Учитывая, что я просто должен был попробовать это.
Когда начать?
Самая большая проблема — недостающие примеры. Вы найдете совсем немного о том, как изменить контейнеры данных (NoSQL или RDBMS) с EclipseLink, но вы не найдете ни одного, который бы точно использовал обе технологии без проблем. Благодаря Шону Смиту и Гуннару Вагенкрнехту у нас есть замечательная беседа на JavaOne о постоянстве Polyglot: EclipseLink JPA для NoSQL, Relational и Beyond, которая говорит именно об этом. К сожалению, источники до сих пор нигде не были переданы, и мне пришлось восстановить это из беседы. Так, кредиты идут для Шона и Гуннара для этого.
Волшебное решение называется « Персональная композиция» . Вам нужен один блок персистентности для каждого контейнера данных. Это выглядит как следующий основной пример. У вас есть пара сущностей в каждом PU, и композитный PU является зонтиком.
Поехали
Вы должны иметь MongoDB на месте, прежде чем вы начнете этот маленький учебник пример. Запустите NetBeans и создайте два Java-проекта. Давайте назовем их polyglot-persistence-nosql-pu и polyglot-persistence -ational-pu. Поместите следующие объекты в nosql-pu: Customer, Address, Order и OrderLine. (В основном взяты из
EclipseLink nosql examples ) и поместите сущность Product в рациональный-pu.
Отдельные продукты поступают в Дерби, а все остальные объекты сохраняются в MongoDB. Интересная часть, где OrderLine имеет отношение один к одному с продуктом:
1
2
|
@OneToOne (cascade = {CascadeType.REMOVE, CascadeType.PERSIST}) private Product product; |
Это точка, где оба мира объединяются. Подробнее об этом позже.
Оба PU должны иметь тип транзакции = ‘RESOURCE_LOCAL’ и должны содержать следующую строку в файле persistence.xml:
1
|
< property name = 'eclipselink.composite-unit.member' value = 'true' /> |
Не забудьте добавить конкретную конфигурацию БД. Для MongoDB это
1
2
3
|
< property name = 'eclipselink.nosql.property.mongo.port' value = '27017' /> < property name = 'eclipselink.nosql.property.mongo.host' value = 'localhost' /> < property name = 'eclipselink.nosql.property.mongo.db' value = 'mydb' /> |
Для дерби это примерно так:
1
2
3
4
|
< property name = 'javax.persistence.jdbc.url' value = 'jdbc:derby://localhost:1527/mydb' /> < property name = 'javax.persistence.jdbc.password' value = 'sa' /> < property name = 'javax.persistence.jdbc.driver' value = 'org.apache.derby.jdbc.ClientDriver' /> < property name = 'javax.persistence.jdbc.user' value = 'sa' /> |
Теперь нам нужно что-то, чтобы связать эти два PU вместе. Комбинированный pu находится в образце модуля polyglot-persistence-web и выглядит так:
1
2
3
4
5
6
7
8
9
|
< persistence-unit name = 'composite-pu' transaction-type = 'RESOURCE_LOCAL' > < provider >org.eclipse.persistence.jpa.PersistenceProvider</ provider > < jar-file >\lib\polyglot-persistence-rational-pu-1.0-SNAPSHOT.jar</ jar-file > < jar-file >\lib\polyglot-persistence-nosql-pu-1.0-SNAPSHOT.jar</ jar-file > < properties > < property name = 'eclipselink.composite-unit' value = 'true' /> </ properties > </ persistence-unit > </ persistence > |
Не упустите путь к файлу jar. Мы собираемся упаковать это в военный архив, и поэтому nosql-pu иational-pu перейдут в папку WEB-INF / lib. Как видите, мой пример — сборка с maven. Убедитесь, что вы используете последнюю зависимость EclipseLink. Даже GlassFish 3.1.2.2 все еще поставляется с более низкой версией. Поддержка MongoDB была добавлена начиная с 2.4.
1
2
3
4
5
|
< dependency > < groupId >org.eclipse.persistence</ groupId > < artifactId >eclipselink</ artifactId > < version >2.4.1</ version > </ dependency > |
Кроме того, вам также необходимо перевернуть загрузчики классов GlassFish:
1
|
< class-loader delegate = 'false' /> |
Не беспокойся о деталях. Я все ставлю на
github.com/myfear так что вы можете сами в дальнейшем разобраться в полном примере.
Тестирование это
Давайте сделаем несколько очень кратких испытаний с ним. Создайте симпатичный маленький сервлет Демо и вставьте в него составной пу. Создайте EntityManager из него и получите транзакцию. Теперь начните создавать продукты, клиента, заказ и отдельные строки заказа. Все просто JPA. Больше никакой магии здесь:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
@PersistenceUnit (unitName = 'composite-pu' ) private EntityManagerFactory emf; protected void processRequest() // [...] { EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); // Products go into RDBMS Product installation = new Product( 'installation' ); em.persist(installation); Product shipping = new Product( 'shipping' ); em.persist(shipping); Product maschine = new Product( 'maschine' ); em.persist(maschine); // Customer into NoSQL Customer customer = new Customer(); customer.setName( 'myfear' ); em.persist(customer); // Order into NoSQL Order order = new Order(); order.setCustomer(customer); order.setDescription( 'Pinball maschine' ); // Order Lines mapping NoSQL --- RDBMS order.addOrderLine( new OrderLine(maschine, 2999 )); order.addOrderLine( new OrderLine(shipping, 59 )); order.addOrderLine( new OrderLine(installation, 129 )); em.persist(order); em.getTransaction().commit(); String orderId = order.getId(); em.close(); |
Если вы установите правильные свойства ведения журнала, вы увидите, что происходит:
Пара последовательностей присваивается созданным объектам Product (GeneratedValue). Сущность Customer сохраняется в Mongo с MappedInteraction. Объекты отображаются на коллекции в MongoDB.
1
2
3
4
5
6
|
FINE: Executing MappedInteraction() spec => null properties => {mongo.collection=CUSTOMER, mongo.operation=INSERT} input => [DatabaseRecord( CUSTOMER._id => 5098FF0C3D9F5D2CCB3CFECF CUSTOMER.NAME => myfear)] |
После этого вы видите, что продукты вставляются в Derby и снова MappedInteraction, который перетаскивает Заказ в MongoDB. Действительно крутая часть внизу на линии заказов:
01
02
03
04
05
06
07
08
09
10
|
ORDER.ORDERLINES => [DatabaseRecord( LINENUMBER => 1 COST => 2999.0 PRODUCT_ID => 3 ), DatabaseRecord( LINENUMBER => 2 COST => 59.0 PRODUCT_ID => 2 ), DatabaseRecord( LINENUMBER => 3 COST => 129.0 PRODUCT_ID => 1 )] |
У строк заказа есть объект, у которого есть product_id, который был создан для связанных сущностей продукта. В дальнейшем вы также можете найти соответствующий Заказ и перебрать товары и получить их описания:
1
|
Order order2 = em.find(Order. class , orderId); |
1
2
3
|
for (OrderLine orderLine : order2.getOrderLines()) { String desc = orderLine.getProduct().getDescription(); } |
Хорошая маленькая демонстрация выглядит так:
Спасибо Шон, спасибо Гуннар за этот хороший маленький пример. Теперь зайдите на github.com/myfear и запачкайте руки 🙂
Ссылка: Постоянство Polyglot: EclipseLink с MongoDB и Derby от нашего партнера по JCG Маркуса Эйзела (Markus Eisele) из блога Enterprise Software Development с Java .