第1章
MongoDB的安装
1.1 MongoDB简介
MongoDB是一个基于分布式文件存储的数据库开源项目。由C++语言编写,旨在为WEB应用提供可护展的高性能数据存储解决方案。
它的特点是可扩展,高性能,易使用,模式自由,存储数据非常方便等。
1.1.1 主要功能特性
a)面向文档存储:(类JSON数据模式简单而强大)。
b)高效的传统存储方式:支持二进制数据及大型对象(如照片和视频)。
c)复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。
d)Auto-Sharding自动分片支持云级扩展性(处于早期alpha阶段):自动分片功能支持水平的数据库集群,可动态添加额外的机器。
e)动态查询:它支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
f)全索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。
g)支持RUBY,PYTHON,JAVA,C++,PHP等多种语言。
1.1.2 适用场景
a)适合实时的插入,更新与查询,并具备应用程序实时数据存储所需的复制及高度伸缩性。
b)适合作为信息基础设施的持久化缓存层。
c)适合由数十或数百台服务器组成的数据库。因为Mongo已经包含对MapReduce引擎的内置支持。
d)Mongo的BSON数据格式非常适合文档化格式的存储及查询。
1.1.3 不适用场景
a)高度事务性的系统。
b)传统的商业智能应用。
c)级为复杂的SQL查询。
1.2 Windows环境安装
1.2.1 下载tar包
mongodb-win32-x86_64-2.4.6。
1.2.2 配置文件
创建log文件夹
md D:\mongodb-win32-x86_64-2.4.6 \log |
创建MongoDB的logpath选项的配置文件:
echo logpath=d:\mongodb-win32-x86_64-2.4.6\log\mongo.log > d:\mongodb-win32-x86_64-2.4.6\mongod.cfg |
1.2.3 手动启动
启动服务
mongod --dbpath d:\mongodb_data 或 mongod --config d:\mongodb-win32-x86_64-2.4.6\mongod.cfg |
1.2.4 服务启动
安装 MongoDB 程序作为Windows 服务。
安装 MongoDB 服务 mongod --config d:\mongodb-win32-x86_64-2.4.6\mongod.cfg --install 运行 MongoDB 服务 net start MongoDB 移除服务 mongod --remove |
1.2.5 REST is not enabled
当出现以下错误时
REST is not enabled. use --rest to turn on. check that
port 28017 is secured for the network too.
解决办法:
使用命令行启动时:
mongod --dbpath d:\mongodb_data --rest --port 27017 |
重新安装系统服务:
mongod --dbpath d:\mongodb_data --config d:\mongodb-win32-x86_64-2.4.6\mongod.cfg --rest --port 27017 --install |
1.3 Linux环境安装
1.3.1 下载包tgz
mongodb-linux-i686-2.4.6.tgz
1.3.2 创建用户
创建用户
adduser mongodb passwd mongodb |
1.3.3 创建数据库文件
创建数据库文件
mkdir -p /data/mongodb_data chown mongodb /data/mongodb_data –R chgrp mongodb /data/mongodb_data -R |
1.3.4 配置文件
创建log文件夹
mkdir /opt/mongodb/mongodb-linux-i686-2.4.6/logs |
创建MongoDB的logpath选项的配置文件:
echo /opt/mongodb/mongodb-linux-i686-2.4.6/bin/mongod --dbpath /data/mongodb_data/
--logpath /opt/mongodb/mongodb-linux-i686-2.4.6/logs/mongodb.log --rest --port 27017 |
1.3.5 手动启动
启动服务
1.3.6 服务启动
安装 MongoDB 程序作为Linux 服务。
安装 MongoDB 服务
echo /opt/mongodb/mongodb-linux-i686-2.4.6/bin/mongod --dbpath
/data/mongodb_data/ --logpath /opt/mongodb/mongodb-linux-i686-2.4.6/logs
/mongodb.log --rest --port 27017–fork >> /etc/rc.local |
1.4 链接数据库
使用命令行方式,并创建student数据库
命令行链接病创建数据库
在Student数据库中,创建user集合,插入一条文档
在Student数据库插入一条数据并查询
db.user.save({username: "limingnihao", nickname: "黎明你好", password: "123456"}) |
1.5 操作命令
1.6 数据类型
ObjectId类型结构:
第2章 MongoDB的增删改查
MongoDB中数据的基本单元叫做文档,采用json的键-值的方式。多个键及其关联的值有序的存放在一起变是文档。类似于编程语言中的键值关系。MongoDB文档都是BSON文档,他是一个JSON的二进制形式。
MongoDB的文档
MongoDB中文档被存储在集合中。集合是一组有关系索引的文档。集合类似于关系数据库中的表。
MongoDB的集合
2.1 方法参考
查询游标方法
2.2 Insert()
db.collection.insert(document) |
Insert()方法有以下行为:
如果该集合不存在,insert()方法将创建集合。
如果文档没有指定一个_id后缀字段,然后 MongoDB 将添加一个_id字段并使用ObjectId为文档分配取值。
如果文档需要增加一个新的字段,则insert()方法可以为文档插入新的字段。这不需要更改集合的数据模型或现有的文档。
db.user.insert({_id: "1", name:{username: "limingnihao", nickname: "黎明你好"}, password: "123456"}) db.user.insert({_id: "2", name:{username: "zhoujielun", nickname: "周杰伦"},
password: "123456", birth: ISODate('1979-01-18')}) db.user.insert({_id: "3", name:{username: "caiyilin", nickname: "蔡依林"},
password: "123456", birth: ISODate('1980-09-15'), special:["看我72变", "花蝴蝶", "特务J"], regionName: "台湾"}) |
2.3 Save()
db.collection.save(document) |
插入一个新的文档,或者根据其文档的参数更新现有的文档。
如果文档不包含一个_id的字段进行save时,mongod将向文档中添加一个_id字段并将其分配一个ObjectId。
如果文档中包含一个_id字段和值进行save ()方法时,则在集合中查询此_id的文档执行的是upsert操作。如果集合中不存在具有指定的_id值的文档,save
()方法执行的是insert操作。save ()方法执行时会将现有文档中的所有字段都替换为新文档中字段。
db.user.save({_id: "1", name:{username: "limingnihao", nickname: "黎明你好"}, password: "123456", birth: ISODate('1985-07-15')}) |
2.4 Update()
db.collection.update( <query>, <update>, <upsert>, <multi> ) |
修改现有存在的文档或集合时使用。
默认的update()方法值更新单个文档。但是如果multi参数设置为true,则更新操作可以更新全部符合条件的文档。
Query – 类型:文档;用于更新选择过滤。
Update – 类型:文档;需要更新的文档的内容。
Upsert – 类型:文档或boolean;设置为true时,当查询没有匹配到文档时进行新建。默认值为false
Multi: - 类型:文档或boolean;设置为true时,则更新满足查询条件的所有文档(多个)。设置为false时只更新单个文档。默认为false。
字段更新操作方式
db.user.update({_id: "1"}, {$inc:{age: 1}}, {multi:true}) db.user.update({_id: "1"}, { $rename: { 'password': 'pwd'}}) db.user.update({_id: "4"}, { $setOnInsert: { works: 5}}, {upsert: true}) db.user.update({_id: "1"}, {$set:{password: "654321", age: 28}}) db.user.update({_id: "4"},{$unset: {"works": 5 }}) |
2.5 Find()
db.collection.find(<criteria>, <projection>) db.collection.findOne(<criteria>, <projection>) |
Criteria - 类型:文档;可选,文档的查询过滤条件。
Projection - 类型:文档,对结果进行字段匹配,{ field1: <boolean>,
field2: <boolean> ... }。
后面还可以:Sort()排序、Limit()限制个数、Skip()起始点。
db.collection.find(<criteria>, <projection>)返回集合 db.collection.findOne(<criteria>, <projection>)返回一个 db.user.find({_id: "1"}) db.user.find({works: 5}) db.user.find().sort({age:1}) db.user.find().limit(2).sort({age:1}) db.user.find().skip(1).limit(2).sort({age:1}) |
2.6 Remove()
db.collection.remove(query, justOne) |
Query – 类型:文档;用于删除选择过滤。
JustOne – 类型:boolean;当设置为true时只删除一个文档。
db.user.remove({_id: "4"}, true) |
2.7 Count()
db.collection.count(<query>) |
Query – 类型:文档;用于查询选择过滤。
2.8 Distinct()
db.collection.distinct(field, query) |
Field – 类型:字符串;返回非重复的字段。
Query – 类型:文档;查询条件。
db.user.distinct("_id", {age: 1}) |
第3章 MongoDB的Java驱动
3.1 下载Java驱动
3.1.1 Jar包
http://central.maven.org/maven2/org/mongodb/mongo-java-driver/
3.1.2 Maven
<dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.10.1</version> <type>jar</type> <scope>compile</scope> </dependency> |
3.2 基本操作
3.2.1 基本操作
String myUserName = "admin"; String myPassword = "admin"; MongoClient mongoClient = new MongoClient("localhost", 27017); // 1.数据库列表 for (String s : mongoClient.getDatabaseNames()) { System.out.println("DatabaseName=" + s); } // 2.链接student数据库 DB db = mongoClient.getDB("student"); mongoClient.setWriteConcern(WriteConcern.JOURNALED); // 3.用户验证 boolean auth = db.authenticate(myUserName, myPassword.toCharArray()); System.out.println("auth=" + auth); // 4.集合列表 Set<String> colls = db.getCollectionNames(); for (String s : colls) { System.out.println("CollectionName=" + s); } // 5.获取摸个集合对象 DBCollection coll = db.getCollection("user"); |
3.2.2 新增
BasicDBObject doc = new BasicDBObject("_id", "6").append("name", new BasicDBObject("username", "limingnihao")
.append("nickname", "黎明你好")).append("password", "123456") .append("password", "123456").append("regionName", "北京").append("works", "5").append("birth", new Date()); WriteResult result = coll.insert(doc); System.out.println("insert-result: " + result); |
3.2.3 查询
// 2.1查询 - one DBObject myDoc = coll.findOne(); System.out.println(myDoc); // 2.2 查询 - 数量 System.out.println(coll.getCount()); // 2.3查询 - 全部 DBCursor cursor = coll.find(); while (cursor.hasNext()) { System.out.println("全部--------" + cursor.next()); } // 2.4查询 - 过滤 - 等于 BasicDBObject query = new BasicDBObject("age", 1); cursor = coll.find(query); while (cursor.hasNext()) { System.out.println("age=1--------" + cursor.next()); } // 2.5查询 - 过滤条件 - 不等于 query = new BasicDBObject("age", new BasicDBObject("$ne", 1)); cursor = coll.find(query); while (cursor.hasNext()) { System.out.println("age!=1" + cursor.next()); } // 2.6查询 - 过滤条件 - 20 < i <= 30 query = new BasicDBObject("age", new BasicDBObject("$gt", 20).append("$lte", 30)); cursor = coll.find(query); while (cursor.hasNext()) { System.out.println("20<age<=30" + cursor.next()); } |
3.2.4 修改
DBObject search = coll.findOne(new BasicDBObject("_id", "5")); BasicDBObject object = new BasicDBObject().append("$set", new BasicDBObject
("password", "1211111")).append("$set", new BasicDBObject("birth", new Date())); WriteResult result = coll.update(search, object, true, true); System.out.println("update-result: " + result); |
3.2.5 删除
DBObject search = coll.findOne(new BasicDBObject("_id", "6")); WriteResult result = coll.remove(search); System.out.println("remove-result: " + result); |
3.3 Java驱动并发
Java MongoDB驱动程序是线程安全的。如果在Web服务器环境中使用,那么应该创建一个MongoClient实例全局使用。MongoClient内部维护了数据库的连接池(默认连接池大小为10)。每次DB请求(查询、插入等)的Java线程将从连接池中获取链接并进行支持,然后释放连接。每次使用连接是不相同的。
在复制(replica)模式下,如果设置slaveOK选项为on,那么读操作会被均匀的分布到各个slave上。这意味着对于同一个线程,一个写操作后紧跟着的一个读操作,有可能被发送到不同的服务器上(写操作发送到master上,读操作发送到slave上),这样读操作有可能不会立刻反映出上一个写操作的数据(因为主从的异步性)。
如果你想要确保在一个session中完整的一致性(例如在一个http请求中),你可能希望java驱动是用同一个socket连接,这时你可以通过使用"consistent
request"来达到目的——在操作前后分别调用requestStart()和requestDone()。
DB和DBCollection完全是线程安全的。事实上,你不管怎么样调用都是同一实例,因为他们进行了缓存。
DB db...; db.requestStart(); try { db.requestEnsureConnection(); code.... } finally { db.requestDone(); } |
在单独写操作上的WriteConcern选项
默认情况下,每次写操作后,连接就被释放回连接池——此时你调用getLastError()是没用的。
所以可以采用两种方式:
1,使用类似WriteConcern.SAFE这样的写策略来代替默认策略,这样java驱动会自动首先调用getLastError(),然后才将连接放回连接池。
DBCollection coll...; coll.insert(..., WriteConcern.SAFE); |
2,采用上述的requestStart()和requestDone()方式来维持连接不被释放,中间调用getLastError()获取错误信息。
DBCollection coll...; coll.insert(..., WriteConcern.SAFE); DB db...; DBCollection coll...; db.requestStart(); try { coll.insert(...); DBObject err = db.getLastError(); } finally { db.requestDone(); } |
第4章 MongoDB整合Spring
4.1.1 repositories
创建maven项目,其中repositories使用spring的maven库:
<repositories> <repository> <id>central</id> <name>Maven Central</name> <url>http://repo1.maven.org/maven2/</url> </repository> <repository> <id>spring-release</id> <name>Spring Maven Release Repository</name> <url>http://repo.springsource.org/libs-release</url> </repository> <repository> <id>atlassian-m2-repository</id> <url>https://m2proxy.atlassian.com/repository/public</url> </repository> </repositories> |
4.1.2 Dependencies
使用到的jar包:
<dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <type>jar</type> <scope>provided</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.1</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.5</version> <type>jar</type> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>2.10.1</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>1.2.1.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb-cross-store</artifactId> <version>1.2.1.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb-log4j</artifactId> <version>1.2.1.RELEASE</version> <type>jar</type> <scope>compile</scope> </dependency> </dependencies> |
4.2 添加spring配置文件
spring的配置文件applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mongo="http://www.springframework.org/schema/data/mongo" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/data/mongo http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="liming.mongodb.example" /> <mongo:mongo host="127.0.0.1" port="27017" /> <!-- mongo的工厂,通过它来取得mongo实例,dbname为mongodb的数据库名,没有的话会自动创建 --> <mongo:db-factory dbname="student" mongo-ref="mongo" /> <!-- mongodb的主要操作对象,所有对mongodb的增删改查的操作都是通过它完成 --> <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"> <constructor-arg name="mongoDbFactory" ref="mongoDbFactory" /> </bean> <!-- 映射转换器,扫描back-package目录下的文件,根据注释,把它们作为mongodb的一个collection的映射 --> <mongo:mapping-converter base-package="climing.mongodb.example.data.model" /> <!-- mongodb bean的仓库目录,会自动扫描扩展了MongoRepository接口的接口进行注入 --> <mongo:repositories base-package="liming.mongodb.example.data.impl" /> <context:annotation-config /> </beans> |
4.3 增删改查
Userl实现的增删改查:
4.3.1 UserEntity
package liming.mongodb.example.data.model; import java.util.Date; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.mapping.Document; @Document(collection = "user") public class UserEntity { @Id private String id; private NameEntity name; private int age; private int works; private Date birth; private String password; private String regionName; private String[] special; public String getId() { return id; } public void setId(String id) { this.id = id; } public NameEntity getName() { return name; } public void setName(NameEntity name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getWorks() { return works; } public void setWorks(int works) { this.works = works; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getRegionName() { return regionName; } public void setRegionName(String regionName) { this.regionName = regionName; } public String[] getSpecial() { return special; } public void setSpecial(String[] special) { this.special = special; } } |
4.3.2 NameEntity
package liming.mongodb.example.data.model; public class NameEntity { private String username; private String nickname; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } } |
4.3.3 UserDaos
package liming.mongodb.example.data; import java.util.List; import liming.mongodb.example.data.model.UserEntity; import org.springframework.transaction.annotation.Transactional; @Transactional public interface UserDao { public abstract void _test(); public abstract void createCollection(); public abstract List<UserEntity> findList(int skip, int limit); public abstract List<UserEntity> findListByAge(int age); public abstract UserEntity findOne(String id); public abstract UserEntity findOneByUsername(String username); public abstract void insert(UserEntity entity); public abstract void update(UserEntity entity); } |
4.3.4 UserDaoImpl
package liming.mongodb.example.data.impl; import java.util.List; import java.util.Set; import liming.mongodb.example.data.UserDao; import liming.mongodb.example.data.model.UserEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.data.mongodb.core.query.Update; import org.springframework.stereotype.Repository; import com.mongodb.DB; @Repository public class UserDaoImpl implements UserDao { public static final Logger logger = LoggerFactory.getLogger(UserDaoImpl.class); @Autowired private MongoTemplate mongoTemplate; @Override public void _test() { Set<String> colls = this.mongoTemplate.getCollectionNames(); for (String coll : colls) { logger.info("CollectionName=" + coll); } DB db = this.mongoTemplate.getDb(); logger.info("db=" + db.toString()); } @Override public void createCollection() { if (!this.mongoTemplate.collectionExists(UserEntity.class)) { this.mongoTemplate.createCollection(UserEntity.class); } } @Override public List<UserEntity> findList(int skip, int limit) { Query query = new Query(); query.with(new Sort(new Order(Direction.ASC, "_id"))); query.skip(skip).limit(limit); return this.mongoTemplate.find(query, UserEntity.class); } @Override public List<UserEntity> findListByAge(int age) { Query query = new Query(); query.addCriteria(new Criteria("age").is(age)); return this.mongoTemplate.find(query, UserEntity.class); } @Override public UserEntity findOne(String id) { Query query = new Query(); query.addCriteria(new Criteria("_id").is(id)); return this.mongoTemplate.findOne(query, UserEntity.class); } @Override public UserEntity findOneByUsername(String username) { Query query = new Query(); query.addCriteria(new Criteria("name.username").is(username)); return this.mongoTemplate.findOne(query, UserEntity.class); } @Override public void insert(UserEntity entity) { this.mongoTemplate.insert(entity); } @Override public void update(UserEntity entity) { Query query = new Query(); query.addCriteria(new Criteria("_id").is(entity.getId())); Update update = new Update(); update.set("age", entity.getAge()); update.set("password", entity.getPassword()); update.set("regionName", entity.getRegionName()); update.set("special", entity.getSpecial()); update.set("works", entity.getWorks()); update.set("name", entity.getName()); this.mongoTemplate.updateFirst(query, update, UserEntity.class); } } |
4.3.5 测试代码
package liming.mongodb.example; import java.util.Arrays; import java.util.Date; import java.util.List; import liming.mongodb.example.data.UserDao; import liming.mongodb.example.data.impl.UserDaoImpl; import liming.mongodb.example.data.model.UserEntity; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class ApplicationSpring { public static void main(String[] args) { System.out.println("Bootstrapping HelloMongo"); ConfigurableApplicationContext context = null; context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserDao userDao = context.getBean(UserDaoImpl.class); userDao._test(); UserEntity entity1 = new UserEntity(); entity1.setId("5"); entity1.setAge(1); entity1.setBirth(new Date()); entity1.setPassword("asdfasdf"); entity1.setRegionName("北京"); entity1.setWorks(1); userDao.insert(entity1); userDao.update(entity1); userDao.createCollection(); List<UserEntity> list = userDao.findList(0, 10); for (UserEntity e : list) { System.out.println("all - id=" + e.getId() + ", age=" + e.getAge() + ",
password=" + e.getPassword() + ", regionName=" + e.getRegionName() + ", special=" + Arrays.toString(e.getSpecial())
+ ", name=" + e.getName().getUsername() + "-" + e.getName().getNickname() + ", birth=" + e.getBirth()); } list = userDao.findListByAge(1); for (UserEntity e : list) { System.out.println("age=1 - id=" + e.getId() + ", age=" + e.getAge() + ",
password=" + e.getPassword() + ", regionName=" + e.getRegionName() + ", special=" + Arrays.toString(e.getSpecial())
+ ", name=" + e.getName().getUsername() + "-" + e.getName().getNickname() + ", birth=" + e.getBirth()); } UserEntity e = userDao.findOne("1"); System.out.println("id=1 - id=" + e.getId() + ", age=" + e.getAge() + ", password=" + e.getPassword() + ",
regionName=" + e.getRegionName() + ", special=" + Arrays.toString(e.getSpecial()) + ", name=" + e.getName().getUsername() + "-" + e.getName().getNickname() + ", birth=" + e.getBirth()); e = userDao.findOneByUsername("limingnihao"); System.out.println("username=limingnihao - id=" + e.getId() + ", age=" + e.getAge() + ",
password=" + e.getPassword() + ", regionName=" + e.getRegionName() + ", special=" + Arrays.toString(e.getSpecial()) + ",
name=" + e.getName().getUsername() + "-" + e.getName().getNickname() + ", birth=" + e.getBirth()); System.out.println("DONE!"); } } |
|