数据库

2022-01-12 14:53:03 浏览数 (1)

数据库

数据库简介

数据库概念

简单的说,数据库(因为Database)就是一个存放数据的仓库,这个仓库是按照一定的数据结构(数据结构是指数据的组织形式或数据之间的联系)来组织、存储的,我们可以通过数据库提供的多种方式来管理数据库里的数据。 更简单形象的理解,数据库和我们生活中存放杂物的储物间仓库性质一样,区别只是存放的东西不同,杂物间存放实体的物件,而数据库里存放的是数据。

数据库最新排名

数据库的种类

在当今的互联网中,最常用的数据库模型主要是两种,即关系型数据库和非关系型数据库。

关系型数据库模型是把复杂的数据结构归结为简单的二元关系(即二维表格形式)。

非关系型数据库也被成为NoSQL数据库,NOSQL的本意是“Not Olnly SQL”。因此,NoSQL的产生并不是要彻底地否定非关系型数据库,而是作为传统关系型数据库的一个有效补充。NOSQL数据库在特定的场景下可以发挥出难以想象的高效率 和高性能。

mysql基础

mysql简介

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。 在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软 件。 MySQL是一种关系数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。 MySQL所使用的 SQL 语言是用于访问数据库的最常用标准化语言。MySQL 软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。

mysql社区版和企业版区别: 1.企业版只包含稳定之后的功能,社区版包含所有Mysql的最新功能。 也就是说,社区版是企业版的测试版,但是,前者的功能要比后者多。 2.官方的支持服务只针对企业版,用户在使用社区版时出现任何问题,Mysql官方概不负责。 至于管理工具,Mysql官方提供的工具都是免费的,从官方网站都可以下载到,同样可以用在社区版的Mysql上。

安装配置

安装 sudo apt-get install mysql-server mysql-client 然后按照提示输入

设置root密码

ubuntu系统新版本mysql安装是没有提供root密码设置引导 需要在usr/bin目录下运行 mysql_secure_installation

sudo mysql_secure_installation 根据提示运行设置

设置完毕重启mysql服务 启动需要使用 sudo mysql -u root -p

管理服务

启动 service mysql start 停止 service mysql stop 重启 service mysql restart

允许远程连接 找到mysql配置文件并修改

sudo vi /etc/mysql/mysql.conf.d/mysqld.cnf 将bind-address=127.0.0.1注释

卸载 sudo apt-get --purge remove mysql-server mysql-common mysql-client

主键、外键和约束

主键:一个记录中有若干个属性,其中一个能唯一标识该记录,该属性就是主键 比如一条记录包括身份证号,姓名,年龄,身份证号是唯一确定这个人的,它就是主键

外键:外键是与另一张表的关联,能确定另一个表中的记录 比如: 有三个表: 客户表:记录客户的信息,如客户编号,客户名称,地址,联系方式等 商品表:记录商品的信息,比如商品编号,商品名称,品牌,单价,库存数量等 订单表:包括订单信息 一条订单记录:包括客户编号,商品编号,商品数量,金额等属性 客户编号是客户表中的主键,它就是订单表的外键

约束:一种限制,通过对表的行或列的数据做出限制,来确保数据的完整性、唯一性 比如:在订单记录中,指定的客户编码,必须是客户表中存在的客户 商品编号,必须是商品表中存在的商品

表字段约束

• 主键primary key • 非空not null • 惟一unique • 默认default • 外键foreign key

表字段类型

• 在mysql中包含的数据类型很多,这里主要列出来常用的几种 • 数字:int,decimal,float • 字符串:varchar,text • 日期:datetime • 布尔:bit

数据库三大范式

数据库设计(Database Design)是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,使之能 够有效地 存储数据,满足各种用户的应用需求(信息要求和处理要求)。

为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范 式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。

第一范式(确保每列保持原子性)

第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。 第一范式的合理遵循需要根据系统的实际需求来定。 比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成一个数据库表的字段就行。但是如果系统经 常会访问“地址”属性中的“城市”部分,那么就非要将“地址”这个属性重新拆分为省份、城市、详细地址等多个部分进行存 储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式

第二范式(确保表中的每列都和主键相关) 第二范式在第一范式的基础之上更进一层。 第二范式需要确保数据库表中的每一列都和主键相关。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以 把多种数据保存在同一张数据库表中。

第三范式(确保每列都和主键列直接相关,而不是间接相关) 第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

连接命令

使用命令连接 打开终端,运行命令(前提需要配置mysql环境变量)

mysql -uroot -p

回车后输入密码,当前设置的密码为mysql

完整命令 mysql -h 192.168.10.123 -P 3306 -u root -p 其中-h参数为主机地址 -P为端口值

退出登录

quit或exit

数据库操作

显示数据库列表

show databases;

创建数据库 create database 数据库名 charset=utf8;

删除数据库 drop database 数据库名;

切换数据库 use 数据库名;

查看当前选择的数据库

select database();

表操作

查看当前数据库中所有表

show tables;

创建表

create table 表名(列及类型)

create table students( id int auto_increment primary key not null, sname varchar(10) not null, );

修改表 alter table 表名 add|change|drop 列名 类型 alter table 表名 add 列名 类型;--添加某一列 alter table 表名 change 原列名 新列名 类型; --修改表的列属性名 alter table 表名 drop 列名; --删除表的某一列 alter table 表名 rename 新表名; --修改表名

删除表 drop table 表名;

查看表结构 desc 表名;

数据操作CURD

查询 select * from 表名

增加 全列插入:insert into 表名 values(...) 缺省插入:insert into 表名(列1,...) values(值1,...) 缺省插入:insert into 表名 set field1=value1,field2=value2 同时插入多条数据:insert into 表名 values(...),(...)...;

主键列是自动增长,但是在全列插入时需要占位,通常使用0,插入成功后以实际数据为准 修改 update 表名 set 列1=值1,... where 条件

删除 delete from 表名 where 条件

外键

MySQL创建关联表可以理解为是两个表之间有个外键关系,但这两个表必须满足三个条件 1.两个表必须是InnoDB数据引擎 2.使用在外键关系的域必须为索引型(Index) 3.使用在外键关系的域必须与数据类型相似 外键的好处:可以使得两张表关联,保证数据的一致性和实现一些级联操作;

定义外键 mysql> create table teacher(id int primary key not null auto_increment, name varchar(20) not null); mysql> create table student(id int primary key not null auto_increment, name varchar(20) not null, teacherid int, constraint teacher_id foreign key(teacherid) references teacher(id));

添加外键 alter table student add constraint teacher_id foreign key(teacherid) references teacher(id);

删除外键 alter table student drop foreign key teacher_id;

在父表上进行update/delete以更新或删除在子表中有一条或多条对应匹配行的候选键时,父表的行为取决于:在定义子表的外键时指定的on update/on delete子句。

关键字的含义 CASCADE 删除包含与已删除键值有参照关系的所有记录 SET NULL 修改包含与已删除键值有参照关系的所有记录,使用NULL值替换(只能用于已标记为NOT NULL的字段) RESTRICT 拒绝删除要求,直到使用删除键值的辅助表被手工删除,并且没有参照时(这是默认设置,也是最安全的设置) NO ACTION 啥也不做

备份和还原

备份 退出mysql命令模式 运行mysqldump命令

mysqldump –uroot –p 数据库名 > ~/Desktop/备份文件.sql;

按提示输入mysql的密码

