58到家数据库30条军规
在开发中有很多设计数据库的软件,常用的如power designer,db desinger等,这些软件可以直观的看到实体及实体间的关系
SQL语言主要分为:
分类 | 解释 |
---|---|
DQL | 数据查询语言,用于对数据进行查询,如select |
DML | 数据操作语言,对数据进行增加、修改、删除,如insert、udpate、delete |
TPL | 事务处理语言,对事务进行处理,包括begin transaction、commit、rollback |
DCL | 数据控制语言,进行授权与权限回收,如grant、revoke |
DDL | 数据定义语言,进行数据库、表的管理等,如create、drop |
CCL | 指针控制语言,通过控制指针完成表的操作,如declare cursor |
SQL不区分大小写
安装客户端:
sudo apt-get install mysql-client
安装完SQL5.7之后没有设置root
的密码,运行:
sudo mysql_secure_installation
1. 前往下载页面下载MySQL APT repository
https://dev.mysql.com/downloads/repo/apt/
2. 使用如下命令安装配置
包名换成刚才下载的.deb
名称
shell> sudo dpkg -i /PATH/version-specific-package-name.deb
安装期间会被提示选择MySQL server的版本和其他组件,如果不确定的话就选择默认即可
3. 更新
shell> sudo apt-get update
shell> sudo apt-get install mysql-server
安装过程中会提示设置root用户密码,记住这个密码
shell> sudo service mysql status
shell> sudo service mysql start
shell> sudo service mysql stop
推荐:
sudo apt-get remove --purge mysql-server
或者:
# 先移除mysql server
shell> sudo apt-get remove mysql-server
# 再移除其他安装的包
shell> sudo apt-get autoremove
# 移除mysql apt repository
shell> sudo apt-get remove mysql-apt-config
# 检查是否完全删除
shell> dpkg -l | grep mysql | grep ii
按照上面的删除方法,并没有删除全部的依赖和配置文件,解决办法:
tar -zcvf ~/msql_backup.tar.gz /etc/mysql /var/lib/mysql
sudo apt purge mysql-server mysql-client mysql-common mysql-server-core mysql-client-core
sudo rm -rfv /etc/mysql /var/lib/mysql
sudo apt autoremove
sudo apt autoclean
参考链接: https://askubuntu.com/questions/763534/cannot-reinstall-mysql-server-after-its-purge
常用数据类型如下:
decimal(5,2)
代表数字有共有5个,小数位2个对于图片、音频、视频等文件,不存储在数据库中,而是上传到某个服务器上,然后在表中存储这个文件的保存路径
数值类型:
类型 | 字节大小 | 有符号范围(Signed) | 无符号范围(Unsigned) |
---|---|---|---|
TINYINT | 1 | -128 ~ 127 | 0 ~ 255 |
SMALLINT | 2 | -32768 ~ 32767 | 0 ~ 65535 |
MEDIUMINT | 3 | -8388608 ~ 8388607 | 0 ~ 16777215 |
INT/INTEGER | 4 | -2147483648 ~2147483647 | 0 ~ 4294967295 |
BIGINT | 8 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
字符串:
类型 | 字节大小 | 示例 |
---|---|---|
CHAR | 0-255 | 类型:char(3) 输入 ‘ab’, 实际存储为’ab ‘, 输入’abcd’ 实际存储为 ‘abc’ |
VARCHAR | 0-255 | 类型:varchar(3) 输 ‘ab’,实际存储为’ab’, 输入’abcd’,实际存储为’abc’ |
TEXT | 0-65535 | 大文本 |
日期时间类型:
类型 | 字节大小 | 示例 |
---|---|---|
DATE | 4 | ‘2020-01-01’ |
TIME | 3 | ‘12:29:59’ |
DATETIME | 8 | ‘2020-01-01 12:29:59’ |
YEAR | 1 | ‘2017’ |
TIMESTAMP | 4 | ‘1970-01-01 00:00:01’ UTC ~ ‘2038-01-01 00:00:01’ UTC |
primary key
:物理上存储的顺序not null
:此字段不允许填写空值unique
:此字段的值不允许重复default
:当不填写此值时会使用默认值,如果填写时以填写为准foreign key
:对关系字段进行约束,当为关系字段填写值时,会到关联的表中查询此值是否存在,如果存在则填写成功,如果不存在则填写失败并抛出异常说明:虽然外键约束可以保证数据的有效性,但是在进行数据的crud(增加、修改、删除、查询)时,都会降低数据库的性能,所以不推荐使用,那么数据的有效性怎么保证呢?答:可以在逻辑层进行控制
命令 | 说明 |
---|---|
mysql --help |
查看所有命令和帮助 |
mysql -u用户名 -p |
连接数据库(本地) |
mysql -h host -u user -p |
连接数据库 |
exit| quit | ctrl+d |
退出mysql交互环境 |
SHOW DATABASES |
显示自己有权限查看的数据库 |
SELECT CURRENT_DATE; |
显示当前日期 |
SELECT NOW(); |
显示当前时间 |
SELECT VERSION(); |
显示当前版本 |
USE 数据库名 |
使用数据库 |
CREATE DATABASE 数据库名称 CHARSET=UTF8; --注意这里没有 -
SHOW CREATE DATABASE 数据库名称;
DROP DATABASE 数据库名称;
-- 如果数据库名称中有特殊符号,就加上 ``
DROP DATABASE `PYTHON-04`;
USE 数据库名;
SELECT DATABASE();
mysqldump –uroot –p 数据库名 > python.sql;
# 按提示输入mysql的密码
要先创建数据库,再运行sql语句
mysql -uroot –p 新数据库名 < python.sql
# 根据提示输入mysql密码
SHOW TABLES;
CREATE TABLE 表名(
字段名 类型 [约束],
字段名 类型 [约束],
...
);
CREATE TABLE MAIN(
ID INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(255)
)
CREATE TABLE MAIN(
ID INT UNSIGNED, -- 还能指定有没有符号
NAME VARCHAR(255)
)
-- 一个完整的表
CREATE TABLE STUDENTS(
ID INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(30);
AGE TINYINT UNSIGNED DEFAULT 0;
HIGH DECIMAL(5,2);
GENDER ENUM("男","女","中性","保密") DEFAULT "保密",
CLS_ID INT UNSIGNED;
)
-- 约束写最后:
CREATE TABLE table_name(
column1 datatype contrai,
column2 datatype,
column3 datatype,
.....
columnN datatype,
PRIMARY KEY(one or more columns)
);
DESC 表名;
rename table 原表名 to 新表名;
ALTER TABLE 表名 ADD 列名 类型;
alter table 表名 change 原名 新名 类型及约束;
ALTER TABLE 表名 MODIFY 列名 类型及约束;
ALTER TABLE 表名 DROP 列名;
DROP TABLE 表名;
SHOW CREATE TABLE 表名;
InnoDB引擎比 MyISAM最主要的区别是 支持事务处理、外键、行级锁
-- 全部插入
INSERT INTO 表名 VALUES(值,值...);
-- 部分插入
INSERT INTO 表名(列, 列) VALUES(值,值);
-- 多行插入
INSERT INTO 表名(列, 列) VALUES(值,值),(值,值),(值,值).. ;
0
,null
,default
来默认设置default
来插入UPDATE 表名 SET 列=值, 列=值... WHERE 条件;
DELETE FROM 表名 WHERE 条件;
SELECT * FROM 表名 WHERE 条件;
SELECT 列名 [AS 别名], 列名 [AS 别名], 列名 [AS 别名] FROM 表名;
select * from 表名 where 条件;
where后面支持多种运算符,进行条件的处理:
= < <= > >= != 或者 <>
and or not
like
%
表示任意字符,0个—多个_
表示任意一个select * from students where name like '黄%'; --黄开头的任何
select * from students where name like '黄_'; -- 黄开头并且是2个字
in
between and
select * from students where id in(1,3,8);
select * from students where id between 3 and 8;
is null
is not null
select * from 表名 order by 列1 asc|desc [,列2 asc|desc,...]
sum
count
min
max
avg
SELECT SUM(AGE)/COUNT(*) FROM STUDENT; --可以做计算
SELECT ROUND(SUM(AGE)/COUNT(*),2) FROM STUDENT; --ROUND函数可以指定保留小数
在数据库中存储小数点,总是容易出误差,解决办法是 将结果存储100、1000等变成整数
SELECT ... FROM ... GROUP BY 列名.
查看组内有哪些内容:group_concat
SELECT COUNT(*), GROUP_CONCAT(NAME) FROM STUDENT;
SELECT COUNT(*), GROUP_CONCAT(NAME,ID) FROM STUDENT;
SELECT COUNT(*), GROUP_CONCAT(NAME,"分隔符",ID) FROM STUDENT;
分组后筛选:
SELECT GENDER FROM STUDENT GROUP BY GENDER HAVING AVG(AGE)>30;
where 是对表内容进行过滤,而having是对groupby之后的临时结果集进行过滤
with rollup:
with rollup
的作用是在最后新增一行,来记录当前列里所有记录的总和
select gender,count(*) from students group by gender with rollup;
+--------+----------+
| gender | count(*) |
+--------+----------+
| 男 | 5 |
| 女 | 7 |
| 中性 | 1 |
| 保密 | 1 |
| NULL | 14 |
+--------+----------+
LIMIT start count
SELECT * FROM STUDENT LIMIT 5; -- 限制个数
SELECT * FROM STUDENT LIMIT 0,5; -- 从第几个开始,限制几个(第一条记录的索引为0)
MYSQl中的连接:
left join/left outer join
right join/right outer join
inner join/join
select * from 表1 inner或left或right join 表2 on 表1.列 = 表2.列
连接之后可以筛选,dongge的意思是,只有在对原表筛选的时候使用where
,而其他的临时结果进行筛选都用having
:
select * from students inner join classes on students.cls_id = classes.id having student.age>18;
select city.* from areas as city
inner join areas as province on city.pid=province.aid
where province.atitle='山西省';
在一个 select 语句中,嵌入了另外一个 select 语句, 那么被嵌入的 select 语句称之为子查询语句
select * from students where age > (select avg(age) from students);
select name from classes where id in (select cls_id from students);
select * from students where (height,age) = (select max(height),max(age) from students);
select * from goods
inner join
(
select
cate_name,
max(price) as max_price,
min(price) as min_price,
avg(price) as avg_price,
count(*) from goods group by cate_name
) as goods_new_info
on goods.cate_name=goods_new_info.cate_name and goods.price=goods_new_info.max_price;
SELECT select_expr [,select_expr,...] [
FROM tb_name
[WHERE 条件判断]
[GROUP BY {col_name | postion} [ASC | DESC], ...]
[HAVING WHERE 条件判断]
[ORDER BY {col_name|expr|postion} [ASC | DESC], ...]
[ LIMIT {[offset,]rowcount | row_count OFFSET offset}]
]
执行顺序为:
在/etc/mysql/mysql.conf.d/mysqld.cnf
中设置 bind-address = 0.0.0.0
或者 不设置这一句,代表允许localhost
以外的IP连接
上面配置了端口转发,意思就是 访问物理主机上的3306端口,就会转发给这个虚拟机的3306端口。
-- 创建 "京东" 数据库
create database jing_dong charset=utf8;
-- 使用 "京东" 数据库
use jing_dong;
-- 创建一个商品goods数据表
create table goods(
id int unsigned primary key auto_increment not null,
name varchar(150) not null,
cate_name varchar(40) not null,
brand_name varchar(40) not null,
price decimal(10,3) not null default 0,
is_show bit not null default 1,
is_saleoff bit not null default 0
);
-- 向goods表中插入数据
insert into goods values(0,'r510vc 15.6英寸笔记本','笔记本','华硕','3399',default,default);
insert into goods values(0,'y400n 14.0英寸笔记本电脑','笔记本','联想','4999',default,default);
insert into goods values(0,'g150th 15.6英寸游戏本','游戏本','雷神','8499',default,default);
insert into goods values(0,'x550cc 15.6英寸笔记本','笔记本','华硕','2799',default,default);
insert into goods values(0,'x240 超极本','超级本','联想','4880',default,default);
insert into goods values(0,'u330p 13.3英寸超极本','超级本','联想','4299',default,default);
insert into goods values(0,'svp13226scb 触控超极本','超级本','索尼','7999',default,default);
insert into goods values(0,'ipad mini 7.9英寸平板电脑','平板电脑','苹果','1998',default,default);
insert into goods values(0,'ipad air 9.7英寸平板电脑','平板电脑','苹果','3388',default,default);
insert into goods values(0,'ipad mini 配备 retina 显示屏','平板电脑','苹果','2788',default,default);
insert into goods values(0,'ideacentre c340 20英寸一体电脑 ','台式机','联想','3499',default,default);
insert into goods values(0,'vostro 3800-r1206 台式电脑','台式机','戴尔','2899',default,default);
insert into goods values(0,'imac me086ch/a 21.5英寸一体电脑','台式机','苹果','9188',default,default);
insert into goods values(0,'at7-7414lp 台式电脑 linux )','台式机','宏碁','3699',default,default);
insert into goods values(0,'z220sff f4f06pa工作站','服务器/工作站','惠普','4288',default,default);
insert into goods values(0,'poweredge ii服务器','服务器/工作站','戴尔','5388',default,default);
insert into goods values(0,'mac pro专业级台式电脑','服务器/工作站','苹果','28888',default,default);
insert into goods values(0,'hmz-t3w 头戴显示设备','笔记本配件','索尼','6999',default,default);
insert into goods values(0,'商务双肩背包','笔记本配件','索尼','99',default,default);
insert into goods values(0,'x3250 m4机架式服务器','服务器/工作站','ibm','6888',default,default);
insert into goods values(0,'商务双肩背包','笔记本配件','索尼','99',default,default);
直接从选择结果插入到表:
insert into goods_cates (name) select cate_name from goods group by cate_name;
联合表更新:
update goods as g inner join goods_cates as c on g.cate_name=c.name set g.cate_name=c.id;
直接创建的时候插入值
-- 在创建数据表的时候一起插入数据
-- 注意: 需要对brand_name 用as起别名,否则name字段就没有值
create table goods_brands (
id int unsigned primary key auto_increment,
name varchar(40) not null) select brand_name as name from goods group by brand_name;
同时更改多个列
alter table goods
change cate_name cate_id int unsigned not null,
change brand_name brand_id int unsigned not null;
添加外键
foreign key,只有 innodb数据库引擎 支持外键约束
-- 修改已存在的表
alter table goods add foreign key (brand_id) references goods_brands(id);
-- 创建表时添加
create table goods(
id int primary key auto_increment not null,
name varchar(40) default '',
price decimal(5,2),
cate_id int unsigned,
brand_id int unsigned,
is_show bit default 1,
is_saleoff bit default 0,
foreign key(cate_id) references goods_cates(id),
foreign key(brand_id) references goods_brands(id)
);
----删除外键
-- 需要先获取外键约束名称,该名称系统会自动生成,可以通过查看表创建语句来获取名称
show create table goods;
-- 获取名称之后就可以根据名称来删除外键约束
alter table goods drop foreign key 外键名称;
在实际开发中,很少会使用到外键约束,会极大的降低表更新的效率
import pymysql
conn = pymysql.connect(参数列表)
...
conn.close()
# 例子
如果不能联网,下载
whl
文件,然后pip install xxxx.whl
来安装
connect方法参数 | 含义 |
---|---|
host | 连接的mysql主机,如果本机是’localhost’ |
port | 连接的mysql主机的端口,默认是3306 |
database | 数据库的名称 |
user | 连接的用户名 |
password | 连接的密码 |
charset | 通信采用的编码方式,推荐使用utf8 |
connect对象的方法 | 含义 |
---|---|
close |
关闭连接 |
commit |
提交,增删改的时候需要 |
rollback |
回滚,增删改的时候需要 |
cursor |
创建cursor,用于执行SQL语句 |
cur = conn.cursor()
cursor对象的方法 | 含义 |
---|---|
close |
关闭连接 |
execute |
执行SQL语句,返回的是受影响的行数 |
fetchone |
依次返回下一条记录,记录是一个元祖 |
fetchmany |
获取结果集中指定数量的记录,每条记录组成一个元祖,整个结果组成一个大元祖 |
fetchall |
获取结果集所有记录,每条记录组成一个元祖, 整个结果集是一个大的元祖 |
cursor对象的属性 | 含义 |
---|---|
rowcount |
获取最近依次execute 方法受影响的行数 |
connection |
获取当前连接对象 |
Python执行代码默认是开启了事务的
from pymysql import *
def main():
# 创建Connection连接
conn = connect(host='localhost',port=3306,database='jing_dong',user='root',password='mysql',charset='utf8')
# 获得Cursor对象
cs1 = conn.cursor()
# 执行insert语句,并返回受影响的行数:添加一条数据
# 增加
count = cs1.execute('insert into goods_cates(name) values("硬盘")')
#打印受影响的行数
print(count)
count = cs1.execute('insert into goods_cates(name) values("光盘")')
print(count)
# # 更新
# count = cs1.execute('update goods_cates set name="机械硬盘" where name="硬盘"')
# # 删除
# count = cs1.execute('delete from goods_cates where id=6')
# 提交之前的操作,如果之前已经之执行过多次的execute,那么就都进行提交
conn.commit()
# 关闭Cursor对象
cs1.close()
# 关闭Connection对象
conn.close()
if __name__ == '__main__':
main()
添加了记录之后,就算没有提交,或者就算之后rollback了,那么主键自增也不会回去了。
count = cs1.execute('select id,name from goods where id>=4')
for i in range(count):
# 获取查询的结果
result = cs1.fetchone()
# 打印查询的结果
print(result)
# 获取查询的结果
# 或者
cs1.fetchmany(5)
cs1.fetchall()
将参数作为execute
之后的参数传入,而不是自己拼接字符串
params = [find_name]
# 执行select语句,并返回受影响的行数:查询所有数据
count = cs1.execute('select * from goods where name=%s', params)
视图是一张虚表,存储的是查询的规则。
优点:
CREATE VIEW 名称 AS
SELECT语句;
SHOW TABLES; -- 视图看起来就像一张表
DROP VIEW 名称;
只有innobdb引擎才有事务
begin;
或者 start transaction;
commit;
rollback;
begin;
--CURD操作...;
commit;
事务中增加了数据,就算回滚, auto_increment也还是会增加
参考书:高性能MySQL
索引是随着表而来的。 主键和外键自动会生成索引。
SHOW INDEX FROM 表;
CREATE INDEX 索引名称 ON 表名(字段名称(长度));
-- 例子
CREATE INDEX index_name on STUDENT(name(10)); -- 如果name是 varchar(10)
CREATE INDEX index_age on STUDENT(age ); -- int类型不需要加长度
DROP INDEX 索引名 ON 表名;
SET profiling=1; -- 开启时间监测
...各种语句
SHOW profiles; -- 查看语句运行时间
MySQL的账户可以分为以下几种
账户的操作主要包括:
mysql中有个数据库叫做mysql,里面的user表就是存储的用户信息:
select host,user,authentication_string from user;
-- host: 用户允许访问的主机
-- user:用户名
-- authentication_string: 加密后的密码
常用权限包括:create、alter、drop、insert、update、delete、select、all privileges
grant 权限列表 on 数据库 to '用户名'@'访问主机' identified by '密码';
--例子:
GRANT ALL PRIVILEGES ON itcast.* TO 'yyfyifan'@'localhost' IDENTIFIED BY 'password';
SHOW GRANTS FOR '用户名'@'主机地址';
grant 权限名称 on 数据库 to 账户@主机 with grant option;
WITH GRANT OPTION
的意思是,被赋予的权限,可以由该用户继续赋予别人。
-- 这一种是直接修改 user表的方式
update user set authentication_string=password('新密码') where user='用户名';
-- 要记得刷新权限
flush privileges
DROP USER '用户名'@'主机';
--第二种,直接修改user表
DELETE from user where user='用户名';
flush privileges
http://blog.csdn.net/lxpbs8851/article/details/10895085
- 不要设置 主机为%,虽然自己使用方便,但是敌人也可以通过尝试root账户的密码来攻击
- 对用户设置的时候,经常可以不设置 删除出权限,以防删库跑路
Mysql服务器之间的主从同步是基于二进制日志机制,主服务器使用二进制日志来记录数据库的变动情况,从服务器通过读取和执行该日志文件来保持和主服务器的数据一致。
在使用二进制日志时,主服务器的所有操作都会被记录下来,然后从服务器会接收到该日志的一个副本。从服务器可以指定执行该日志中的哪一类事件(譬如只插入数据或者只更新数据),默认会执行日志中的所有语句。
每一个从服务器会记录关于二进制日志的信息:文件名和已经处理过的语句,这样意味着不同的从服务器可以分别执行同一个二进制日志的不同部分,并且从服务器可以随时连接或者中断和服务器的连接。
主服务器和每一个从服务器都必须配置一个唯一的ID号(在my.cnf文件的[mysqld]模块下有一个server-id配置项),另外,每一个从服务器还需要通过CHANGE MASTER TO语句来配置它要连接的主服务器的ip地址,日志文件名称和该日志里面的位置(这些信息存储在主服务器的数据库里)
有很多种配置主从同步的方法,可以总结为如下的步骤:
因为从服务器同步主服务器,是依据主服务器上的日志文件来同步,而不是读取已有数据,这就需要先确保数据已经保存在从服务器上
主服务器上执行:
mysqldump -uroot -pmysql --all-databases --lock-all-tables > ~/master_db.sql
-u :用户名
-p :示密码
--all-databases :导出所有数据库
--lock-all-tables :执行操作时锁住所有表,防止操作时有数据修改
~/master_db.sql :导出的备份数据(sql文件)位置,可自己指定
从服务器上还原
mysql –uroot –pmysql < master_db.sql
打开配置文件:
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
设置 server-id 和 log_bin:
重启服务
sudo service mysql restart
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by 'slave';
FLUSH PRIVILEGES;
SHOW MASTER STATUS;
登录从服务器,执行:
change master to master_host='10.211.55.5', master_user='slave', master_password='slave',master_log_file='mysql-bin.000006', master_log_pos=590;
master_host:主服务器Ubuntu的ip地址
master_log_file: 前面查询到的主服务器日志文件名
master_log_pos: 前面查询到的主服务器日志文件位置
从服务器中,运行
mysql > start slave;
mysql > show slave status \G;
数据库名:与系统名相同
表名:系统名称缩写+_+表名。表名必须描述该表的用途,由单个或多个名词组成,首字母小写,后续单词首字母大写。
字段名:字段名必须描述该字段的用途,由单个或多个名词组成,首字母小写,后续单词首字母大写。这里跟其他地方的规范不太一样。阿里规范中要求必须使用下划线的格式,主要考虑某些环境mysql不区分大小写,有些环境区分大小写。其实只要查询时区分大小写就没有问题了,但如果使用下划线的命名方式,在字段映射的时候会非常麻烦。
主键字段:表名+Id
外键字段:与主表主键字段完全一样
主键:pk
_+表名
外键:fk
+从表名++主表名
视图:view
_+名名称
存储过程:prcd
_+名称
函数:fun
_+名称
触发器:trg
_+名称
索引:idx
_+名称