從現在開始,多語種持久性一直是新聞。 從2011年底開始,在著名的Fowler帖子的推動下,我看到了更多更好的主意。 最新的一個是公司內部的學生項目,我們在其中使用Scala作為后端數據,將數據持久存儲到MongoDB,Derby和Solar中。 我不是Scala的忠實擁護者,并且還記得EclipseLink對NoSQL數據庫的日益增長的支持 。 鑒于我只需要嘗試一下。
從哪兒開始?
最大的問題是缺少的示例。 您發現了很多有關如何使用EclipseLink更改數據容器(NoSQL或RDBMS)的知識,但是您找不到一個完全無縫地同時使用兩種技術的數據容器。 感謝Shaun Smith和Gunnar Wagenkrnecht,我們在JavaOne上進行了關于Polyglot持久性的精彩演講:EclipseLink JPA for NoSQL,Relational和Beyond正是在此進行了討論。 不幸的是,消息來源仍然沒有被推送到任何地方,我不得不從演講中重新構建它,因此,功勞歸功于Shaun和Gunnar。
神奇的解決方案稱為持久性單元組成 。 每個數據容器都需要一個持久性單元。 看起來像下面的基本示例。 每個PU中都有幾個實體,并且復合PU是保護傘。
我們走吧
在開始這個小教程示例之前,您應該已經安裝了MongoDB 。 啟動NetBeans并創建兩個Java項目。 讓我們稱它們為polyglot-persistence-nosql-pu和polyglot-persistence-rational-pu。 將以下實體放入nosql-pu:客戶,地址,訂單和訂單行。 (大部分取自
EclipseLink nosql示例 ),然后將Product實體放入Rational-pu。
單個產品進入Derby,而其他所有實體都保留在MongoDB中。 有趣的部分是,OrderLine與產品具有一對一關系:
@OneToOne(cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
private Product product;
這是兩個世界融合在一起的點。 以后再說。
兩個PU都必須是transaction-type ='RESOURCE_LOCAL',并且需要在persistence.xml中包含以下行:
<property name='eclipselink.composite-unit.member' value='true'/>
不要忘記添加數據庫特定的配置。 對于MongoDB,這是
<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'/>
對于德比,這是這樣的:
<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鏈接在一起。 Combined-pu駐留在示例polyglot-persistence-web模塊中,如下所示:
<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和有理-pu將進入WEB-INF / lib文件夾。 如您所見,我的示例是使用Maven構建的。 確保使用最新的EclipseLink依賴項。 甚至GlassFish 3.1.2.2仍附帶較低版本。 從2.4開始增加了對MongoDB的支持。
<dependency><groupId>org.eclipse.persistence</groupId><artifactId>eclipselink</artifactId><version>2.4.1</version></dependency>
除此之外,還需要翻轉GlassFish的類加載器:
<class-loader delegate='false'/>
不用擔心細節。 我把一切都放在
github.com/myfear,因此,您稍后可能會自行研究完整的示例。
測試它
讓我們用它做一些非常簡短的測試。 創建一個不錯的Demo servlet,然后將Composite-pu注入其中。 從中創建一個EntityManager并獲取交易。 現在開始創建產品,客戶,訂單和單獨的訂單行。 所有普通的JPA。 這里沒有進一步的魔術:
@PersistenceUnit(unitName = 'composite-pu')private EntityManagerFactory emf;protected void processRequest() // [...]{EntityManager em = emf.createEntityManager();em.getTransaction().begin();// Products go into RDBMSProduct 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 NoSQLCustomer customer = new Customer();customer.setName('myfear');em.persist(customer);// Order into NoSQLOrder order = new Order();order.setCustomer(customer);order.setDescription('Pinball maschine');// Order Lines mapping NoSQL --- RDBMSorder.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();
如果將正確的日志記錄屬性放在適當的位置,您可以看到正在發生的情況:
將幾個序列分配給創建的產品實體(GeneratedValue)。 客戶實體通過MappedInteraction持久化到Mongo中。 實體映射到MongoDB中的集合。
FINE: Executing MappedInteraction()
spec => null
properties => {mongo.collection=CUSTOMER, mongo.operation=INSERT}
input => [DatabaseRecord(
CUSTOMER._id => 5098FF0C3D9F5D2CCB3CFECF
CUSTOMER.NAME => myfear)]
之后,您將看到產品被插入到Derby中,然后又被插入到MappedInteraction中,該訂單將訂單插入MongoDB中。 真正酷的部分在于OrderLines:
ORDER.ORDERLINES => [DatabaseRecord(LINENUMBER => 1COST => 2999.0PRODUCT_ID => 3), DatabaseRecord(LINENUMBER => 2COST => 59.0PRODUCT_ID => 2), DatabaseRecord(LINENUMBER => 3COST => 129.0PRODUCT_ID => 1)]
訂單行具有一個對象,該對象具有為相關產品實體生成的product_id。 進一步,您還可以找到相關的訂單并遍歷產品并獲得其描述:
Order order2 = em.find(Order.class, orderId);
for (OrderLine orderLine : order2.getOrderLines()) {String desc = orderLine.getProduct().getDescription();}
不錯的小演示如下所示:
感謝Shaun,感謝Gunnar提供的這個好例子。 現在去github.com/myfear弄臟你的手:)
參考: Polyglot持久性: JCG合作伙伴 Markus Eisele在Java企業軟件開發博客上的EclipseLink與MongoDB和Derby 。
翻譯自: https://www.javacodegeeks.com/2012/11/polyglot-persistence-eclipselink-with-mongodb-and-derby.html