数据恢复 连接mysqk,创建数据库 退出连接,执行如下命令 mysql -uroot –p 数据库名 < ~/Desktop/备份文件.sql 根据提示输入mysql密码

权限操作

grant all on *.* to zzy@localhost identified by '1234'; grant select on db.stu to zzy@localhost identified by '1234';

删除用户 use mysql delete from user where user ='zzy'; 修改密码 use mysql update user set password=password('新密码') where User="zzy" ;

mysql查询

基础查询

1.别名as 使用 as 给字段起别名 mysql> select nid as 标号, name as 姓名, role as 角色id from user;

可以通过 as 给表起别名 -- 如果是单表查询 可以省略表名 mysql>select id, name, gender from students;

-- 表名.字段名 mysql>select students.id,students.name,students.gender from students;

-- 可以通过 as 给表起别名 mysql> select s.id, s.name, s.gender from students as s

2.去重distinct mysql> select distinct gender from students; -------- | gender | -------- | 2 | | 1 | --------

3.条件查询where mysql> select * from students where gender = 1;

4.比较运算符:>、<和=

mysql>select * from students where id > 3;

mysql>select * from students where id <= 4;

mysql>select * from students where name != 'houyi';

5.逻辑运算符:and、or和not

mysql> select * from students where id < 3 and gender = 1;

6.模糊查询like %表示任意多个任意字符, _表示一个任意字符

mysql> select * from students where name like 'huang%';

mysql> select * from students where name like 'chang_';

mysql> select * from students where name like 'huang%' or name like 'chang_';

7.范围查询 in表示在一个非连续的范围内, between ... and ...表示在一个连续的范围内

mysql> select * from students where id in(1, 3, 8);

mysql> select * from students where id between 1 and 3;

mysql>select * from students where id between 3 and 8 and gender=1;

8.空判断 注意:null与''是不同的, 判空is null

mysql> select * from students where name is null;

mysql> select * from students where name is not null;

select * from students where name is not null and gender = 1;

高级查询

1.聚合:count、max、min、sum、avg

查询总数 mysql> select count(*) from students;

查询女生的编号最大值 mysql> select max(id) from students where gender = 2;

查询男生的编号最小值 mysql> select min(id) from students where gender = 1;

查询男生编号之和 mysql> select sum(id) from students where gender = 2;

查询男生编号的平均值 mysql> select avg(id) from students where gender = 1;

2.分组:group by 查询男女生总数 mysql> select gender,count(*) from students group by gender;

3.排序:order by asc从小到大排列,即升序,desc从大到小排序,即降序

查询男生学生信息,按学号降序排列 mysql> select * from students where gender = 1 order by id;

4.分页:limit 查询id为2之后的2条数据 mysql> select * from students limit 2, 2;

连接查询

1、内连接:只列出匹配的记录

SELECT … FROM join_table [INNER] JOIN join_table2 [ON join_condition] WHERE where_definition 解释:只列出这些连接表中与连接条件相匹配的数据行。INNER可以不写,则默认为内连接。[ON join_condition]里面写的是连接的条件。

2、外连接: mysql> select s.name, t.name from students s inner join type t on s.typeid = t.id;

外连接分类:

左外连接(LEFT [OUTER] JOIN) 右外连接(RIGHT [OUTER] JOIN) 全外连接(FULL [OUTER] JOIN) 注:MySQL5.1的版本暂不支持

SELECT … FROM join_table1

(LEFT | RIGHT | FULL) [OUTER] JOIN join_table2

ON join_condition

WHERE where_definition

解释:

不仅列出与连接条件(on)相匹配的行,还列出左表table1(左外连接)、或右表table2(右外连接)、或两个表(全外连接)中所有符合WHERE过滤条件的数据行。一般都是用左连接或者外连接。

其中,[OUTER]部分可以不写,(LEFT | RIGHT | FULL)部分要写其中一个。

2、1左外连接:左表列出全部,右表只列出匹配的记录。 mysql> select * from students s left join type t on s.typeid = t.id;

2、2右外连接:右表列出全部,左表只列出匹配的记录。 mysql> select * from students s right join type t on s.typeid = t.id;

3、交叉连接: 语法:

SELECT … FROM join_table1 CROSS JOIN join_table2;

没有ON子句和WHERE子句,它返回的是连接表中所有数据行的笛卡尔积。

笛卡尔积举例:假设集合A={a,b},集合B={0,1,2},则两个集合的笛卡尔积为{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}

其结果集合中的数据行数等于第一个表中符合查询条件的数据行数乘以第二个表中符合查询条件的数据行数。

等价于:(荐)

SELECT … FROM table1, table2;

mysql> select * from students cross join type;

4、自连接:参与连接的表都是同一张表。(通过给表取别名虚拟出两张表)

mysql> select s1.name hero, s2.name enemy from students s1 left join students s2 on s1.enemy = s2.id; ------------ ------- | hero | enemy | ------------ ------- | huangzhong | daji | | change | daji | | daji | NULL | | NULL | NULL | ------------ -------

mysql高级

触发器

什么是触发器

简单的说,就是一张表发生了某件事(插入、删除、更新操作),然后自动触发了预先编写好的若干条SQL语句的执行;

特点及作用

特点:触发事件的操作和触发器里的SQL语句是一个事务操作,具有原子性,要么全部执行,要么都不执行;

作用:保证数据的完整性,起到约束的作用;

视图

视图就是一条SELECT语句执行后返回的结果集。所以我们在创建视图的时候,主要的工作就落在创建这条SQL查询语句上。 视图是虚拟表,本身不存储数据,而是按照指定的方式进行查询。

视图的特性 视图是对若干张基本表的引用,一张虚表,查询语句执行的结果,不存储具体的数据(基本表数据发生了改变,视图也会跟着改变);

可以跟基本表一样,进行增删改查操作(ps:增删改操作有条件限制);

视图的作用

方便操作,特别是查询操作,减少复杂的SQL语句,增强可读性;

更加安全,数据库授权命令不能限定到特定行和特定列,但是通过合理创建视图,可以把权限限定到行列级别;

使用场合

权限控制的时候,不希望用户访问表中某些含敏感信息的列,比如salary...

关键信息来源于多个复杂关联表,可以创建视图提取我们需要的信息,简化操作;

创建视图

>CREATE VIEW 视图名(列1,列2...) AS SELECT 列1,列2... FROM ...;

mysql> select * from students; ---- ------- | id | name | ---- ------- | 1 | houyi | ---- ------- mysql> create view v_students(vid, vname) as select id, name from students;

修改视图CREATE OR REPLACE VIEW

CREATE OR REPLACE VIEW 视图名 AS SELECT [...] FROM [...];

查看视图 SHOW TABLES; 查看视图详情的方法有两种,一种是和查看表详情一样使用desc 视图名,另外一种方法是show fields from 视图名: >DESC 视图名; 或者 >SHOW FIELDS FROM 视图名;

存储过程

存储过程就是把经常使用的SQL语句或业务逻辑封装起来,预编译保存在数据库中,当需要的时候从数据库中直接调 用,省去了编译的过程,提高了运行速度; 存储过程实现的过程要复杂一些,而函数的针对性较强; 存储过程可以有多个返回值,而自定义函数只有一个返回值; 存储过程一般独立的来执行,而函数往往是作为其他SQL语句的一部分来使用;

存储过程弊端 不同数据库,语法差别很大,移植困难,换了数据库,需要重新编写;

不好管理,把过多业务逻辑写在存储过程不好维护,不利于分层管理,容易混乱,一般存储过程适用于个别对性能要求较高的业务,其它的必要性不是很大;

