1.大数据定义:
数据量级大 byte kb MB GB TB PB ...
数据种类多 数据维度 例如:人物画像
数据处理速度快
数据有价值
问题:①.存储 ? ②.数据分析? ③.高并发?
大数据应用领域: 电商(推荐) 广告栏位,交通,医疗
维度优化:
①X轴 服务水平拓展
②Y轴 业务垂直拆分 SOA
③Z轴 对使用群体分区(地域性)(多游戏)
==============================================
NoSQL :not noly sql 为什么?
RDBMS:比较擅长 关系、事务 (约束) 快速 写 不擅长
基于磁盘存储 速度慢 高效 读写
大都数 数据库 都是 单点存储 不支持 水平拓展
NoSQL:
1.schemaless 弱化表结构 没有表结构
2.in-memory 基于内存--redis
3.支持Cluster 集群 副本集合 分片
4.弱化事务 mongoDB不支持事务
5.支持脚本 mongodb javascript脚本 redisCluster ruby脚本
总结:NoSQL作为 RMDBS 补充 相辅相成。
==============================================
【MongoDB】:
1.NoSQL数据库 不支持 事务
2.MongoDB 单条记录 不得超过16M
3.没有表结构 基于 BSON/json 存储
t_user (RDBMS) 缺点 : 磁盘利用率低 IO利用率低
id name sex info ....
1 张三 null 逗你玩 记录(null值占用空间)
2 李四 null null
3 王五 false null
4 赵六 null null
t_user[] (MongoDB)集合 没有表结构
[
{id:1,name:"张三",info:"逗你玩"},
{id:2,name:"李四"},
{id:3,name:"王五",sex:false},
{id:4,name:"赵六"},
{id:5,name:"win7",hobbies:["看电视","打游戏"]},
{id:6,name:"win8",hobbies:"敲代码"]}
]
MongoDB安装:
1.将mongodb解压到/usr
2.创建dbpath
mkdir -p /root/data/db
3.在mongodb文件下启动mongodb
./bin/mongod --port 27017 --dbpath /root/data/db/ --journal
4.新建窗口在mongodb文件下连接mongoDB
./bin/mongo --port 27017 --host 192.168.100.128
数据操作
>show databases/dbs
>use 数据库名 切换数据库
>db 查看
>db.dropDatabase() 删除数据库
更多请查看 db.help();
表:
创建:db.createCollection("表名");
查看:show tables/collections
...
任务:
1.权威指南 2,3,4,5,6 章节
2.了解mongo-java-driver javaAPI 不讲解
----------------------------------------------------------------------------------------------------------------------------
复习:
MongoDB的常见操作
1.创建表/collection
(1).方式 :db.createCollection("collectionName");
(2).隐式: db.'collectionName'.insert(document);
2.查看表: show collections/tables;
3.删除表:db.'collectionName'.drop();
添加:
db.user.insert/save(json);
注意:如果数据表collection不存在就会创建。
id name sex birth ...
1 zs null
2 ww 男 1990-01-01
删除:
db.users.remove({})
根据条件进行删除的命令是:db.user.remove({age:31});
更新:
①:MongoDB中没有更新,事实上是先删除在添加
var jeo=db.user.findOne({});
delete jeo.age;
db.user.update(查询,更新的文档);
②修改器 $set ,$inc ,$unset
db.users.update(query,{$set:{sex:true}}, { "upsert" : true, "multi" : true });
//将name键删除
db.users.update(query,{$unset:{name:true}}, { "upsert" : true, "multi" : true });
附加说明:
upsert:表示按照查询条件修改数据,如果没有匹配 执行 插入操作
multi:表示 如果按照条件查询,查到多条记录后是否执行批量修改
db.t_user.update({name:"win7"},{$inc:{age:1}},{ "upsert" : true, "multi" : true });
数组的修改:
db.t_user.update({ name: "win7" },{$set: {address:[]}},false,true);
db.t_user.update({ name: "win7" },{$push: {address:"北京"}},false,true);
一次更新多个数据
db.t_user.update({ name: "win7" },{$push: {address:{$each:["北京","上海"]}}},false,true);
避免重复插入
db.user.update({ name: "zs" },{$addToSet: {address:{"$each":["北京","深圳","上地"]}}},false,true);
删除指定元素 pop/pull
db.user.update({ name: "zs" },{$pop: {address:1}},false,true); //1表示弹出第一个元素 -1 表示弹出最后一个元素
db.user.update({ name: "zs" },{$pull: {address:"北京"}},false,true);//删除指定元素
查询:
1.查询一条
document <—— db.user.findOne(查询条件);
2.查询多条
DBCursor <—— db.user.find();
db.user.find({});
3.条件查询
(1)等值 ==
db.user.find({name:"张三"});
db.user.find({name:{$eq:"张三"}});
(2)且 AND
db.user.find({name:"张三",age:18});
(3)或 $or/$nor
db.user.find({ "$or" : [{ "name" : "张三" }, { "age" : 20 }] });
db.user.find({ "$nor" : [{ "name" : "zhangsan" }, { "age" : 20 }] });
(4) 不等值 > < <= >= != ! $gt $lt $lte $gte $ne $not
①db.user.find({ "age" : { "$gt" : 15, "$lt" : 30 } })
②db.user.find({ "name" : { "$ne" : "zhangsan" } })
(5) $in/$nin
db.user.find({ "id" : { "$in" : [1, 2, 3] } });
(6) 数组查询
大小查询 $size
db.t_fruit.find({ "fruit" : { "$size" : 3 } });
下标查询
db.fruit.find({ "fruit.1" : "apple"});
判断元素是否包含
db.fruit.find({ "fruit" :{"$all":["apple","banana"]}});
(7) $exists 判断是否有key 1/true表示存在 0/false 表示 不存在
db.user.find({"sex":{ "$exists" : 0 }});
(8) 投影查询 0/false表示显示 1/true 表示不显示
db.t_user.find({},{"name":true});
(9) 查询总记录数
db.t_user.count()
db.fruit.find({}).count(); 返回符合query查询结果
db.fruit.find({}).size(); 返回实际的document个数
(10) 数据分页 skip limit
db.fruit.find({ }).skip(1).limit(50); //查询从第一条开始 查询50条记录
(11) 排序
db.fruit.find({ }).sort({id:1});根据ID升序排列 1表示升序 -1 降序
(12 )正则搜索
db.t_user.find({name:{$regex:"^张三$"}})
(13)where 查询
db.user.find({ "$where" : "function aa(){
\r\n print(this.name);
\r\n if(this.name==\"张三\"){
\r\n return true;\r\n
}
\r\n return false;
\r\n}"
})
db.t_user.find({name:{$eq:"张三"},$where:"(this.id<4)?false:true"})
======================================================
索引:
db.users.ensureIndex({name:1},[options]) _id这个key mongo自动加入索引
索引创建:db.users.ensureIndex({name:1})
db.t_user.ensureIndex({ "name" : 1 },{ "name" : "name_index" });
查看索引:db.t_user.getIndexes();
删除索引:db.t_user.dropIndex("name_index");
索引重建:db.users.reIndex()
唯一索引:db.users.ensureIndex({"username" : 1}, {"unique" : true})//此时不可以为该域添加重复的值
稀疏索引:db.users.ensureIndex({"name" : 1}, {"unique" : true, "sparse" : true})//主要对null值处理,允许多个null值存在,不认为违反unique
TTL索引:db.users.ensureIndex({"last_modify" : 1}, {"expireAfterSecs" : 60})//定时清除过期数据 该索引必须建立在日期类型的field上
=====================================================
MapReduce数据统计 计算:
db.students.insert({classid:1, age:14, name:'张三'});
db.students.insert({classid:1, age:12, name:'李四'});
db.students.insert({classid:2, age:16, name:'王五'});
db.students.insert({classid:2, age:9, name:'赵六'});
db.students.insert({classid:2, age:19, name:'win7'});
var map=function() {
emit(this.classid,{age:this.age,classid:this.classid,name:this.name})
}
var reduce=function (key,values) {
var x ={classid:-1,username:[],total:0};
var total=0;
values.forEach(function (v) {
x.classid = v.classid;
total++;
x.username.push(v.name);
});
x .total=total;
return x;
}
db.students.mapReduce( map, reduce,{out:"students_res"})
或者
var res = db.runCommand({
mapreduce:"students",
map:map,
reduce:reduce,
out:"students_res"
});
===========================================
*辅线 Mongo集群管理
主从:
Master/slave options (old; use replica sets instead):
--master master mode
--slave slave mode
--source arg when slave: specify master as
--only arg when slave: specify a single database to replicate
--slavedelay arg specify delay (in seconds) to be used when applying master ops to slave
--autoresync automatically resync if slave data is stale
查看主从状况:
: rs.help();查看集群状态
主机:./bin/mongod --port 27017 --dbpath /root/master --journal --master
从机:./bin/mongod --port 27018 --dbpath /root/slave --journal --slave --source 192.168.100.128:27017 [--only zpark --autoresync]
查看 slave 必须执行 rs.slaveOk() 允许在secondary节点上执行查询
可以执行db.isMaster();查看当前服务状态。
【缺点】:
1.无法实现 自动的 故障转移 auto_faliover,如果主机宕机,需要关闭slave并且按照master模式启动
2.无法解决海量数据存储
-----------------------------------------------------------------------------------------------------------
副本集:(主从 升级版 仅仅解决的是第一问题 )
1.在root文件夹创建repl1/repl2/repl3
2.在mongodb文件下执行启动
./bin/mongod --port 27017 --dbpath /root/repl1 --replSet r1
./bin/mongod --port 27018 --dbpath /root/repl2 --replSet r1
./bin/mongod --port 27019 --dbpath /root/repl3 --replSet r1
3.链接任意一台mongo
var config = {
_id:"r1",
members:[
{_id:0,host:"192.168.17.130:27017"},
{_id:1,host:"192.168.17.130:27018"},
{_id:2,host:"192.168.17.130:27019"}]
}
//初始化配置文件
rs.initiate(config);
rs.isMaster() / rs.status();
①.添加一个副本集
./bin/mongod --port 27010 --dbpath /root/repl4 --replSet r1
rs.add("192.168.100.128:27010");//添加一个节点
②.删除一个副本集:
rs.remove("192.168.100.128:27010");
③.添加仲裁arbiter节点: 该节点只负责选举主节点不负责做数据的存储
rs.add({_id:3,host:"192.168.17.130:27020",arbiterOnly:true});
==》等价rs.addArb("192.168.100.128:27010");
阻止Secondary节点成为Primary 设置该节点的priority=0
cfg=rs.config();
cfg.members[1].priority=0
rs.reconfig(cfg);
④.添加一个hidden节点 该节点不会成为primary以及被客户端引用
cfg=rs.config();
cfg.members[1].priority=0
cfg.members[1].hidden=true
rs.reconfig(cfg);
⑤.延迟复制节点(延迟节点的优先级必须为0和hidden节点是一样的) 一般都会设置hidden
cfg=rs.config();
cfg.members[1].priority=0
cfg.members[1].slaveDelay=3600//单位是秒
rs.reconfig(cfg);
⑥.SecondaryOnly节点
Priority为0的节点永远不能成为主节点,所以设置Secondaryonly节点只需要将其priority设置为0.
⑦.设置Non-Voting节点:
cfg=rs.conf();
cfg.members[0].votes=0;
rs.reconfig(cfg);
注意:MongoDB的副本级别最大上限是17个,但最多只能有7个节点具有投票权。所以如果超过7个以后的节点,一般分配为Non-Voting
副本集状态
STARTUP:刚加入到复制集中,配置还未加载
STARTUP2:配置已加载完,初始化状态
RECOVERING:正在恢复,不适用读
ARBITER: 仲裁者
DOWN:节点不可到达
UNKNOWN:未获取其他节点状态而不知是什么状态,一般发生在只有两个成员的架构,脑裂
REMOVED:移除复制集
ROLLBACK:数据回滚,在回滚结束时,转移到RECOVERING或SECONDARY状态
FATAL:出错。
PRIMARY:主节点
SECONDARY:备份节点
【缺点】:海量数据存储
====================================================
分片:配置服务器 路由服务器 shard服务器
./bin/mongod --port 27017 --dbpath /root/shard1 --journal --shardsvr
./bin/mongod --port 27018 --dbpath /root/shard2 --journal --shardsvr
./bin/mongod --port 27019 --dbpath /root/config --journal --configsvr
./bin/mongos --port 27020 --configdb 192.168.17.129:27019
--连接路由服务器
mongo --port 27020
use admin
sh.addShard("192.168.100.128:27017");
sh.addShard("192.168.100.128:27018");
sh.enableSharding("zpark");//对zpark数据库分片
//表示对_id 做分片处理(2选1)
sh.shardCollection("zpark.t_user1", {"_id" : 1});
sh.shardCollection("zpark.t_user2", {"_id": "hashed" })
use zpark;
插入测试数据
for(var i=0; i<10000; i++){
db.t_user1.insert({name:"user"+i, age:i, email:"[email protected]" })
}
for(var i=0; i<10000; i++){
db.t_user2.insert({name:"user"+i, age:i, email:"[email protected]" })
}
查看状态:db.'collectionName'.stats()
==========================================================================
解释:
shard服务器个数决定数据库存储能力(副本集)--至少需要两个shard服务器 即生产环境下至少需要机器(2*3)台
config servers存储shard位置信息(3台)
路由服务器(1台) 伪装成一个MongoDB实例 接收用户发送过来的请求
最终版:副本集+分片 搭建mongo的集群
shard1
./bin/mongod --port 27017 --dbpath /root/data/shard11 --journal --replSet r1 --shardsvr
./bin/mongod --port 27018 --dbpath /root/data/shard12 --journal --replSet r1 --shardsvr
./bin/mongod --port 27019 --dbpath /root/data/shard13 --journal --replSet r1 --shardsvr
副本集跑起来
连接任意一台mongo
./bin/mongo --port 27019 --host 192.168.17.130
var config = {
_id:"r1",
members:[
{_id:0,host:"192.168.17.130:27017"},
{_id:1,host:"192.168.17.130:27018"},
{_id:2,host:"192.168.17.130:27019"}]
}
rs.initiate(config);
shard2
./bin/mongod --port 27020 --dbpath /root/data/shard21 --journal --replSet r2 --shardsvr
./bin/mongod --port 27021 --dbpath /root/data/shard22 --journal --replSet r2 --shardsvr
./bin/mongod --port 27022 --dbpath /root/data/shard23 --journal --replSet r2 --shardsvr
副本集跑起来
连接任意一台mongo
./bin/mongo --port 27022 --host 192.168.17.130
var config = {
_id:"r2",
members:[
{_id:0,host:"192.168.17.130:27020"},
{_id:1,host:"192.168.17.130:27021"},
{_id:2,host:"192.168.17.130:27022"}]
}
rs.initiate(config);
启动配置服务器:(目前版本3.0.6不支持将配置服务器搭建为副本集,最新版可以)
./bin/mongod --port 27023 --dbpath /root/data/config1 --journal --configsvr
./bin/mongod --port 27024 --dbpath /root/data/config2 --journal --configsvr
./bin/mongod --port 27025 --dbpath /root/data/config3 --journal --configsvr
启动路由:
//把三台配置服务器添加进路由服务器
./bin/mongos --port 27026 --configdb 192.168.17.130:27023,192.168.17.130:27024,192.168.17.130:27025
连接路由服务器
./bin/mongo --port 27026
use admin
sh.addShard("r1/192.168.17.130:27017,192.168.17.130:27018,192.168.17.130:27019");
sh.addShard("r2/192.168.17.130:27020,192.168.17.130:27021,192.168.17.130:27022");
sh.enableSharding("baizhi");//对baizhi数据库分片
//表示对_id 做分片处理(方式2选1)
sh.shardCollection("baizhi.t_user", {"_id" : 1});//先由一个副本集存放数据,快满时启用下个副本集
sh.shardCollection("baizhi.t_address", {"_id": "hashed" });//副本集平均分布
插入测试数据
for(var i=0; i<10000; i++){
db.t_user .insert({name:"user"+i, age:i, email:"[email protected]" })
}
for(var i=0; i<10000; i++){
db.t_address .insert({name:"user"+i, age:i, email:"[email protected]" })
}
查看状态:db.user.stats()
【注意】:集群搭建后,数据库建立索引需通过数据库,不能在代码中建立索引
=========================================================================
SpringData-MongoDB
①.导jar包
Spring-jar、
mongo-java-driver-2.14.3.jar
spring-data-commons-1.12.5.RELEASE.jar
spring-data-mongodb-1.9.5.RELEASE.jar
②. applicationContext.xml
< 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:aop ="http://www.springframework.org/schema/aop"
xmlns:mvc ="http://www.springframework.org/schema/mvc"
xmlns:tx= "http://www.springframework.org/schema/tx"
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-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd" >
③.实体类
package com.baizhi.entity;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Document(collection="t_user") //指明存入数据库后对应的文档
public class User implements Serializable {
@Id//默认情况下,mongo的主键只能是String、BigInteger、ObjectId
private String id;
//给name字段设置索引,唯一、稀疏索引(针对null)
@Indexed(name="name_index",unique=true,sparse=true) //搭建集群后不能在此处设置索引
private String name;
private int age;
@Field(value="u_sex")//给数据库字段起别名
private boolean sex;
@DBRef(lazy=true)
private City address;
//使用到的时候,才会给该属性赋值
@DBRef(lazy=true)
private List orderItems;
@PersistenceConstructor //数据库利用该构造方法将查询结果封装为对象 (要有set方法)
public User(String name, int age, boolean sex) {
super();
this.name = name;
this.age = age;
this.sex = sex;
}
public User() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public City getAddress() {
return address;
}
public void setAddress(City address) {
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public List getOrderItems() {
return orderItems;
}
public void setOrderItems(List orderItems) {
this.orderItems = orderItems;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", address=" + address
+ ", age=" + age + ", orderItems=" + orderItems + "]";
}
}
package com.baizhi.entity;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.PersistenceConstructor;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection="t_orderitem")
public class OrderItem implements Serializable {
@Id
private String id;
private String name;
private int count;
@PersistenceConstructor
public OrderItem(String name, int count) {
super();
this.name = name;
this.count = count;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public String toString() {
return "OrderItem [id=" + id + ", name=" + name + ", count=" + count
+ "]";
}
}
④测试代码
package com.baizhi.test;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
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 com.baizhi.entity.City;
import com.baizhi.entity.OrderItem;
import com.baizhi.entity.User;
import com.mongodb.Mongo;
public class Demo {
private Mongo mongo;
private MongoTemplate mongoTemplate;
@Before
public void before(){
ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
mongo = (Mongo) ac.getBean("mongo");
mongoTemplate = (MongoTemplate) ac.getBean("mongoTemplate");
}
@Test
public void test8(){
for (int i = 0; i < 10000; i++) {
User user = new User("a"+i,i,true);
user.setAddress(null);
user.setOrderItems(null);
mongoTemplate.insert(user);
}
}
@Test
public void test(){
User user = new User("张三",18,true);
mongoTemplate.insert(user);
System.out.println(user);
}
@Test
public void test1(){
User user = mongoTemplate.findById("58c8e2696f5799eb36d4e83e", User.class);
System.out.println(user);
}
@Test
public void testSave(){
double[] a = new double[]{1.1,2.2};
User user=new User("马腾",18,false);
City city = new City("北京",a);
user.setAddress(city);
List orderItems=Arrays.asList(
new OrderItem("hadoop权威指南", 1),
new OrderItem("MongoDB权威指南",1));
user.setOrderItems(orderItems);
//先保存地址、订单项 再保存用户
mongoTemplate.save(city);
for (OrderItem orderItem : orderItems) {
mongoTemplate.save(orderItem);
}
mongoTemplate.save(user);
}
@Test
public void testQueryUserById(){
User user = mongoTemplate.findById("58c8e5376f57cac13e322036", User.class);
//获取的是代理对象@DBRef(lazy=true)
List orderItems = user.getOrderItems();
for (OrderItem orderItem : orderItems) {
System.out.println(orderItem);
}
}
@Test
public void testQueryAll(){
List users = mongoTemplate.findAll(User.class);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void testQuery(){
Query query = new Query();
Criteria criteria = new Criteria("name");
criteria.is("刘备");
query.addCriteria(criteria);
List find = mongoTemplate.find(query, User.class);
System.out.println(find);
}
@Test
public void testQueryByPage(){
Query query = new Query();
query.skip(5);
query.limit(10);
List list = mongoTemplate.find(query, User.class);
for (User user : list) {
System.out.println(user);
}
}
@Test
public void testQueryByOrder(){
Query query = new Query();
Sort sort = new Sort(Direction.ASC,"age");
query.with(sort);
List list = mongoTemplate.find(query, User.class);
for (User user : list) {
System.out.println(user);
}
}
@Test
public void testRemove(){
Query query = new Query();
Criteria criteria = new Criteria("name");
criteria.is("张三");
query.addCriteria(criteria);
mongoTemplate.remove(query, User.class);
}
@Test
public void testUpdateMulit(){
Query query = new Query();
Criteria criteria = new Criteria("sex");
criteria.is(false).and("age").gte(25);
/*Criteria criteria = new Criteria("name");
criteria.is("赵六");*/
query.addCriteria(criteria);
Update update = new Update();
update.set("age", 31);
mongoTemplate.upsert(query, update, User.class);
}
}