目录
MySQL
创建数据库
- 创建数据库:
CREATE DATABASE db1;
CREATE SCHEMA db1;
- 指定数据库:
USE db1;
- 显示当前使用的数据库:
SELECT DATABASE();
- 创建表:
- CREATE TABLE 表名(列名1 数据类型1,列明2 数据类型2......);
CREATE TABLE tb1 (empid VARCHAR(10),name VARCHARF(10),age INT);
- 或
CREATE TABLE tb1 (empid VARCHAR(10),name VARCHARF(10),age INT) CHARSET=utf8;
- 显示表:
SHOW TABLES;
- 表的列结构:
DESC 表名
;
- 插入数据:
INSERT INTO 表名 VALUES (数据1,数据2);
- 指定列插入数据:
INSERT INTO tb1 (列名1,列名2...) VALUES (数据1,数据2...);
- 显示数据:
SELECT 列名1,列名2... FROM 表名;
SELECT * FROM 表名;
- 查看系统用户:
SELECT user FROM user;
数据类型
序号 |
数据类型 |
取值范围 |
1 |
INT(整数) |
-2147483648 ~ 2147483647 |
2 |
TINYINT(极短整数) |
-128 ~ 127 |
3 |
SMALLINT(短整数) |
-32768 ~ 32767 |
4 |
MEDIUMINT(中等整数) |
-8388608 ~ 8388607 |
5 |
BIGINT(大整数) |
-9223372036854775808 ~ 9223372036854775807 |
6 |
FLOAT(单精度) |
-3.402823466E+38 ~ 3.402823466E+38 |
7 |
DOUBLE(双精度) |
-1.7976931348623157E+308 ~ 1.7976931348623157E+308 |
8 |
DECIMAL(精确小数) |
DECIMAL(最大位数<65,小数点后位数<30) |
序号 |
数据类型 |
取值范围(字符) |
1 |
CHAR(固定长度字符串) |
255 |
2 |
VARCHAR(可变长度字符串) |
1 ~ 65532 |
3 |
TEXT(长文本字符串) |
65535 |
4 |
LONGTEXT(极长文本字符串) |
4294967295 |
序号 |
数据类型 |
取值范围 |
1 |
DATETIME(日期和时间) |
1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 |
2 |
DATE(日期) |
1000-01-01 ~ 9999-12-31 |
3 |
YEAR(年) |
1901 ~ 2155 |
4 |
TIME(时间) |
-838:59:59 ~ 838:59:59 |
修改表
表字符集修改:ALTER TABLE ... DEFAULT CHARACTER SET UTF8;
- 修改列的数据类型:
ALTER TABLE 表名 MODIFY 列名 数据类型;
- 添加列:
ALTER TABLE 表名 ADD 列名 数据类型;
- 指定位置添加:FIRST , AFTER ...
- 修改列的顺序:
ALTER TABLE ... MODIFY ... ... FIRST/AFTER ...;
- 修改列名和数据类型:
ALTER TABLE 表名 CHANGE 修改前的列名 修改后的列名 修改后的数据类型 (CHARACTER SET UTF8);
- 删除列:
- 设置键:
- 主键:列的特殊属性 ---> 没有重复的值,不允许输入空值、
CREATE TABLE 表名 (列名 数据类型 PRIMARY KEY,... ...);
- 唯一键:标注列为不可重复属性 ---> 允许输入空值,但不许重复
CREATE TABLE 表名 (列名 数据类型 UNIQUE,... ...);
- 自动连续编号:
- 数据类型为INT等整型
- 数据类型加AUTO_INCREMENT关键字
- 设置PRIMARY KEY
- 插入记录:
- 编号初始化:
ALTER TABLE 表名 AUTO_INCREMENT=1;
- 设置列的默认值:
CREATE TABLE 表名 (列名 数据类型 DEFAULT 默认值...);
ALTER TABLE 表名 MODIFY 列名 数据类型 DEFAULT 默认值;
- 索引:
- 设置了主键时,索引会自动创建
- 创建索引:
CREATE INDEX 索引名 ON 表名(列名);
- 显示索引:
SHOW INDEX FROM 表名;
复制/删除表
- 复制列结构和数据:
CREATE TABLE 新表名 SELECT * FROM 元表名;
- 不会复制AUTO_INCREMENT属性
- 复制表列结构:
CREATE TABLE 新表名 LIKE 元表名;
- 复制表的数据:
INSERT INTO 表名 SELECT * FROM 元表名;
- 选择某一列进行复制:
INSERT 表名(列名) SELECT 元列名 FROM 元表名;
- 删除表:
DROP TABLE 表名;
- 表存在时删除:
DROP TABLE IF EXISTS 表名;
- 删除数据库:
- 删除表中记录:
条件提取
- 使用别名:
- 列计算:
- ‘+’、‘-’、‘*’、‘/’、‘DIV’、‘%’或MOD
SELECT a/b FROM 表名;
函数
- 函数计算:
- 函数:
- 平均:AVG()
- 求和:SUM()
- 计数:COUNT()
SELECT AVG(列名) FROM 表名;
- 显示信息:
- PI: PI()
- MYSQL版本: VERSION()
- 当前使用数据库: DATABASE()
- 当前用户: USER()
- 字符编码:CHARSET('...')
SELECT PI();
- 字符串函数:
- 连接字符串:
SELECT CONCAT(... , ... , ...) FROM 表名;
- 从右取出:RIGHT(列名,a) ---> 取出该列最右边的a个字符
- 从左取出:LEFT(列名,a)
- 截取字符:SUBSTRING(列名,a,b) ---> 取出第a个字符开始的连续b个字符
- 重复字符:REPEAT('...',列名) ---> 重复显示字符,重复次数为列的值
- 反转字符:REVERSE(列名) ---> 将列中的字符反转显示
- 日期和时间函数:
条件显示
排序
- 升序:
SELECT 列名 FROM 表名 ORDER BY 排序列 ASC
- 降序:
SELECT 列名 FROM 表名 ORDER BY 排序列 DESC
- 记录的显示范围:从第a+1条记录开始显示b条记录
SELECT 列名 FROM 表名 LIMIT b OFFSET a;
分组显示
- 分组:
SELECT 列名 FROM 表名 GROUP BY 用于分组的列名;
- 各组的记录数:
SELECT 列名,COUNT(*) FROM 表名 GROUP BY ...;
- 分组显示:
- 分组后提取记录:
SELECT 统计列 FROM 表名 GROUP BY 分组列 HAVING 条件;
SELECT empid,SUM(sales) FROM tb GROUP BY empid HAVING SUM(sales)>=200;
- 满足条件的分组会显示出来
- 提取记录后分组:
SELECT 统计列 FROM 表名 WHERE 条件 GROUP BY 分组列;
- 分组后排序:先写GROUP BY,再写ORDER BY
- GROUP BY函数:MAX,AVG,SUM
编辑数据
- 修改列的记录:
UPDATE 表名 SET 列名 = 值 WHERE 条件;
- 排序并修改前3个:
UPDATE tb SET ... = ... ORDER BY sales LIMIT 3;
- 删除指定记录:
DELETE FROM 表名 WHERE 条件;
多表
- 合并记录:
SELECT 列名1 FROM 表名1 UNION SELECT 列名2 FROM 表名2;
- 允许重复:
UNION ALL
- 内联:
SELECT 列名 FROM 表1 INNER JOIN 表2 ON 表1.列=表2.列;
- 在两个表连接的列名相同时可使用
USING(列名)
代替
- 在最后可添加WHERE限制条件
- 只会提取与连接键相匹配的记录
- 外联:
- 左连接:显示相匹配的记录和左表中的全部记录
SELECT 列名 FROM 表1 LEFT JOIN 表2 ON 表1.列=表2.列;
- 右连接:
SELECT 列名 FROM 表1 RIGHT JOIN 表2 ON 表1.列=表2.列;
- 自联:
- 自连接:
SELECT 列名 FROM 表名 AS 别名1 JOIN 表名 AS 别名2;
- 排序:
SELECT a.empid,COUNT(*) FROM tb1 AS a JOIN tb1 AS b WHERE a.age<=b.age GROUP BY a.empid;
- 注:MySQL5.7以上的版本默认'ONLY_FULL_GROUP_BY',即SELECT后的参数要在GROUP BY中出现,需要配置my.ini来取消
- 子查询:
SELECT ... FROM ... WHERE ... IN (SELECT ... FROM ...);
- EXISTS/NOT EXISTS:WHERE EXISTS/WHERE NOT EXISTS
视图
- 创建视图:
CREATE VIEW 视图名 AS SELECT 列名 FROM 表名 WHERE 条件;
- 修改视图:
UPDATE 视图名 SET ... = ...;
- 修改视图也会修改表
- 修改表时,视图也同样会进行相应更新(包括视图是从表中条件提取的情况)
- 限制INSERT:当插入数据与条件不匹配时报错 ---> 最后加上WITH CHECK OPTION
- 替换视图:
CREATE OR REPLACE VIEW 要替换的视图名 AS SELECT ......;
- 修改视图结构:
ALTER VIEW 视图名 AS SELECT 列名 FROM 表名;
- 删除视图:
- 主从库复制:
- 异步(默认)
- 半同步(从库会发送响应信息)
- 无损半同步(主库接受到从库的响应信息后才写入修改)
存储
- 存储过程:将多个SQL语句组合成一个使用CALL就能执行的集合
将分隔符;换为//
delimiter //
CREATE PROCEDURE 存储过程名()
BEGIN
SQL语句1
SQL语句2;
......
END
//
delimiter ;
复原分隔符
- 执行:
CALL 存储过程名;
- 带参数存储:
CREATE PROCEDURE 存储过程名 (参数名 数据类型);
- 显示存储过程:
SHOW CREATE PROCEDURE 存储过程名;
- 删除存储过程:
- 存储函数:
delimiter //
CREATE FUNCTION 存储函数名 (参数 数据类型) RETURNS 返回值的数据类型
BEGIN
SQL语句......;
RETURN 返回值/表达式
END
//
delimiter ;
- 显示存储函数:
SHOW CREATE FUNCTION 存储函数名;
- 删除存储函数:
- 触发器:对表执行某种操作后会触发执行其它命令的机制
CREATE TRIGGER 触发器名 BEFORE (或者AFTER) DELETE 等命令
ON 表名 FRO EACH NOW
BEGIN
使用更新前 (OLD.列名) 或者更新后 (NEW.列名) 的处理
END
事务
- 存储引擎:
- MyISAM --- 高速运行,但不支持事务和外键
- InnoDB --- 默认引擎,唯一支持事务的引擎
- BLACKHOLE --- 写入的数据会消失,查询返回空结果。用于复制
- MERGE --- 将多个MyISAM表作为一个表处理
- CSV --- 文件可以用EXCEL打开
- MEMORY --- 内存储存,主要用于临时区和缓存。不支持事务
- ARCHIVE --- 可通过压缩存储大量数据,仅支持INSERT和SELECT
- 设置存储引擎:
- 确认存储引擎:
SHOW CREATE TABLE tb;
- 修改存储引擎:
ALTER TABLE 表名 ENGINE=MyISAM;
- 使用事务:
- 开启事务:
START TRANSACTION;
- 回滚复原:
ROLLBACK;
- 提交:
COMMIT;
- 不能回滚的命令:
DROP DATABASE
DROP TABLE
DROP VIEW
ALTER TABLE
- 事务冲突:
- 脏读(脏数据):一个事务访问数据并修改且并未提交,则另一个事务读取的数据称为脏数据,如果前一事务回滚,后一事务读取的数据是不正确的
- 不可重复读:一个事务读取了一行数据,在事务结束前,另一事务访问了同一行并进行了修改,此时前一事务再次读取,结果会不同,称为不可重复读
- 幻读:一个事务读取了满足条件的所有行后,另一个事务插入了一行数据,前一事务再次进行同样的条件读取时,结果多了一行数据,称为幻读
- 事务隔离:
- Read Uncommitted:保证读取过程不会读到非法数据,但无法避免事务冲突
- Read Commited::保证一个事务不会读到另一个并行事务已修改但未提交的数据,避免了脏读
- Repeatable Read:避免了脏读和不可重复读(即看不到其它事务对已有记录的更新/修改)
- Serializable:最高级别事务隔离,串行化事务执行
文件
- CSV文件:
- 导入:
LOAD DATA INFILE '文件名' INTO TABLE 表名 选项的描述;
- 选项:
- FIELDS TERMINATED BY 分隔符 (默认是'\t:Tab)
- LINES TERMINATED BY 换行符 (默认是'\n:换行)
- IGNORE 最开始跳过的行 LINES (默认是0)
- 导出:
SELECT * INTO OUTFILE '文件名' 选项的描述 FROM 表名;
- SQL命令:
- 读取并执行:
SOURCE 文本文件名
- 结果保存:
tee 输出文件的名称
- 备份和恢复:
- 转储:对数据库的所有内容进行导出。
mysqldump -u 用户名 -p密码 数据库名 > 输出文件的名称
- 恢复:
mysql -u 用户名 -p密码 恢复数据库 < 备份文件的名称
- 制定字符编码:
- 在最后加
--default-character-set=utf8
- 锁表:限制表的操作
LOCK TABLES 表名 锁的类型
- READ --- 所有客户端都只允许执行SELECT,只读锁
- READ LOCAL --- InnoDB以外的引擎,本地只读锁
- WRITE --- 只有加锁的客户端可以执行操作
- 解锁:
UNLOCK TABLES;
MongoDB
MongoDB介绍
- 文档:
- 键不能有空字符
- .和$具有特殊意义
- 类型敏感/大小写敏感
- 集合:
- 不同文档的集合
- 不能有空字符
- 不能以system.开头
- 不能有保留字符$
- 数据库:
- admin --- root身份数据库
- local --- 本地集合,不可复制
- config --- 分片信息
- 命名空间:cms数据库的blog.posts集合 --- 命名空间:cms.blog.posts
- Shell:
- 查看当前数据库:
db
- 选择数据库:
use ...
- 基本操作:
- insert:集合中插入文档 -
db.集合名.insert(文档名)
- find:查询集合中的所有文档 -
db.集合名.find()
- findOne:查询一个文档 -
db.集合名.findOne()
- update:修改文档,用新文档替换满足键/值对的文档 -
db.集合名.update({key:value},新文档名)
- remove:删除文档 -
db.集合名.remove({key:value})
- 数据类型:
- null:
{"x" : null}
- bool:
{"x" : true}
- 数值:
{"x" : 3.14}
{"x" : NumberInt("3")}
{"x" : NumberLong("3")}
- 字符串:
{"x" : "foobar"}
- 日期:
{"x" : new Date()}
- 正则表达式:
{"x" : /foobar/i}
- 数组:
{"x" : ["a","b","c"]}
- 内嵌文档:
{"x" : {"foo" : "bar"}}
- 对象id:
{"x" : ObjectId()}
- 二进制数据
- js代码:
{"x" : function() { /*...*/}}
- shell脚本:
- 可以运行JavaScript脚本
$ mongo script1.js script2.js
load("script1.js")
- .mongorc.js文件:启动时运行脚本
- 集合命名注意事项:
- 集合名称中如果包含JavaScript的无效属性(如以数字开头和除$和_以外的字符),不能使用db.collectionName
db.getCollection("version")
db[name]访问db.name
创建/更新/删除
插入/保存
- 插入文档:
db.foo.insert({"bar" : "baz"})
- 批量插入(文档数组):
db.foo.batchInsert([{"_id" : 0},{"_id" : 1},{"_id" : 2}])
- 插入校验:文档结构检查(_id字段),文档大小检查(小于16MB)
- 删除文档:
- 删除集合中的所有文档:
db.foo.remove()
- 条件删除(删除满足条件的文档):
db.foo.remove({"opt" : true})
- 清空集合(代替remove,速度更快):
db.foo.drop()
- 删除字段:
- 更新文档:
- 替换文档:
db.foo.update(...定位需更新的目标文档 , ...修改器,说明进行哪些修改);
- 更新修改器:对文档中某些字段进行更新
db.foo.update({"..." : "..."} , {"$inc" : {"..." : 1}})
"$set"
修改:指定一个字段的值,若字段不存在,则创建它
"$unset"
删除键 --- {"$unset" : {"..." : 1}}
"$inc"
增加/减少:--- {"$inc" : {"..." : 1}}
- 数组修改器
"$push"
--- 添加元素 -> 数组已存在,则在末尾添加元素,否则创建一个新数组
"$each"
--- 一次性添加多个值 -> {"$each" : [... , ... , ...]}
"$slice"
--- 限制数组最大长度(只包含最后加入的10个元素)
{"$push" : {"..." : {"$each" : [...] , "$slice" : -10}}}
"$sort"
--- 排序
"$sort"
/"$slice"
必须与"$each"
搭配使用
- 数组数据集(保证数组内元素不会重复)
$ne
--- db.foo.update({"..." : {"$ne" : "..."}} , {$push : {"..." : "..."}})
$addToSet
--- {"$addToSet" : {"..." : "..."}}
- 数组元素删除
"$pop"
--- 栈删除
{"$pop" : {"key" : 1}}
--- 从数组末尾删除
{"$pop" : {"key" : -1}}
--- 从数组头部删除
"$pull"
--- 条件删除
{"$pull" : {"key" : "value"}}
- 基于位置的数组修改器
{"comments.0.votes" : 1}
--- 已知下标可以直接定位comments[0].votes
$
--- db.foo.update({"comments.author" : "John"} , {"$set" : {"comments.$.author" : "Jim"}})
- 修改器速度
- 依次插入的文档在磁盘上位置是相邻的
- 修改文档 -> 文档变大 -> 文档移动 -> 填充因子改变 -> 产生大量空的数据空间
- 提高磁盘复用率(大量的移动数据或打乱数据)
db.runCommand({"collMod" : collectionName , "usePowerOf2Sizes" : true})
- false可以关闭该机制
- upsert
- 无符合条件的文档,则创建新文档
- 有符合条件的文档,则正常更新
- 可以避免查询竞态问题(原子操作)
db.foo.update({"key" : "value"} , {"$inc" : {"keyname" : 1}} , true)
- $setOnInsert
- 更新多个文档:
- update的第四个参数置为true
- 默认行为可能会变化,因此建议每次都显示表明第四个参数
update({"...":"..."} , {"$..." : {"..." : "..."}} , false , true)
db.runCommand({getLastError : 1})
查询上一次操作的信息
- 序列操作:
ps = db.runCommand({"findAndModify" : "processes",
... "query" : {"status" : "READY"},
... "sort" : {"priority" : -1},
... "update" : {"$set" : {"status" : "RUNNING"}})
//findAndModify默认返回的是修改前的文档
//可以改变new字段来设置返回的文档
- 写入安全:
- 应答式写入:默认方式,会等待数据库响应操作是否成功
- 非应答式写入:不返回数据库错误
查询
- find:
- 匹配查询:
db.foo.find({"..." : "..."})
- 制定需要返回的键:
db.foo.find({},{"keyname_1" : 1 , "keyname_2" : 1})
- 仅返回指定键/值对(_id总是会返回)
- 值为0则代表剔除该键/值对
- find()里的参数不能有引用文档中其他键的值
- 查询条件:
- 比较操作符:
"$lt"
-> 小于
"$lte"
-> 小于等于
"$gt"
-> 大于
"$gte"
-> 大于等于
"$ne"
-> 不等于
db.foo.find({"age" : {"$gte" : 18 , "$lte" :30}})
- 逻辑:
- 多匹配:
"$in"
{"$in" : [... , ... , ...]}
- 返回所有不匹配的:
"$nin"
- OR查询:
"$or"
{"$or" : [{"..." : "..."} , {"..." : "..."}]}
- AND查询:
find({"..." : "..." , "..." : "..."})
{"$and" : [{"x" : {"$lt" : 1}} , {"x" : 0}]}
--- 不推荐
- NOT查询:
"$not"
{"$not" : {"$mod" : [5,1]}}
- 类型查询:
- null
- 正则表达式 ---
/joe?/i
- 数组
- AND匹配:
"$all"
- 查询特定位置:
db.foo.find({"fruit.2" : "peach"})
- SIZE匹配:
"$size"
- 子集:
{"arrayname" : {"$slice" : 10}}
{"arrayname" : {"$slice" : [23,10]}}
- 除非特别声明,否则也会返回文档中的其它键
- 数组元素匹配
db.foo.find({"comments.name" : "bob"} , {"comments.$" : 1})
- 得到第一个匹配的文档
- 范围查询
- 如果查询字段是一个数组,数组中的某一个元素只要与任意一条语句相匹配,就会返回该文档
- 对数组的范围查询会失效
- 内嵌文档
- 点表示法:
db.foo.find({"name.first" : "Joe" , "name.last" : "Schmoe"})
- 条件组合查询:
"$eleMatch"
db.foo.find({"comments" : {"$elemMatch" : {"author" : "Joe" , "score" : {"$gte" : 5}}}})
- $where查询:
- javaScript匹配查询
{"$where" : function () {......}}
- shell游标:
- .next( )
- .limit( )
- .skip( )
- .sort( )
- 保证查询时每个文档只返回一次:.snapshot( )
- -结果集较大造成文档移动使得.next()迭代造成多次返回同一文档
- 数据库命令:
- 删除集合:
db.runCommand({"drop" : "test"})
- 管理员命令:
db.adminCommand({"shutdown" : 1})
索引
- 创建索引:
db.foo.ensureIndex({"username" : 1})
- 复合索引:
db.foo.ensureIndex({"age" : 1,"username" : 1})
- 复合索引的使用形式:
db.foo.ensureIndex({"sortKey" : 1,"queryCriteria" : 1})
- 在查询有限结果数量时效率最高
- 需要查询所有结果时,效率较低
- 使用复合索引:
- 排列顺序:1 - 正序;-1 - 逆序
- 覆盖索引
- 隐式索引
- $操作符索引处理:
- 无法使用索引的操作符:
"$where"/"$exists"/"$ne"/"$not"/"$nin"
- 复合索引范围:
- OR查询
"$or"
使查询可以使用多个索引
db.foo.find({"$or" : [{"x" : 123} , {"y" : 456}]})
- 嵌套对象索引和数组索引:
- 嵌套对象索引:
db.foo.ensureIndex({"loc.city" : 1})
- 数组索引:
db.foo.ensureIndex({"comments.date" : 1})
- 索引基数:
- 基数:集合中某个字段拥有不同值的数量
- 在基数较高的字段上建立索引
- hint()强制索引:
- 何时应该不使用索引:
- 索引需要二次查找:索引条目和文档查找
- 如果结果集在集合中比例较大,索引使用的时间可能更多
- 强制做全表扫描:
.hint({"$natural" : 1})
- 索引类型:
- 唯一索引:保证集合的每一个文档的指定键的值是唯一的
db.foo.ensureIndex({"username" : 1} , {"unique" : true})
- 集合中已存在重复值会报错
- 去除重复:
{"unique" : true , "dropDups" : true}
- 插入有相同键/值索引的文档会报错
- 没有对应的键的文档会将null作为索引存储
- 稀疏索引:
{"unique" : true , "sparse" : true}
- 不存在字段的文档不会列入索引条目
- 复合唯一索引:所有键的组合值必须是唯一的
- 索引管理:
- 查看给定集合上的所有索引信息:
- 自定义索引名称:
db.foo.ensureIndex({"a" : 1} , {"name" : "alphabet"})
- 删除索引:
db.foo.dropIndex("x_1_y_1")
特殊的索引和集合
固定集合
- 固定集合:
- 事先创建,大小固定
- 循环队列,集合满时,会删除老数据给新数据释放空间
- 碟式磁盘上写入很快
- 一般用于记录日志
- 创建:显式创建
db.createCollection("my_collection" , {"capped" : true , "size" : 10000 , "max" : 100})
- max为可选字段
- 转化为固定集合:
db.runCommand({"convertToCapped" : "test" , "size" : 10000})
- 自然排序:
- 得到文档的插入顺序
- 从旧到新:```db.my_collection.find().sort({"$natural" : 1})
全文本索引
- 创建:
db.foo.ensureIndex({"title" : "text"})
- 指定权重:
db.foo.ensureIndex({"title" : "text" , "desc" : "text"} , {"weights" : {"title" : 3 , "desc" : 2}})
- 使用索引:
db.runCommand({"text" : "foo" , "search" : "..."})
- 返回完全匹配和部分匹配的文档
- 不区分大小写
- 搜索语法:
- 精确匹配:
"\"ask\""
"\"ask\" me"
- 排除匹配:
"-start"
- 优化全文搜索:
- 缩小范围:
db.foo.ensureIndex({"date" : 1 , "post" : "text"})
GridFS
- GridFS:
- 存储大型二进制文件
- 用于不常改变但经常连续访问的大文件
- mongofiles工具:
- 上传文件:
./mongofiles put foo.txt
- 列出GridFS文件:
./mongofiles list
- 下载GridFS文件:
./mongofiles get foo.txt
- search/delete
聚合
- 聚合框架:对集合中的文档进行变换和组合
db.foo.aggregate({},{},...)
- 管道操作符:
"$match"
- 对集合中的文档进行筛选
{"$match" : {"keyname" : "value"}}
"$project"
- 从集合中提取字段
{"$project" : {"author" : 1 , "name" : 1}}
- 重命名字段:
{"$project" : {"user" : "$_id" , "_id" : 0}}
$
为引用语法:$_id
代表_id
字段的内容
- 索引不能继承,应在重命名前使用索引
- 管道表达式:
- 数学表达式:
{"$project" : {"total" : {"$add" : ["$salary" , "$bonus"]}}}
- 表达式嵌套:
{"$subtract" : [{"$add" : ["%salary" , "$bonus"]} , "$401k"]}
"$add"
"$subtract
"$multiply"
"$divide"
"$mod"
- 日期表达式:对日期类型的字段进行操作(提取相应的日期信息)
{"$project" : {"hired" : {"$month" : "$hireDate"}}}
"$year"/"$month"/"$week"/"$dayOfMonth"/"$dayOfWeek"/"$dayOfYear"/"$hour"/"$minute"/"$second"
- 字符串表达式:
"$substr" : [expr,startOffset,numToReturn]
"$concat" : [expr1,expr2,...exprN]
"$toLower" : expr
"$toUpper" : expr
- 逻辑表达式:
"$cmp" : [expr1,expr2]
"$strcasecmp" " [string1,string2]
"$eq"/"$ne"/"$gt"/"$gte"/"$lt"/"$lte" : [expr1,expr2]
"$and" : [expr1,....,exprN]
"$or" : [expr1,...,exprN]
"$not" : expr
"$cond" : [booleanExpr,trueExpr,falseExpr]
"$ifNull" : [expr,replacementExpr]
"$group"
:将文档依据字段的不同值进行分组
- 将需要分组的字段传递给_id字段
- 算术操作符:
- "$sum" : value
{"$group" : {"_id" : "$country" , "total" : {"$sum" : "$revenue"}}}
- "$avg" : value
- 极值操作符:
- "$max" : expr
- "$min" : expr
- "$first" : expr
- "$last" : expr
- 数组操作符:
- "$addToSet" : expr
- "$push" : expr
"$unwind"
:可以将数组中的每一个值拆分为单独的文档
db.foo.aggregate({"$unwind" : "$comments"})
"$sort"
:
{"$sort" : {"compensation" : -1 , "name" : 1}}
"$limit"
:返回结果集中的前n个文档
"$skip"
:丢弃结果集中的前n个文档
- 聚合命令:
- count:
- distinct:
- 找出给定键的所有不同值
db.runCommand({"distinct" : "people" , "key" : "age"})
- group:类似于SQL里的GROUP BY
db.runCommand({"$group" : {
"ns" : "stocks", //指定要进行分组的集合
"key" : "day", //指定文档分组依据的键
"initial" : {"time" : 0}, //reduce调用中的初始值
"$reduce" : function(doc,prev) { //函数在集合内的每个文档上执行(prev为累加器文档)
if(doc.time > prev.time) {
prev.price = doc.price;
prev.time = doc.time; }}
"condition" : {"day" : {"$gt" : "2010/09/30"}} //文档过滤
"finalize" : function(prev) {}
}})
应用程序设计
- 范式化和反范式化:
- 范式化:将数据分散至不同集合(适用数据频繁更新)
- 反范式化:将文档相关的所有数据都保存在文档内部(适用数据频繁读取)
- 基数:集合中包含对其他集合的引用数量
- 优化数据操作:
- 数据库和集合:
- 文档需要进行集中查询和聚合,应将这些文档放在一个大集合中
副本集
- 复制:将数据副本保存到多台服务器上
- 副本集:
- 创建副本集:
replicaSet = new ReplSetTest({"nodes" : 3})
- 启动进程:
replicaSet.startSet()
- 配置复制功能:
replicaSet.initiate()
- shell连接:
conn1 = new Mongo("localhost:31000")
primaryDB = conn1.getDB("test")
- 查看主节点信息:
primaryDB.isMaster()
- 对主节点进行写入会备份至副节点
- 设置备份节点可读取:
conn2.setSlaveOk()
- 自动故障转移:主节点失去连接,备份节点成为主节点
- 关闭副本集:
replicaSet.stopSet()
应用管理
- 了解正在进行的操作:
- 终止操作:
- 系统分析器:
- 开启:
db.setProfilingLevel(level)
- 提供系统进行操作的所有详细信息
- 计算空间消耗:
- 文档:
Object.bsonsize({_id:ObjectId()})
Objecy.bsonsize(db.foo.findOne())
- 集合:
- 数据库:
- 命令行工具:
- mongotop - 概述集合的运行状态
- mongostat - 提供有关服务器的状态信息
数据管理
- 身份验证:
- 每个数据库都可以拥有多个用户
- admin/local数据库 : 超级用户
db.addUser("read_user","passwd",true)
- 启用安全检查:命令行选项加上--auth (客户端必须登陆才能进行读写)
- 登陆用户:
db.auth("user","passwd")
- 配置身份验证:
- admin数据库建立用户前,“本地”客户端可对数据库进行读写
- 删除用户:
db.system.users.remove({"user" : "test_user"})
- 索引:
- 后台建立索引:
db.foo.ensureIndex({"somefield" : 1} , {"background" : true})
- 前台建立索引会锁定数据库
- 删除索引:
db.runCommand({"dropIndexes" : "foo" , "index" : "alphabet"})
db.runCommand({"dropIndexes" : "foo" , "index" : "*"})
- 压缩数据:
- 清除空区段,重整集合:
db.runCommand({"compact" : "collectionName"})
- 移动集合:
db.sourceColl.renameCollection("newName")
启动和停止
- 命令行启动:mongod
- 使用配置文件:mongod --config ~/.mongodb.conf
- 停止:admin权限下 ---
db.runComand({"shutdown" : 1})
- 安全性:
- 不要将MongoDB服务器暴露在外网上,限制外部对数据库的访问
- 配置文件:
- --bind_ip:指定监听端口
- --nohttointerface:不启用提供系统信息的http服务器
- --nounixsocket:禁止socket连接
- --noscripting:禁止JavaScript脚本运行
- 日志:
- 默认会将日志发送至终端控制台
- 使用--logpath指定日志文件
- 日志级别更改:
db.adminCommand({"setParameter" : 1 , "loglevel" : 3})
- 日志分割:
db.adminCommand({"logRoutate" : 1})
备份
- 文件系统快照
- 复制数据文件
- 锁定数据库:
db.fsynLock()
- 复制数据目录中的所有文件:
$ cp -R /data/db/* /.......
- 解锁数据库:
db.fsyncUnlock()
- mongodump
- 备份所有数据库(指定运行端口):
$ mongodump -p 31000
- 可选择指定的备份目录:
$mongodump --dbpath /data/db
- 恢复:
$ mongorestore -p 31000 --oplogReplay dump/
Druid数据库连接池
Druid连接池
- Druid:
- DruidDriver:代理Driver,提供基于Filter-Chain模式的插件体系
- DruidDataSource:高效可管理的数据库连接池
- SQLParser:实用的SQL语法分析
代码
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
//注:在SpringBoot项目中,使用SpringFramwork的ThreadPoolTaskExecutor线程池来使用Druid连接池
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JdbcUtil {
// 创建数据源对象
private static DataSource dataSource;
static {
// 新建一个配置文件对象
Properties properties = new Properties();
// 通过类加载器找到文件路径,读配置文件
InputStream inputStream = JdbcUtil.class.getResourceAsStream("/d.properties");
// 加载属性文件
try {
properties.load(inputStream);
// 创建连接池对象
dataSource = DruidDataSourceFactory.createDataSource(properties);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* 从连接池中获取连接
* */
public static Connection getConnect(){
Connection con = null;
try {
con = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
/*
* 关闭资源
* */
public static void close(Connection connection, Statement statement, ResultSet resultSet){
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(statement!=null){
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(resultSet!=null){
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}