函数

什么是函数 mysql中的函数与存储过程类似,都是一组SQL集;

与存储过程的区别 函数可以return值,存储过程不能直接return,但是有输出参数可以输出多个返回值;

函数可以嵌入到sql语句中使用,而存储过程不能;

函数一般用于实现较简单的有针对性的功能(如求绝对值、返回当前时间等),存储过程用于实现复杂的功能(如复杂的业务逻辑功能);

索引

什么是索引?为什么要建立索引 索引用于快速找出在某个列中有一特定值的行,数据库优化加快查找性能 不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行,表越大,查询数据所花费的时间就越多, 如果表中查询的列有一个索引,MySQL能够快速到达一个位置去搜索数据文件,而不必查看所有数据,那么将会节省很大 一部分时间。 例如:有一张person表,其中有2W条记录,记录着2W个人的信息。有一个Phone的字段记录每个人的电话号码, 现在想要查询出电话号码为xxxx的人的信息。 如果没有索引,那么将从表中第一条记录一条条往下遍历,直到找到该条信息为止。 如果有了索引,那么会将该Phone字段,通过一定的方法进行存储,好让查询该字段上的信息时, 能够快速找到对应的数据,而不必在遍历2W条数据了。 其中MySQL中的索引的存储类型有两种:BTREE、HASH。 也就是用树或者Hash值来存储该字段, 要知道其中详细是如何查找的,就需要会算法的知识了。我们现在只需要知道索引的作用,功能是什么就行。 MySQL中索引的优点和缺点和使用原则 优点: 所有的MySql列类型(字段类型)都可以被索引,也就是可以给任意字段设置索引 大大加快数据的查询速度

缺点: 创建索引和维护索引要耗费时间,并且随着数据量的增加所耗费的时间也会增加 当对表中的数据进行增加、删除、修改时,索引也需要动态的维护,降低了数据的维护速度。 **什么时间真正需要索引:查询操作量大 ** 建立索引纯属浪费:查询量少 更改量大

事务

事务: 为了保证数据的完整性,成批的SQL要么全部执行,要么全部不执行。 通常用来操作数据量大,复杂度高的数据 事务通常用来管理update insert delete MySQL中只有使用innerDB引擎才支持事务 ACID特性 原子性:要么全部执行,要么全部不执行 一致性 :事务开始前结束后对数据的完整性不会破坏 隔离性 :允许多个并发事务同时对数据的读写,防止多个并发执行引起的不一致 持久性:事务处理结束后,对数据的修改是永久的 常用操作 begin 开始事务 rollback 回滚 commit 结束事务 想要使用事务必须使用INNODB引擎

python操作mysql

安装引入

python3安装pymysql pip install pymysql

引入pymysql import pymysql

Connection对象

Connection对象用于建立与数据库的连接 创建对象:调用connect()方法 参数host:连接的mysql主机,如果本机是'localhost' 参数port:连接的mysql主机的端口,默认是3306 参数db:数据库的名称 参数user:连接的用户名 参数password:连接的密码 参数charset:通信采用的编码方式,默认是'gb2312',要求与数据库创建时指定的编码一致,否则中文会乱码

对象的方法 close()关闭连接 commit()事务,所以需要提交才会生效 rollback()事务,放弃之前的操作 cursor()返回Cursor对象,用于执行sql语句并获得结果

Cursor对象

创建对象:调用Connection对象的cursor()方法 cursor1=conn.cursor() 对象的方法 close()关闭 execute(operation [, parameters ])执行语句,返回受影响的行数 fetchone()执行查询语句时,获取查询结果集的第一个行数据,返回一个元组 fetchall()执行查询时,获取结果集的所有行,一行构成一个元组,再将这些元组装入一个元组返回 fetchmany(n)执行查询时,获取n行,一行构成一个元组,再将这些元组装入一个元组返回 next() 执行查询语句时,获取当前行的下一行() scroll(value[,mode])将行指针移动到某个位置 mode表示移动的方式 mode的默认值为relative,表示基于当前行移动到value,value为正则向下移动,value为负则向上移动 mode的值为absolute,表示基于第一条数据的位置,第一条数据的位置为0 对象的属性 rowcount只读属性,表示最近一次execute()执行后受影响的行数

CURD

create 创建testInsert.py文件,向学生表中插入一条数据 import pymysql try: conn=pymysql.connect(host='localhost',port=3306,db='test1',user='root',passwd='mysql',charset='utf8') cs1=conn.cursor() count=cs1.execute("insert into students(sname) values('张良')") print count conn.commit() cs1.close() conn.close() except Exception as e: conn.rollback() print(e)

update 创建testUpdate.py文件,修改学生表的一条数据 import pymysql try: conn=pymysql.connect(host='localhost',port=3306,db='test1',user='root',passwd='mysql',charset='utf8') cs1=conn.cursor() count=cs1.execute("update students set sname='刘邦' where id=6") print count conn.commit() cs1.close() conn.close() except Exception,e: conn.rollback() print(e)

read 创建testSelectOne.py文件,查询一条学生信息 import pymysql try: conn=pymysql.connect(host='localhost',port=3306,db='test1',user='root',passwd='mysql',charset='utf8') cur=conn.cursor() cur.execute('select * from students where id=7') result=cur.fetchone() result=cur.fetchall() print(result) cur.close() conn.close() except Exception as e: print(e)

delete 创建testDelete.py文件,删除学生表的一条数据

import pymysql try: conn=pymysql.connect(host='localhost',port=3306,db='test1',user='root',passwd='mysql',charset='utf8') cs1=conn.cursor() count=cs1.execute("delete from students where id=6") print count conn.commit() cs1.close() conn.close() except Exception,e: print(e)

语句参数化

#format # row = cursor.execute("select * from customer where id>{} and addr='{}'".format(2, 'henan')) # % # row = cursor.execute("select * from customer where id>%s and addr='%s'" % (2, 'henan')) # args # row = cursor.execute("select * from customer where id>%s and addr=%s", (2, 'henan'))

封装

import pymysql

class MysqlHelper(): def __init__(self, host, port, db, user, passwd, charset='utf8'): self.host = host self.port = port self.db = db self.user = user self.passwd = passwd self.charset = charset

def connect(self): self.conn = MySQLdb.connect(host = self.host, port = self.port, db = self.db, user = self.user, passwd = self.passwd, charset = self.charset)

self.cursor = self.conn.cursor()

def close(self): self.cursor.close() self.conn.close()

def get_one(self, sql, params=()): result = None try: self.connect() self.cursor.execute(sql, params) result = self.cursor.fetchone() self.close() except Exception as e: print(e.message) return result

def get_all(self, sql, params=()): list=() try: self.connect() self.cursor.execute(sql, params) list=self.cursor.fetchall() self.close() except Exception as e: print(e.message) return list

def insert(self, sql, params=()): return self.__edit(sql, params)

def update(self, sql, params=()): return self.__edit(sql, params)

def delete(self, sql, params=()): return self.__edit(sql, params)

def __edit(self, sql, params): count=0 try: self.connect() count=self.cursor.execute(sql, params) self.conn.commit() self.close()

except Exception as e: print(e.message)

return count

orm与sqlalchemy

orm

ORM技术:Object-Relational Mapping,把关系数据库的表结构映射到对象上。操作数据库像操作对象一样,是不是很简 单? 但是由谁来做这个转换呢?所以ORM框架应运而生。 在Python中,最有名的ORM框架是SQLAlchemy。

