mongodb是一种基于文档类型的高性能nosql数据库,在高并发下具有优秀的表现,因此,在互联网行业中,mongodb的使用场景将非常广泛。
当然,mongodb主要对性能关注很多,因而没有提供类似于关系数据库的事务的功能,对于复杂的业务及严格数据一致性要求很高有企业级应用,不建议使用mongodb(网上也有自己去实现事务提交的方案,但实现起来比较繁琐,类似于我们早期dbase,access文件型数据库的事务解决方案)。
其实,也不排除在企业级应用上把某些访问压力大的,对事务要求不严格的数据保存到nosql数据库中。
spring data框架,提供了对mongodb的支持,大家可以到http://mongojack.org/,及http://www.springsource.org/spring-data/mongodb
上了解更多信息mongodb及sprig data for mongodb相关信息。
下面,我用一个简单的实例,给大家讲解mongodb的使用,在这之前,你需要下载mongodb java驱动包,spring data commons, spring data for mongodb这些组件包。
共两个对象,客户,客户订单,一对多关系,单向关联。
客户:
@Document
public class Customer {
@Id
private int id;
private String loginCode;
private String name;
private String pwd;
@Version
private long varsion;
private Date birthday = new Date();
private Set<Order> orders = new HashSet<Order>();
订单:
@Document
public class Order {
@Id
private int id;
private String code;
private String orderName;
spring data的配置:
@Configuration
public class MongoConfiguration {
public @Bean MongoDbFactory mongoDbFactory() throws Exception {
//需要用户名、密码验证
UserCredentials userCredentials = new UserCredentials("yq", "123");
return new SimpleMongoDbFactory(new Mongo(), "exam", userCredentials);
//return new SimpleMongoDbFactory(new Mongo(), "exam");
}
public @Bean MongoTemplate mongoTemplate() throws Exception {
return new MongoTemplate(mongoDbFactory());
}
}
当然,上面这段信息可以配置在xml中,也可以像我上面一样用写在java代码中。
这里要建立exam库,可以在mongodb命令行下,使用 use 命令建立,比如:use exam,然后随便添点东西在里面,库就建好了。另外,如果要启用认证功能,需要大家通过命令向某个库中添加用户(具体如db.addUser(“用户名”,”密码”)),启动mongodb时使用-auth参数。
在整合过程中,如果报:
tried to access methodorg.springframework.core.GenericTypeResolver.getTypeVariableMap错误,是由于包版本冲突所至,请下载新的spring核心包。
下面给大家举例说明api的使用:
我们的所有操作只需要一个MongoTemplate
@Resource
private MongoTemplate mt;
(1)检测一个空间是否存在
mt.collectionExists(Customer.class);
(2)建立新空间
mt.createCollection("myCollection");
(3)统计总记录条数,其中query可以为null,或一个建好的带条件查数据的query,如需分页,请先count,再查分页数据
mt.count(new Query(), Customer.class);
(4)删除空间,其中的数据会一并清除
mt.dropCollection("myCollection");
(5)按id号查询
Customer c = mt.findById(1, Customer.class);
(6)删除id号为1的客户
mt.remove(mt.findById(1, Customer.class));
(7)删除id号小于5的客户
mt.remove(new Query(Criteria.where("id").lt(5)), Customer.class);
(8)查询姓名是:张三5,并且密码是:111的用户
List<Customer> cc = mt.find(new Query(Criteria.where("name").is("张三5").and("pwd").is("111")), Customer.class);
或List<Customer> cs = mt.find(new Query(Criteria.where("name").is("张三5").andOperator(Criteria.where("pwd").is("111"))), Customer.class);
要注意,一个criteria中只能有一个andOperator,如果要写并列条件,直接用and就可以了。
(9)查询姓名是:张三5,或者 密码是:111的用户
List<Customer> cs = mt.find(new Query(new Criteria().orOperator(Criteria.where("name").is("张三5"),Criteria.where("pwd").is("111"))), Customer.class);
(10)查询出生日期小于2013年6月6日的客户
List<Customer> cs = mt.find(new Query(Criteria.where("birthday").lt(new Date())), Customer.class);
(11)查询出生日期等于2013年6月6日的客户
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd-hh:mm:ss");
List<Customer> cs = mt.find(new Query(
Criteria.where("birthday").gte(sf.parse("2013-06-06-00:00:00"))
.andOperator(Criteria.where("birthday").lte(sf.parse("2013-06-09-23:59:59")))
), Customer.class);
(12)查询定单编号是0015或者0018的客户
List<Customer> cs = mt.find(new Query(new Criteria()
.where("orders.code").in("0015","0018")
), Customer.class);
请注意,mongodb可以直接针对集合查询,比如,上面的orders就是一个set集合。
(13)查询包含四的,并以0结尾的客户
//(正则表 达式,以XX开头,请用^,以XX结束,请用$,不写这两个,表示任意)
List<Customer> cs = mt.find(new Query(new Criteria()
.where("name").regex("四.*0$")
), Customer.class);
请注意,mongodb不支持在id上的正则查询。
(14)修改对象属性名,修改后,要同步修改对象中的属性名,否则,此属性值为null
mt.updateMulti(new Query(), new Update().rename("password", "pwd"), "customer");
(15)批量修改,把id为100的客户姓名改为tomcat999,密码改为222
mt.findAndModify(new Query(Criteria.where("id").is(100)),
new Update().set("name", "tomcat999").set("pwd", "222"),
Customer.class);
(16)修改单个对象
Customer cc = mt.findById(100, Customer.class);
cc.setPwd("333");
mt.save(cc);
(17)排序及分页实现
public Page<Customer> getCustomerByPage(int pageNo, int pageSize, Map params) {
Page<Customer> page = new Page<Customer>(pageNo, pageSize);
//查询数据
List<Customer>data = mt
.find(
new Query().skip(page.getRowStartIndex())
.limit(pageSize)
.with(new Sort(Sort.Direction.DESC, "_id"))
, Customer.class);
page.setData(data);
//统计总记录数
long count = mt.count(null, Customer.class);
page.setRowcounts(count);
return page;
}
最后,给出几个使用mongodb,在对象设计实践:
对象id最好设计成String类型,在新增时,如果用户没有赋值,mongodb会自动生成的,当然你也可以使用UUID自己赋值。
Spring对mongodb的封装在对象间存在循环关联的情况,在新增及查询时都会出现堆栈溢出情况,目前的解决办法是:
A、切断双向关联。比如:一对多双向关联,你可以删除一方的集合属性,多方对一方的引用采用dbref注解标注。一对多、多对多也如此,尽可能地简化对象间的关系。
B、对象间关系,最好直接建立成关系数据库中的外键形式字段,即:以非面向对象的方式去建立,这就是“鱼和熊掌,不可兼得”,在追求性能效率的同时,放弃更好理解的对象模型。
有严格事务要求的业务系统,不要用mongodb。
如有极端的高并发大数据量查询,请用mongodb,也可以把项目中的部分数据保存在mongodb中。
一般的并发修改,可以使用乐观锁解决,spring mongodb支持@Version注销。
还有,开发中最好准备一个图型化的mongodb管理工具,比如:MongoCola,随时查看保存的数据实况,方便调试。