• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
Lith
博客园    首页    新随笔    联系   管理    订阅  订阅
Java学习笔记(三) - 数据库MySQL和MongoDB
参考书目:MySQL基础教程/MongoDB权威指南

目录

  • 目录
  • MySQL
    • 创建数据库
    • 数据类型
    • 修改表
    • 复制/删除表
    • 条件提取
      • 函数
      • 条件显示
      • 排序
      • 分组显示
    • 编辑数据
    • 多表
    • 视图
    • 存储
    • 事务
    • 文件
  • MongoDB
    • MongoDB介绍
    • 创建/更新/删除
      • 插入/保存
    • 查询
    • 索引
    • 特殊的索引和集合
      • 固定集合
      • 全文本索引
      • GridFS
    • 聚合
    • 应用程序设计
    • 副本集
    • 应用管理
    • 数据管理
    • 启动和停止
    • 备份
  • Druid数据库连接池
    • Druid连接池
    • 代码

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);
  • 删除列:
    • ALTER TABLE 表名 DROP 列名;
  • 设置键:
    • 主键:列的特殊属性 ---> 没有重复的值,不允许输入空值、
    • CREATE TABLE 表名 (列名 数据类型 PRIMARY KEY,... ...);
    • 唯一键:标注列为不可重复属性 ---> 允许输入空值,但不许重复
    • CREATE TABLE 表名 (列名 数据类型 UNIQUE,... ...);
  • 自动连续编号:
    • 数据类型为INT等整型
    • 数据类型加AUTO_INCREMENT关键字
    • 设置PRIMARY KEY
    • 插入记录:
      • 自动编号列插入0或NULL
    • 编号初始化: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 表名;
  • 删除数据库:
    • DROP DATABASE 数据库名;
  • 删除表中记录:
    • DELETE FROM 表名;

条件提取

  • 使用别名:
    • SELECT 列名 AS 别名 FROM 表名;
  • 列计算:
    • ‘+’、‘-’、‘*’、‘/’、‘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(列名) ---> 将列中的字符反转显示
  • 日期和时间函数:
    • NOW()

条件显示

  • 限制记录数:
    • SELECT 列名 FROM 表名 LIMIT 显示的记录数;
  • 条件提取:
    • SELECT 列名 FROM 表名 WHERE 条件;
    • 运算符:
      • 等于:'='
      • 大于:'>'
      • 大于等于:'>='
      • 小于:'<'
      • 小于等于:'<='
      • 不等于:'<>'
      • a在b列表中:a IN b
      • a不在b列表中:a NOT IN b
      • a在b和c之间:a BETWEEN b AND c
      • a不在b和c之间:a NOT BETWEEN b AND c
    • 字符串:
      • 字符串相等:a = b
      • 模糊匹配LIKE
        • % 任意字符串
        • _ 任意一个字符
      • 不包含 NOT LIKE
      • NULL
        • 列值为空:IS NULL
        • 列值非空:IS NOT NULL
    • 去除重复的记录:SELECT DISTINCT 列名 FROM 表名;
  • 组合条件:
    • AND
    • OR
    • CASE WHEN
    SELECT
    CASE
      WHEN 条件1 THEN 显示的值
      WHEN 条件2 THEN 显示的值
    ELSE
    END
    FROM ...;
    

排序

  • 升序:
    • 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 ...;
      • SUM()和AVG()同样适用
  • 分组显示:
    • 分组后提取记录: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 表名;
  • 删除视图:
    • DROP VIEW 视图名;
  • 主从库复制:
    • 异步(默认)
    • 半同步(从库会发送响应信息)
    • 无损半同步(主库接受到从库的响应信息后才写入修改)

存储

  • 存储过程:将多个SQL语句组合成一个使用CALL就能执行的集合
    将分隔符;换为//
    delimiter //
    CREATE PROCEDURE 存储过程名()
    BEGIN
      SQL语句1
      SQL语句2;
      ......
    END
    //
    delimiter ;
    复原分隔符
    
    • 执行:CALL 存储过程名;
    • 带参数存储:
      • CREATE PROCEDURE 存储过程名 (参数名 数据类型);
    • 显示存储过程:
      • SHOW CREATE PROCEDURE 存储过程名;
    • 删除存储过程:
      • DROP PROCEDURE 存储过程名;
  • 存储函数:
    • 带返回值的存储过程
    delimiter //
    CREATE FUNCTION 存储函数名 (参数 数据类型) RETURNS 返回值的数据类型
    BEGIN
      SQL语句......;
      RETURN 返回值/表达式
    END
    //
    delimiter ;
    
    • 显示存储函数:
      • SHOW CREATE FUNCTION 存储函数名;
    • 删除存储函数:
      • DROP FUNCTION 存储函数名;
  • 触发器:对表执行某种操作后会触发执行其它命令的机制
    • 创建触发器:
    CREATE TRIGGER 触发器名 BEFORE (或者AFTER) DELETE 等命令
    ON 表名 FRO EACH NOW
    BEGIN
      使用更新前 (OLD.列名) 或者更新后 (NEW.列名) 的处理
    END
    
    • 确认触发器:
      • SHOW TRIGGERS;
    • 删除触发器:
      • DROP TRIGGER 触发器名;

事务

  • 存储引擎:
    • 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()
  • 删除字段:
    • delete db.foo.keyname
  • 更新文档:
    • 替换文档:
      • 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 : {"..." : "..."}})
        • 如果不存在就添加进去
        • 不能和"$each"组合
      • $addToSet --- {"$addToSet" : {"..." : "..."}}
        • 非重复添加
        • 可以和"$each"组合起来
    • 数组元素删除
      • "$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)
        • 第三个参数表明这是个upsert
    • $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指定使用的索引
  • 何时应该不使用索引:
    • 索引需要二次查找:索引条目和文档查找
    • 如果结果集在集合中比例较大,索引使用的时间可能更多
    • 强制做全表扫描:.hint({"$natural" : 1})
  • 索引类型:
    • 唯一索引:保证集合的每一个文档的指定键的值是唯一的
      • db.foo.ensureIndex({"username" : 1} , {"unique" : true})
      • 集合中已存在重复值会报错
        • 去除重复:{"unique" : true , "dropDups" : true}
      • 插入有相同键/值索引的文档会报错
      • 没有对应的键的文档会将null作为索引存储
        • 稀疏索引:{"unique" : true , "sparse" : true}
        • 不存在字段的文档不会列入索引条目
      • 复合唯一索引:所有键的组合值必须是唯一的
  • 索引管理:
    • 查看给定集合上的所有索引信息:
      • db.foo.getIndexes()
    • 自定义索引名称:
      • 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:
      • 返回集合中文档数量:db.foo.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.currentOp()
  • 终止操作:
    • db.killOp(opid)
  • 系统分析器:
    • 开启:db.setProfilingLevel(level)
    • 提供系统进行操作的所有详细信息
  • 计算空间消耗:
    • 文档:
      • Object.bsonsize({_id:ObjectId()})
      • Objecy.bsonsize(db.foo.findOne())
    • 集合:
      • db.foo.stats()
    • 数据库:
      • db.stats()
    • 命令行工具:
      • 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();
            }
        }
    }
}
posted on 2020-08-13 09:45  Lith  阅读(236)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3