框架安装

需要安装sqlalchemy以及mysql-connector-python两个模块

dbsession

import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker

print(sqlalchemy.__version__)

engine = create_engine("mysql mysqlconnector://root:root@localhost/test1") result = engine.execute("show tables") print(result.fetchall())

#通过bind参数使session连接到数据库 sess = sessionmaker(bind=engine)

print(sess)

CURD

from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationships from sqlalchemy import create_engine

engine = create_engine("mysql mysqldb://root:root@localhost:3306/test1?charset=utf8", max_overflow=5) Base = declarative_base()

# 创建单表 class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(32))

extra = Column(String(16))

__table_args__ = ( UniqueConstraint('id', 'name', name='uix_id_name'), Index('ix_id_name', 'name', 'extra') )

#创建表 Base.metadata.create_all(engine) DBSession = sessionmaker(bind=engine) session = DBSession() obj = Users(name="alex0",extra='sb')

# session.add(obj) # session.add_all([ # Users(name='alex1', extra='sb'), # Users(name='alex2', extra='sb') # ]) # session.commit()

# 删除 # session.query(Users).filter(Users.id > 2).delete() # session.commit()

# 修改 # session.query(Users).filter(Users.id > 2).update({"name":"099"}) # session.query(Users).filter(Users.id > 2).update({Users.name:Users.name "099"}, synchronize_session = False) # # session.commit()

# 查询 # ret = session.query(Users).all() # for r in ret: # print(r.id, r.name, r.extra)

mongodb基础

备份 语法 mongodump -h dbhost -d dbname -o dbdirectory -h:服务器地址,也可以指定端口号 -d:需要备份的数据库名称 -o:备份的数据存放位置,此目录中存放着备份出来的数据 例1 sudo mkdir test1bak sudo mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1bak 恢复 语法 mongorestore -h dbhost -d dbname --dir dbdirectory -h:服务器地址 -d:需要恢复的数据库实例 --dir:备份数据所在位置 例2 mongorestore -h 192.168.196.128:27017 -d test2 --dir ~/Desktop/test1bak/test1

MongoDB简介

MongoDB 是一个基于分布式 文件存储的NoSQL数据库

由C 语言编写,运行稳定,性能高 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案

MongoDB特点 模式自由 :可以把不同结构的文档存储在同一个数据库里 面向集合的存储:适合存储 JSON风格文件的形式 完整的索引支持:对任何属性可索引 复制和高可用性:支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。 复制的主要目的是提供冗余及自动故障转移 自动分片:支持云级别的伸缩性:自动分片功能支持水平的数据库集群,可动态添加额外的机器 丰富的查询:支持丰富的查询表达方式,查询指令使用JSON形式的标记,可轻易查询文档中的内嵌的对象及数组 快速就地更新:查询优化器会分析查询表达式,并生成一个高效的查询计划 高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)

常用nosql数据库

安装

在线安装 sudo apt-get install mongodb 版本号 mongo -version 服务启动停止重启 service mongodb stop service mongodb start service mongodb restart 查看是否启动 pgrep mongo 卸载mongodb sudo apt-get --purge remove mongodb mongodb-server mongodb-clients

基本概念

基本操作 MongoDB将数据存储为一个文档,数据结构由键值(key=>value)对组成 MongoDB文档类似于JSON对象,字段值可以包含其他文档、数组、文档数组 名词

三元素:数据库,集合,文档 集合就是关系数据库中的表 文档对应着关系数据库中的行 文档,就是一个对象,由键值对构成,是json的扩展Bson形式 {'name':'guojing','gender':'男'} 集合:类似于关系数据库中的表,储存多个文档,结构不固定,如可以存储如下文档在一个集合中 {'name':'guojing','gender':'男'} {'name':'huangrong','age':18} {'book':'shuihuzhuan','heros':'108'} 数据库:是一个集合的物理容器,一个数据库中可以包含多个文档 一个服务器通常有多个数据库

数据库操作

数据库切换 查看当前数据库名称 db 查看所有数据库名称 列出所有在物理上存在的数据库 show dbs 切换数据库 如果数据库不存在,则指向数据库,但不创建,直到插入数据或创建集合时数据库才被创建 use 数据库名称 默认的数据库为test,如果你没有创建新的数据库,集合将存放在test数据库中 数据库删除 删除当前指向的数据库 如果数据库不存在,则什么也不做 db.dropDatabase()

集合操作

集合创建 语法 db.createCollection(name, options) name是要创建的集合的名称 options是一个文档,用于指定集合的配置 选项参数是可选的,所以只需要到指定的集合名称。以下是可以使用的选项列表: 例1:不限制集合大小 db.createCollection("stu") 例2:限制集合大小,后面学会插入语句后可以查看效果 参数capped:默认值为false表示不设置上限,值为true表示设置上限 参数size:当capped值为true时,需要指定此参数,表示上限大小,当文档达到上限时,会将之前的数据覆盖,单位为字节

db.createCollection("sub", { capped : true, size : 10 } )

查看当前数据库的集合 语法 show collections

删除 语法 db.集合名称.drop()

数据操作

数据类型 下表为MongoDB中常用的几种数据类型: Object ID:文档ID String:字符串,最常用,必须是有效的UTF-8 Boolean:存储一个布尔值,true或false Integer:整数可以是32位或64位,这取决于服务器 Double:存储浮点值 Arrays:数组或列表,多个值存储到一个键 Object:用于嵌入式的文档,即一个值为一个文档 Null:存储Null值 Timestamp:时间戳 Date:存储当前日期或时间的UNIX时间格式

object id 每个文档都有一个属性,为_id,保证每个文档的唯一性 可以自己去设置_id插入文档 如果没有提供,那么MongoDB为每个文档提供了一个独特的_id,类型为objectID

objectID是一个12字节的十六进制数 前4个字节为当前时间戳 接下来3个字节的机器ID 接下来的2个字节中MongoDB的服务进程id 最后3个字节是简单的增量值

插入 语法 db.集合名称.insert(document) 插入文档时,如果不指定_id参数,MongoDB会为文档分配一个唯一的ObjectId db.stu.insert({name:'gj',gender:1})

s1={_id:'20160101',name:'hr'} s1.gender=0 db.stu.insert(s1)

查询语法 db.集合名称.find()

更新语法db.集合名称.update(<query>,<update>, {multi: <boolean>})参数query:查询条件,类似sql语句update中where部分参数update:更新操作符,类似sql语句update中set部分参数multi:可选,默认是false,表示只更新找到的第一条记录,值为true表示把满足条件的文档全部更新db.stu.update({name:'hr'},{name:'mnc'})指定属性更新,通过操作符

保存语法 db.集合名称.save(document) 如果文档的_id已经存在则修改,如果文档的_id不存在则添加 db.stu.save({_id:'20160102','name':'yk',gender:1}) db.stu.save({_id:'20160102','name':'wyk'})

删除语法 db.集合名称.remove(<query>, { justOne: <boolean> })

参数query:可选,删除的文档的条件 参数justOne:可选,如果设为true或1,则只删除一条,默认false,表示删除多条 db.stu.remove({gender:0},{justOne:true})

全部删除 db.stu.remove({})

备份与恢复

