话说世间万物有一得必有一失,而在0和1的世界里这点体现的是更加明显。无模式Nosql存储在拥有了一些列的优点同时,付出的也不可谓不多。而Nosql运动的主要优势莫过于赐予人们数据持久层的多样化选择。通过Nosql我们不必要再将所有数据都转化成关系数据模式。而今最大的挑战没过于每个领域系统中数据持久模型的选择及后续模型的紧密集合。有很多方法可以用于解决这个问题,通用的方法一般是Polyglot Peristence。下面我们来看一下如何通过Java、Spring、Hibernate和Postgresql将普通的sql模型与key-value Nosql模型紧密的集合起来。
本文涉及到一个简单的网络应用程序,这个程序使用了常规sql及PostgreSQL的hstore类型的键值对。思想是将Nosql混合进sql中,而这个方法的好处则是可以在同一个数据存储中同时储存sql和Nosql类型数据。
在这个例子中将覆盖Java、Spring和Hibernate服务器技术,当然也可以通过Rails、Django及一些其他技术来实现。为了向Hibernate中添加对hstore的支持,更是特意的查询了“通过Hibernate向单一数据库行中储存PostgreSQL hstore类型键/值对”这篇文章。虽然编码内容不会在这里详谈,但是你可以通过GitHub repo for my demo project得到你想要的一切。
演示应用程序使用Maven来定义依赖性。Jetty的嵌入则是通过一个简单的ole Java用用程序开始。Spring则是通过Java Config中的main部分、web部分及database部分来配置。
客户端技术将会用到jQuery和Bootstrap,而客户端和服务器将会通过RESTful JSON服务进行严格分隔。整个客户端部分都会放在一个简单的ole HTML文件中。客户端与JSON之间将通过jQuery/Ajax实现通信,这点则是在Spring MVC Controller中得以声明。
言归正传,回到在sql中实现Nosql上来。虽然该应用程序存储的“Contacts”只有一个name属性,但是不妨碍它拥有“Contacts Methods”(比如,电话号码和电子邮箱地址)。“Contact Methods”是个非常好的无模式键值对列因为它避免了繁琐的替代选择:将这些信息放进一个单独的表或者尝试去建立一个包含所有可能存在的“Contact Methods”类。来让我们看一下简单的Contact类:
- packagecom.jamesward.model;
- importnet.backtothefront.HstoreUserType;
- importorg.hibernate.annotations.Type;
- importorg.hibernate.annotations.TypeDef;
- importjavax.persistence.Column;
- importjavax.persistence.Entity;
- importjavax.persistence.GeneratedValue;
- importjavax.persistence.Id;
- importjava.util.HashMap;
- importjava.util.Map;
- @Entity
- @TypeDef(name="hstore",typeClass=HstoreUserType.class)
- publicclassContact{
- @Id
- @GeneratedValue
- publicIntegerid;
- @Column(nullable=false)
- publicStringname;
- @Type(type="hstore")
- @Column(columnDefinition="hstore")
- publicMap<String,String>contactMethods=newHashMap<String,String>();
- }
如果你熟知Hibernate/JPA的话,那么以上这些对于你来说都会非常的熟悉。而吸引你的陌生之处在于contactMethods对象的修饰 — Map<String,String>,并且还使用了Postgresql的hostore数据类型。为了正常运行,hostore数据的类型必须被定义以及columnDefinition集。这不得不再次感谢Jakub Gluszecki对HstoreHelper和HostoreUserTyper的整合,否则的话这一切都无法实现。
因为只是简单的Hibernate/JPA,剩下的就比较简单了。下面是做基本查询和修改的ContactService类:
packagecom.jamesward.service;
importcom.jamesward.model.Contact;
importorg.springframework.stereotype.Service;
importorg.springframework.transaction.annotation.Transactional;
importjavax.persistence.EntityManager;
importjavax.persistence.PersistenceContext;
importjavax.persistence.criteria.CriteriaQuery;
importjava.util.List;
@Service
@Transactional
publicclassContactServiceImplimplementsContactService{
@PersistenceContext
EntityManagerem;
@Override
publicvoidaddContact(Contactcontact){
em.persist(contact);
}
@Override
publicList<Contact>getAllContacts(){
CriteriaQuery<Contact>c=em.getCriteriaBuilder().createQuery(Contact.class);
c.from(Contact.class);
returnem.createQuery(c).getResultList();
}
publicContactgetContact(Integerid){
returnem.find(Contact.class,id);
publicvoidaddContactMethod(IntegercontactId,Stringname,Stringvalue){
Contactcontact=getContact(contactId);
contact.contactMethods.put(name,value);
}
在你了解它的工作机制后,我们要开始尝试在Heroku上面的演示了。
如果你想在本地或者Heroku上运行这个应用程序,那么首先你必须提取源代码然后继续新建spring_hibernate_hstore_demo目录的工作:
$gitclonehttps:
$cdspring_hibernate_hstore_demo
在本地运行需要做的工作:
1.通过新建到pssql上的连接来允许Postgresql数据库对hstore的支持:
$psql-Uusername-W-hlocalhostdatabase
2. 启用hstore:
=>createextensionhstore;
=>\q
3. 建立应用程序(这部依赖Maven的安装):
$mvnpackage
4. 设置DATABASE_URL环境变量指向你的Postgresql服务器:
$exportDATABASE_URL=postgres:
5. 运行应用程序:
$java-cptarget/classes:target/dependency/*com.jamesward.Webapp
6.尝试一下
完美?!现在再试一下通过Heroku在云上运行。你需要完成以下几个步骤:
1.安装Hero Toolbelt
2. 登陆Heroku:
$herokulogin
3. 建立一个新的应用程序:
$herokucreate
4. 添加Heroku Postgres:
$herokuaddons:addheroku-postgresql:dev
5. 通知Heroku完成基于刚添加数据库上的DATABASE_USL设置(手动重置YOUR_HEROKU_POSTGEsql_COLOR_URL):
$herokupg:promoteYOUR_HEROKU_POSTGREsql_COLOR_URL
6. 打开到数据库的psql连接:
$herokupg:psql
7. 让hstore完成对你数据库的支持:
8. 部署应用程序:
$gitpushherokumaster
9. 在云端查看应用程序:
$herokuopen
在这里我们完成了使用postgresql、hibernate、spring、java在sql数据库中实现Nosql的全部演示,而在集思广益下Nosql与sql的融合也必将更加完美!(编译/仲浩包研/责编原文来自James Ward)
http://www.csdn.net/article/2012-10-18/2810937-nosql-sql-java-spring-hibernate