备份 语法 mongodump -h dbhost -d dbname -o dbdirectory -h:服务器地址,也可以指定端口号 -d:需要备份的数据库名称 -o:备份的数据存放位置,此目录中存放着备份出来的数据 例1 sudo mkdir test1bak sudo mongodump -h 192.168.196.128:27017 -d test1 -o ~/Desktop/test1bak 恢复 语法 mongorestore -h dbhost -d dbname --dir dbdirectory -h:服务器地址 -d:需要恢复的数据库实例 --dir:备份数据所在位置 例2 mongorestore -h 192.168.196.128:27017 -d test2 --dir ~/Desktop/test1bak/test1

授权

创建超级管理员账户 use admin db.createUser({ user:'root', pwd:'123456', roles:[{ role:'root', db:'admin' }] })

配置文件开启权限验证 security: authorization: enabled

mongodb查询

数据查询

基本查询方法find():查询db.集合名称.find({条件文档})方法findOne():查询,只返回第一个db.集合名称.findOne({条件文档})方法pretty():将结果格式化db.集合名称.find({条件文档}).pretty()比较运算符等于,默认是等于判断,没有运算符小于lt小于或等于lte大于gt大于或等于gte不等于ne例1:查询名称等于'gj'的学生db.stu.find({name:'gj'})例2:查询年龄大于或等于18的学生db.stu.find({age:{gte:18}})逻辑运算符查询时可以有多个条件,多个条件之间需要通过逻辑运算符连接逻辑与:默认是逻辑与的关系例3:查询年龄大于或等于18,并且性别为1的学生db.stu.find({age:{gte:18},gender:1})逻辑或:使用or例4:查询年龄大于18,或性别为0的学生db.stu.find({or:[{age:{gt:18}},{gender:1}]})and和or一起使用例5:查询年龄大于18或性别为0的学生,并且学生的姓名为gj

db.stu.find({or:[{age:{gte:18}},{gender:1}],name:'gj'})范围运算符使用"in","in:[18,28]}})支持正则表达式使用//或regex编写正则表达式例7:查询姓黄的学生db.stu.find({name:/^黄/})自定义查询使用where后面写一个函数,返回满足条件的数据例7:查询年龄大于30的学生db.stu.find({where:function(){return this.age>20}})

投影

在查询到的返回结果中,只选择必要的字段,而不是选择一个文档的整个字段 如:一个文档有5个字段,需要显示只有3个,投影其中3个字段即可 语法: 参数为字段与值,值为1表示显示,值为0不显示 db.集合名称.find({},{字段名称:1,...}) 对于需要显示的字段,设置为1即可,不设置即为不显示 特殊:对于_id列默认是显示的,如果不显示需要明确设置为0 db.stu.find({},{name:1,gender:1}) db.stu.find({},{_id:0,name:1,gender:1})

排序

方法sort(),用于对结果集进行排序 语法 db.集合名称.find().sort({字段:1,...}) 参数1为升序排列 参数-1为降序排列 根据性别降序,再根据年龄升序

db.stu.find().sort({gender:-1,age:1})

分页

Limit 方法limit():用于读取指定数量的文档 语法: db.集合名称.find().limit(NUMBER) 参数NUMBER表示要获取文档的条数 如果没有指定参数则显示集合中的所有文档 例1:查询2条学生信息 db.stu.find().limit(2) skip 方法skip():用于跳过指定数量的文档 语法: db.集合名称.find().skip(NUMBER) 参数NUMBER表示跳过的记录条数,默认值为0 例2:查询从第3条开始的学生信息 db.stu.find().skip(2) 一起使用 方法limit()和skip()可以一起使用,不分先后顺序 创建数据集 for(i=0;i<15;i ){db.t1.insert({_id:i})} 查询第5至8条数据 db.stu.find().limit(4).skip(5) 或 db.stu.find().skip(5).limit(4)

统计

统计个数 方法count()用于统计结果集中文档条数 语法 db.集合名称.find({条件}).count() 也可以与为 db.集合名称.count({条件}) 例1:统计男生人数 db.stu.find({gender:1}).count() 例2:统计年龄大于20的男生人数 db.stu.count({age:{$gt:20},gender:1})

去重

方法distinct()对数据进行去重 语法 db.集合名称.distinct('去重字段',{条件}) 例1:查找年龄大于18的性别(去重) db.stu.distinct('gender',{age:{$gt:18}})

python操作mongodb

安装python包 pip install pymongo 引入包pymongo import pymongo 连接,创建客户端 client=pymongo.MongoClient("localhost", 27017) 获得数据库test1 db=client[test1] 获得集合stu stu = db[stu] 添加文档 s1={name:'gj',age:18} s1_id = stu.insert_one(s1).inserted_id 查找一个文档 s2=stu.find_one() 查找多个文档1 for cur in stu.find(): print cur 查找多个文档2 cur=stu.find() cur.next() cur.next() cur.next() 获取文档个数 print stu.count()

redis基础

Redis简介

Remote DIctionary Server(Redis) 是一个key-value存储系统。 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。 Redis 与其他 key - value 缓存产品有以下三个特点: Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。 Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。 Redis支持数据的备份,即master-slave模式的数据备份

Ubuntu安装Redis

sudo apt-get install redis-server 停止服务 service redis stop 启动服务 service redis start 启动服务端 redis-server 启动客户端 redis-cli

Redis配置

以指定配置文件启动服务端 redis-server "C:Program FilesRedisredis.conf" 获取所有配置信息 config get * 获取单项配置信息 config get loglevel config get dbfilename ... 设置单项配置信息 config set loglevel warning config set ...

设置数据库的数量,默认数据库为0,可以使用SELECT <dbid>命令在连接上指定数据库id databases 16 绑定的主机地址 bind 127.0.0.1 绑定的主机端口 port 6379

指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 save <seconds><changes> Redis默认配置文件中提供了三个条件: save 900 1 save 300 10 save 60 10000 分别表示900秒(15分钟)内有1个更改,300秒(5分钟)内有10个更改以及60秒内有10000个更改。 指定本地数据库文件名,默认值为dump.rdb dbfilename dump.rdb 指定本地数据库存放目录 dir ./ 设置Redis连接密码,如果配置了连接密码,客户端在连接Redis时需要通过AUTH <password>命令提供密码,默认关闭 requirepass foobared 设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步 slaveof <masterip><masterport> 当master服务设置了密码保护时,slav服务连接master的密码 masterauth <master-password> Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no 当 客户端闲置多长时间后关闭连接,如果指定为0,表示关闭该功能 timeout 300

redis数据操作

数据类型

redis是key-value的数据,所以每个数据都是一个键值对 键的类型是字符串 值的类型分为五种: 字符串string 哈希hash 列表list 集合set 有序集合zset

String类型

设置 设置键值 set key value 设置键值及过期时间,以秒为单位 SETEX key seconds value redis> setex 1001 50 'zhouzhiruo'

设置多个键值 MSET key value [key value ...]

根据键获取值,如果不存在此键则返回nil GET key 根据多个键获取多个值 MGET key [key ...]

redis> MSET date "2012.3.30" time "11:00 a.m." weather "sunny" OK

redis> MGET date time weather 1) "2012.3.30" 2) "11:00 a.m." 3) "sunny"

要求:值是数字 将key对应的value加1 INCR key 将key对应的value加整数 INCRBY key increment 将key对应的value减1 redis> SET page_view 20 OK

redis> INCR page_view (integer) 21

redis> GET page_view # 数字值在 Redis 中以字符串的形式保存 "21"

键存在,并且值为数字:

redis> SET rank 50 OK

redis> INCRBY rank 20 (integer) 70

redis> GET rank "70" 键不存在:

redis> EXISTS counter (integer) 0

redis> INCRBY counter 30 (integer) 30

redis> GET counter "30" 键存在,但值无法被解释为数字:

redis> SET book "long long ago..." OK

redis> INCRBY book 200 (error) ERR value is not an integer or out of range

DECR key 将key对应的value减整数 DECRBY key decrement

对储存数字值的键 key 执行 DECR 命令:

redis> SET failure_times 10 OK

redis> DECR failure_times (integer) 9 对不存在的键执行 DECR 命令:

redis> EXISTS count (integer) 0

redis> DECR count (integer) -1

其它 追加值 APPEND key value

对不存在的 key 执行 APPEND :

redis> EXISTS myphone # 确保 myphone 不存在 (integer) 0

redis> APPEND myphone "nokia" # 对不存在的 key 进行 APPEND ,等同于 SET myphone "nokia" (integer) 5 # 字符长度 对已存在的字符串进行 APPEND :

redis> APPEND myphone " - 1110" # 长度从 5 个字符增加到 12 个字符 (integer) 12

redis> GET myphone "nokia - 1110"

获取值长度 STRLEN key 获取字符串值的长度:

redis> SET mykey "Hello world" OK

redis> STRLEN mykey (integer) 11 不存在的键的长度为 0 :

redis> STRLEN nonexisting (integer) 0

键操作

查找键,参数支持正则 KEYS pattern redis> MSET one 1 two 2 three 3 four 4 # 一次设置 4 个 key OK

redis> KEYS *o* 1) "four" 2) "two" 3) "one"

redis> KEYS t?? 1) "two"

redis> KEYS t[w]* 1) "two"

redis> KEYS * # 匹配数据库内所有 key 1) "four" 2) "three" 3) "two" 4) "one"

KEYS 的速度非常快,但在一个大的数据库中使用它仍然可能造成性能问题,如果你需要从一个数据集中查找特定的 key ,你最好还是用 Redis 的集合结构(set)来代替。

判断键是否存在,如果存在返回1,不存在返回0 EXISTS key [key ...] redis> SET db "redis" OK

redis> EXISTS db (integer) 1

redis> DEL db (integer) 1

redis> EXISTS db (integer) 0

查看键对应的value的类型 TYPE key # 字符串

redis> SET weather "sunny" OK

redis> TYPE weather string

# 列表

redis> LPUSH book_list "programming in scala" (integer) 1

redis> TYPE book_list list

# 集合

redis> SADD pat "dog" (integer) 1

redis> TYPE pat set

删除键及对应的值 DEL key [key ...] # 删除单个 key

redis> SET name huangz OK

redis> DEL name (integer) 1

# 删除一个不存在的 key

redis> EXISTS phone (integer) 0

redis> DEL phone # 失败,没有 key 被删除 (integer) 0

# 同时删除多个 key

redis> SET name "redis" OK

redis> SET type "key-value store" OK

redis> SET website "redis.com" OK

redis> DEL name type website (integer) 3

设置过期时间,以秒为单位 创建时没有设置过期时间则一直存在,直到使用使用DEL移除 EXPIRE key seconds

redis> SET cache_page "www.google.com" OK redis> EXPIRE cache_page 30 # 设置过期时间为 30 秒 (integer) 1

redis> TTL cache_page # 查看剩余生存时间 (integer) 23

redis> EXPIRE cache_page 30000 # 更新过期时间 (integer) 1

redis> TTL cache_page (integer) 29996

查看有效时间,以秒为单位 TTL key # 不存在的 key

redis> FLUSHDB OK

redis> TTL key (integer) -2

# key 存在,但没有设置剩余生存时间

redis> SET key value OK

redis> TTL key (integer) -1

# 有剩余生存时间的 key

redis> EXPIRE key 10086 (integer) 1

redis> TTL key (integer) 10084

hash

hash用于存储对象,对象的格式为键值对 设置 设置单个属性 HSET key field value 设置一个新域:

redis> HSET website google "www.g.cn" (integer) 1

redis> HGET website google "www.g.cn" 对一个已存在的域进行更新:

redis> HSET website google "www.google.com" (integer) 0

redis> HGET website google "www.google.com"

设置多个属性 HMSET key field value [field value ...] redis> HMSET website google www.google.com yahoo www.yahoo.com OK

redis> HGET website google "www.google.com"

redis> HGET website yahoo "www.yahoo.com"

获取 获取一个属性的值 HGET key field 域存在的情况:

redis> HSET homepage redis redis.com (integer) 1

redis> HGET homepage redis "redis.com" 域不存在的情况:

redis> HGET site mysql (nil)

获取多个属性的值 HMGET key field [field ...] redis> HMSET pet dog "doudou" cat "nounou" # 一次设置多个域 OK

redis> HMGET pet dog cat fake_pet # 返回值的顺序和传入参数的顺序一样 1) "doudou" 2) "nounou" 3) (nil) # 不存在的域返回nil值

获取所有属性和值 HGETALL key redis> HSET people jack "Jack Sparrow" (integer) 1

redis> HSET people gump "Forrest Gump" (integer) 1

redis> HGETALL people 1) "jack" # 域 2) "Jack Sparrow" # 值 3) "gump" 4) "Forrest Gump"

获取所有的属性 HKEYS key # 哈希表非空

redis> HMSET website google www.google.com yahoo www.yahoo.com OK

redis> HKEYS website 1) "google" 2) "yahoo"

# 空哈希表/key不存在

redis> EXISTS fake_key (integer) 0

redis> HKEYS fake_key (empty list or set)

返回包含属性的个数 HLEN key redis> HSET db redis redis.com (integer) 1

redis> HSET db mysql mysql.com (integer) 1

redis> HLEN db (integer) 2

redis> HSET db mongodb mongodb.org (integer) 1

redis> HLEN db (integer) 3

获取所有值 HVALS key # 非空哈希表

redis> HMSET website google www.google.com yahoo www.yahoo.com OK

redis> HVALS website 1) "www.google.com" 2) "www.yahoo.com"

# 空哈希表/不存在的key

redis> EXISTS not_exists (integer) 0

redis> HVALS not_exists (empty list or set)

其它 判断属性是否存在 HEXISTS key field 给定域不存在:

redis> HEXISTS phone myphone (integer) 0 给定域存在:

redis> HSET phone myphone nokia-1110 (integer) 1

redis> HEXISTS phone myphone (integer) 1

删除属性及值 HDEL key field [field ...] # 测试数据

redis> HGETALL abbr 1) "a" 2) "apple" 3) "b" 4) "banana" 5) "c" 6) "cat" 7) "d" 8) "dog"

# 删除单个域

redis> HDEL abbr a (integer) 1

# 删除不存在的域

redis> HDEL abbr not-exists-field (integer) 0

# 删除多个域

redis> HDEL abbr b c (integer) 2

redis> HGETALL abbr 1) "d" 2) "dog"

返回值的字符串长度 HSTRLEN key field redis> HMSET myhash f1 "HelloWorld" f2 "99" f3 "-256" OK

redis> HSTRLEN myhash f1 (integer) 10

redis> HSTRLEN myhash f2 (integer) 2

redis> HSTRLEN myhash f3 (integer) 4

list

列表的元素类型为string 按照插入顺序排序 在列表的头部或者尾部添加元素

设置 在头部插入数据 LPUSH key value [value ...] # 加入单个元素

redis> LPUSH languages python (integer) 1

# 加入重复元素

redis> LPUSH languages python (integer) 2

redis> LRANGE languages 0 -1 # 列表允许重复元素 1) "python" 2) "python"

# 加入多个元素

redis> LPUSH mylist a b c (integer) 3

redis> LRANGE mylist 0 -1 1) "c" 2) "b" 3) "a"

在尾部插入数据 RPUSH key value [value ...]

# 添加单个元素

redis> RPUSH languages c (integer) 1

# 添加重复元素

redis> RPUSH languages c (integer) 2

redis> LRANGE languages 0 -1 # 列表允许重复元素 1) "c" 2) "c"

# 添加多个元素

redis> RPUSH mylist a b c (integer) 3

redis> LRANGE mylist 0 -1 1) "a" 2) "b" 3) "c"

在一个元素的前|后插入新元素 LINSERT key BEFORE|AFTER pivot value redis> RPUSH mylist "Hello" (integer) 1

redis> RPUSH mylist "World" (integer) 2

redis> LINSERT mylist BEFORE "World" "There" (integer) 3

redis> LRANGE mylist 0 -1 1) "Hello" 2) "There" 3) "World"

# 对一个非空列表插入,查找一个不存在的 pivot

redis> LINSERT mylist BEFORE "go" "let's" (integer) -1 # 失败

# 对一个空列表执行 LINSERT 命令

redis> EXISTS fake_list (integer) 0

redis> LINSERT fake_list BEFORE "nono" "gogogog" (integer) 0 # 失败

设置指定索引的元素值 索引是基于0的下标 索引可以是负数,表示偏移量是从list尾部开始计数,如-1表示列表的最后一个元素 LSET key index value # 对空列表(key 不存在)进行 LSET

redis> EXISTS list (integer) 0

redis> LSET list 0 item (error) ERR no such key

# 对非空列表进行 LSET

redis> LPUSH job "cook food" (integer) 1

redis> LRANGE job 0 0 1) "cook food"

redis> LSET job 0 "play game" OK

redis> LRANGE job 0 0 1) "play game"

# index 超出范围

redis> LLEN list # 列表长度为 1 (integer) 1

redis> LSET list 3 'out of range' (error) ERR index out of range

移除并且返回 key 对应的 list 的第一个元素 LPOP key redis> LLEN course (integer) 0

redis> RPUSH course algorithm001 (integer) 1

redis> RPUSH course c 101 (integer) 2

redis> LPOP course # 移除头元素 "algorithm001"

移除并返回存于 key 的 list 的最后一个元素 RPOP key redis> RPUSH mylist "one" (integer) 1

redis> RPUSH mylist "two" (integer) 2

redis> RPUSH mylist "three" (integer) 3

redis> RPOP mylist # 返回被弹出的元素 "three"

redis> LRANGE mylist 0 -1 # 列表剩下的元素 1) "one" 2) "two"

返回存储在 key 的列表里指定范围内的元素 start 和 end 偏移量都是基于0的下标 偏移量也可以是负数,表示偏移量是从list尾部开始计数,如-1表示列表的最后一个元素 LRANGE key start stop

redis> RPUSH fp-language lisp (integer) 1

redis> LRANGE fp-language 0 0 1) "lisp"

redis> RPUSH fp-language scheme (integer) 2

redis> LRANGE fp-language 0 1 1) "lisp" 2) "scheme"

裁剪列表,改为原集合的一个子集 start 和 end 偏移量都是基于0的下标 偏移量也可以是负数,表示偏移量是从list尾部开始计数,如-1表示列表的最后一个元素 LTRIM key start stop

# 情况 1: 常见情况, start 和 stop 都在列表的索引范围之内

redis> LRANGE alpha 0 -1 # alpha 是一个包含 5 个字符串的列表 1) "h" 2) "e" 3) "l" 4) "l" 5) "o"

redis> LTRIM alpha 1 -1 # 删除 alpha 列表索引为 0 的元素 OK

redis> LRANGE alpha 0 -1 # "h" 被删除了 1) "e" 2) "l" 3) "l" 4) "o"

# 情况 2: stop 比列表的最大下标还要大

redis> LTRIM alpha 1 10086 # 保留 alpha 列表索引 1 至索引 10086 上的元素 OK

redis> LRANGE alpha 0 -1 # 只有索引 0 上的元素 "e" 被删除了,其他元素还在 1) "l" 2) "l" 3) "o"

# 情况 3: start 和 stop 都比列表的最大下标要大,并且 start < stop

redis> LTRIM alpha 10086 123321 OK

redis> LRANGE alpha 0 -1 # 列表被清空 (empty list or set)

# 情况 4: start 和 stop 都比列表的最大下标要大,并且 start > stop

redis> RPUSH new-alpha "h" "e" "l" "l" "o" # 重新建立一个新列表 (integer) 5

redis> LRANGE new-alpha 0 -1 1) "h" 2) "e" 3) "l" 4) "l" 5) "o"

redis> LTRIM new-alpha 123321 10086 # 执行 LTRIM OK

redis> LRANGE new-alpha 0 -1 # 同样被清空 (empty list or set)

返回存储在 key 里的list的长度 LLEN key # 空列表

redis> LLEN job (integer) 0

# 非空列表

redis> LPUSH job "cook food" (integer) 1

redis> LPUSH job "have lunch" (integer) 2

redis> LLEN job (integer) 2

返回列表里索引对应的元素 LINDEX key index redis> LPUSH mylist "World" (integer) 1

redis> LPUSH mylist "Hello" (integer) 2

redis> LINDEX mylist 0 "Hello"

redis> LINDEX mylist -1 "World"

redis> LINDEX mylist 3 # index不在 mylist 的区间范围内 (nil)

set

无序集合 元素为string类型 元素具有唯一性,不重复

添加元素 SADD key member [member ...] # 添加单个元素

redis> SADD bbs "discuz.net" (integer) 1

# 添加重复元素

redis> SADD bbs "discuz.net" (integer) 0

# 添加多个元素

redis> SADD bbs "tianya.cn" "groups.google.com" (integer) 2

redis> SMEMBERS bbs 1) "discuz.net" 2) "groups.google.com" 3) "tianya.cn"

返回key集合所有的元素 SMEMBERS key # key 不存在或集合为空

redis> EXISTS not_exists_key (integer) 0

redis> SMEMBERS not_exists_key (empty list or set)

# 非空集合

redis> SADD language Ruby Python Clojure (integer) 3

redis> SMEMBERS language 1) "Python" 2) "Ruby" 3) "Clojure"

返回集合元素个数 SCARD key redis> SADD tool pc printer phone (integer) 3

redis> SCARD tool # 非空集合 (integer) 3

redis> DEL tool (integer) 1

redis> SCARD tool # 空集合 (integer) 0

求多个集合的交集 SINTER key [key ...] redis> SMEMBERS group_1 1) "LI LEI" 2) "TOM" 3) "JACK"

redis> SMEMBERS group_2 1) "HAN MEIMEI" 2) "JACK"

redis> SINTER group_1 group_2 1) "JACK"

求某集合与其它集合的差集 SDIFF key [key ...] redis> SMEMBERS peter's_movies 1) "bet man" 2) "start war" 3) "2012"

redis> SMEMBERS joe's_movies 1) "hi, lady" 2) "Fast Five" 3) "2012"

redis> SDIFF peter's_movies joe's_movies 1) "bet man" 2) "start war"

求多个集合的合集 SUNION key [key ...] redis> SMEMBERS songs 1) "Billie Jean"

redis> SMEMBERS my_songs 1) "Believe Me"

redis> SUNION songs my_songs 1) "Billie Jean" 2) "Believe Me"

判断元素是否在集合中 SISMEMBER key member redis> SMEMBERS joe's_movies 1) "hi, lady" 2) "Fast Five" 3) "2012"

redis> SISMEMBER joe's_movies "bet man" (integer) 0

redis> SISMEMBER joe's_movies "Fast Five" (integer) 1

zset

sorted set,有序集合 元素为string类型 元素具有唯一性,不重复 每个元素都会关联一个double类型的score,表示权重,通过权重将元素从小到大排序 元素的score可以相同

添加 ZADD key score member [score member ...] # 添加单个元素

redis> ZADD page_rank 10 google.com (integer) 1

# 添加多个元素

redis> ZADD page_rank 9 baidu.com 8 bing.com (integer) 2

redis> ZRANGE page_rank 0 -1 WITHSCORES 1) "bing.com" 2) "8" 3) "baidu.com" 4) "9" 5) "google.com" 6) "10"

# 添加已存在元素,且 score 值不变

redis> ZADD page_rank 10 google.com (integer) 0

redis> ZRANGE page_rank 0 -1 WITHSCORES # 没有改变 1) "bing.com" 2) "8" 3) "baidu.com" 4) "9" 5) "google.com" 6) "10"

# 添加已存在元素,但是改变 score 值

redis> ZADD page_rank 6 bing.com (integer) 0

redis> ZRANGE page_rank 0 -1 WITHSCORES # bing.com 元素的 score 值被改变 1) "bing.com" 2) "6" 3) "baidu.com" 4) "9" 5) "google.com" 6) "10"

返回指定范围内的元素 ZRANGE key start stop redis > ZRANGE salary 0 -1 WITHSCORES # 显示整个有序集成员 1) "jack" 2) "3500" 3) "tom" 4) "5000" 5) "boss" 6) "10086"

redis > ZRANGE salary 1 2 WITHSCORES # 显示有序集下标区间 1 至 2 的成员 1) "tom" 2) "5000" 3) "boss" 4) "10086"

redis > ZRANGE salary 0 200000 WITHSCORES # 测试 end 下标超出最大下标时的情况 1) "jack" 2) "3500" 3) "tom" 4) "5000" 5) "boss" 6) "10086"

redis > ZRANGE salary 200000 3000000 WITHSCORES # 测试当给定区间不存在于有序集时的情况 (empty list or set)

返回元素个数 ZCARD key redis > ZADD salary 2000 tom # 添加一个成员 (integer) 1

redis > ZCARD salary (integer) 1

redis > ZADD salary 5000 jack # 再添加一个成员 (integer) 1

redis > ZCARD salary (integer) 2

redis > EXISTS non_exists_key # 对不存在的 key 进行 ZCARD 操作 (integer) 0

redis > ZCARD non_exists_key (integer) 0

返回有序集key中,score值在min和max之间的成员 ZCOUNT key min max redis> ZRANGE salary 0 -1 WITHSCORES # 测试数据 1) "jack" 2) "2000" 3) "peter" 4) "3500" 5) "tom" 6) "5000"

redis> ZCOUNT salary 2000 5000 # 计算薪水在 2000-5000 之间的人数 (integer) 3

redis> ZCOUNT salary 3000 5000 # 计算薪水在 3000-5000 之间的人数 (integer) 2

返回有序集key中,成员member的score值 ZSCORE key member redis> ZRANGE salary 0 -1 WITHSCORES # 测试数据 1) "tom" 2) "2000" 3) "peter" 4) "3500" 5) "jack" 6) "5000"

redis> ZSCORE salary peter # 注意返回值是字符串 "3500"

redis高级

发布订阅

发布者不是计划发送消息给特定的接收者(订阅者),而是发布的消息分到不同的频道,不需要知道什么样的订阅者订阅。

订阅者对一个或多个频道感兴趣,只需接收感兴趣的消息,不需要知道什么样的发布者发布的发布者和订阅者的解耦合可以带来更大的扩展性和更加动态的网络拓扑客户端发到频道的消息,将会被推送到所有订阅此频道的客户端。

客户端不需要主动去获取消息,只需要订阅频道,这个频道的内容就会被推送过来消息的格式。

推送消息的格式包含三部分 part1:消息类型,包含三种类型 subscribe,表示订阅成功 unsubscribe,表示取消订阅成功 message,表示其它终端发布消息

如果第一部分的值为subscribe,则第二部分是频道,第三部分是现在订阅的频道的数量 如果第一部分的值为unsubscribe,则第二部分是频道,第三部分是现在订阅的频道的数量,如果为0则表示当前没有 订阅任何频道,当在Pub/Sub以外状态,客户端可以发出任何redis命令 如果第一部分的值为message,则第二部分是来源频道的名称,第三部分是消息的内容 命令 订阅 SUBSCRIBE 频道名称 [频道名称 ...] 取消订阅 如果不写参数,表示取消所有订阅 UNSUBSCRIBE 频道名称 [频道名称 ...] 发布 PUBLISH 频道 消息

主从配置

一个master可以拥有多个slave,一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构 比如,将ip为192.168.1.10的机器作为主服务器,将ip为192.168.1.11的机器作为从服务器 设置主服务器的配置 bind 192.168.1.10 设置从服务器的配置 注意:在slaveof后面写主机ip,再写端口,而且端口必须写 bind 192.168.1.11 slaveof 192.168.1.10 6379

在master和slave分别执行info命令,查看输出信息 在master上写数据 set hello world 在slave上读数据 get hello

安全配置

Redis 安全 配置密码 查看密码 CONFIG get requirepass

设置密码 CONFIG set requirepass 123456

远程连接 redis-cli -h 127.0.0.1 -p 6379 -a 123456

登录之后授权 auth 123456

python操作redis

redis模块使用

安装 pip install redis 引入模块 import redis 连接 try: r=redis.StrictRedis(host='localhost',port=6379) except Exception,e: print e.message

方式一:根据数据类型的不同,调用相应的方法,完成读写 更多方法同前面学的命令 r.set('name','hello') r.get('name')

方式二:pipline 缓冲多条命令,然后一次性执行,减少服务器-客户端之间TCP数据库包,从而提高效率 pipe = r.pipeline() pipe.set('name', 'world') pipe.get('name') pipe.execute()

封装

连接redis服务器部分是一致的 这里将string类型的读写进行封装 import redis class RedisHelper(): def __init__(self,host='localhost',port=6379): self.__redis = redis.StrictRedis(host, port) def get(self,key): if self.__redis.exists(key): return self.__redis.get(key) else: return "" def set(self,key,value): self.__redis.set(key,value)

示例:用户登录

业务过程如下: 输入用户名、密码 密码加密 判断redis中是否记录了用户名,如果有则成功 如果redis中没有用户名,则到mysql中查询 从mysql中查询成功后,将用户名记录到redis中 from t2 import RedisHelper from t3 import MysqlHelper import hashlib name=raw_input("请输入用户名:") pwd=raw_input("请输入密码:") sha1=hashlib.sha1() sha1.update(pwd) pwd1=sha1.hexdigest() try: redis=RedisHelper() if redis.get('uname')==name: print 'ok' else: mysql=MysqlHelper('localhost',3306,'test1','root','mysql') upwd=mysql.get_one('select upwd from userinfos where uname=%s',[name]) if upwd==None: print '用户名错误' elif upwd[0]==pwd1: redis.set('uname', name) print '登录成功' else: print "密码错误" except Exception,e: print e.message

0 人点赞