目录
使用SQLyog软件操作数据库
前提知识
数据库三层机构
1.所谓安装MySQL数据库,就是在主机安装一个数据库管理系统(DBMS),这个管理程序可以管理多个数据库。DBMS(database manage system)
2.一个数据库可以创建多个表,以保存数据。
3.数据库管理系统(DBMS)、数据库和表的关系如图所示:
数据在数据库的存储方式
表的一行成为一条记录(在Java程序中,一行程序往往使用对象表示),一行中的一列称为一个字段。
SQL语句分类
DDL:数据定义语句[create 表,库..]
DML:数据库操作语句[增加 insert,修改 update,删除delete]
DQL:数据查询语句[select]
DCL:数据控制语句[管理数据库:比如用户权限 grant revoke]
数据库操作
[这里是可选限制条件]
创建数据库
create database 数据库名 [CHARACTER SET 字符集 [COLLATE 校对规则]]
注意:
名字不能和关键字重名,如果想想重名则可使用反引号(英文输入法,tab键上面,!的左边)包裹名字
例如
create database `database`;
举个例子
# 创建一个使用utf8字符集的cs_db02数据库
CREATE DATABASE cs_db02 CHARACTER SET utf8;
# 创建一个使用utf8字符集,并带校对规则的cs_db03数据库
CREATE DATABASE cs_db03 CHARACTER SET utf8 COLLATE utf8_bin;
# 校对规则 utf8_bin 区分大小写 默认utf8_general_ci 不区分大小写
查看数据库
show databases;
使用数据库
use 数据库名
删除数据库
drop database 数据库名
删库是很危险的操作,所以一般操作时要谨慎使用
删除分为逻辑删除和物理删除,
备份数据库
mysqldump -u 用户名 -p -B 数据库1 数据库2 数据库n > 文件名sql(含路径)
例如:
mysqldump -u root -p -B cs_db01 cs_db03 > d:\\bak.sql
恢复数据库
Source 文件名.sql(含路径)
常用数据类型
注意decimal类型,如果设置第二个参数为0时可以表示整数
字符串细节
细节1:
char(4) //这个44表示字符数(最大255),不是字节数,不管中文还是字幕都是放四个,按字符计算。
varchar(4) //这个4表示字符数,不管时字母还是中文都是定义好的表的编码存放数据
共同点:不管是 中文还是英文字母,都是最多存放4个,是按照字符来存放的
细节2:
char(4)是定长(固定的大小),就是说,即使插入'aa',也会占用分配的4个字符的空间
varchar(4)是边长(变化的大小),就是说,如果插入'aa'实际占用空间大小并不是4个字符,而是按照实际占用空间来分配
特别注意:
varchar本身还需要占用1~3个字节来记录存放内容长度 L(实际数据大小) + (1~3)字节
细节3:
什么时候使用char,什么时候使用varchar
1.如果数据是定长,推荐使用char,比如md5的密码,邮编,手机号,身份证号码等等
2.如果一个字段的长度是不确定,我们使用varchar,比如留言,文章
查询速度:char > varchar
细节4:
在存放文本时,也可以使用text数据结构,可以将text列视为varchar列,注意text不能有默认值,大小0~2^16字节
如果希望存放更多字符,可以选择
mediumtext 0~2^24 或者longtext 0~2^32
- 根据存储的实现:可以考虑用 varchar 替代 text,因为 varchar 存储更弹性,存储数据少的话性能更高。
- 如果存储的数据大于 64K,就必须使用到 mediumtext,longtext,因为 varchar 已经存不下了。
- 如果 varchar(255+) 之后,和 text 在存储机制是一样的,性能也相差无几。
- 需要特别注意 varchar(255) 不只是 255byte,实质上有可能占用的更多。
表操作
对表操作的前提是进入该数据库,所以操作表前使用use 数据库进入数据库
创建表
create table 表名 (
字段名1 类型,
字段名2 类型,
字段名3 类型,
...
);
例如:
创建actor表,包含id和name
CREATE TABLE actor ( -- 演员表
id INT,
name VARCHAR(32)
);
查看表结构
desc 表名;
删除表
drop table 表名;
数据库CRUD语句
insert
insert into 表名 [(参数列表)] values(内容) [,(内容),(内容)...];
例如:
insert into actor (id, name) values(1,‘小明’);
解释第5点
字段是否可以为空时创建表的时候定义的,不为空可以在字段名类型后加not null
例如
create table t1 (
id int not null
);
看下面代码
insert into actor values('2', '小李');
代码不会报错,mysql会把字符串解析,如果是数字,直接替换,但是数字不可以解析为字符串。
updata
update 表名 set 修改内容 where 条件;
例如
修改id为1的名字为小王
update actor set name = '小王' where id = 1;
delete
delete from 表名 where 条件;
例如
删除id为1的记录
delete from actor where id = 1;
select
select 查询内容 from 表名[,表名,表名...] [限制条件];
例如
查询actor所有信息
select * from actor
别名
查询actor的id,name(分别命名为号,姓名)
select 查询的字段名 [as] 别名 from 表名 [限制条件];
select id as '号', name as '姓名' from actor
as可以省略
去重
查询actor的id(去除重复id)
select distinct 查询的字段名 form 表名 [限制条件];
select distinct id from actor;
排序
查询actor的全部信息(升序排列)
select 查询的字段名 from 表名 order by 排列字段 [asc/desc];
select * from actor order by id asc;
条件查询
比较运算符
运算符 | 说明 | ||||||||
>,>=,<,<= | 大于,大于等于,小于,小于等于 | ||||||||
= | 等于,NULL不安全,例如NULL = NULL 结果时NULL | ||||||||
<=> | 等于,NULL安全,例如NULL = NULL 结果时TRUE(1) | ||||||||
!=,<> | 不等于 | ||||||||
BETWEEN a0 END a1 | 范围分配,[a0,a1],如果 a0 <= value <= a1,返回TRUE | ||||||||
IN (option, ...) | 如果是option中任意一个,返回TRUE(1) | ||||||||
IS NULL | 是NULL | ||||||||
IS NOT NULL | 不是NULL | ||||||||
LIKE | 模糊查询,%表示任意多个(包括0个)任意字符; _表示任意一个字符 |
逻辑运算符
运算符 | 说明 | ||||||||
AND | 多个条件必须都为TRUE(1),结果才是TRUE(1) | ||||||||
OR | 任意一个条件为TRUE(1),结果为TRUE(1) | ||||||||
NOT | 条件为TRUE(1),结果为FALSE(0) |
注意:
1. WHERE条件可以使用表达式,但不能使用别名。
2. AND的优先级高于OR,在同时使用时,需要使用小括号()包裹优先执行的部分
函数
合计函数
count
count(*);//表示算出所有记录
count(列名1);//表示算出所有列名1不为NULL的总数
l例如
查询actor记录个数
select count(*) as '总记录数' from actor;
sum
sum(统计的列名)
例如
查询actor表的id之和
select sum(id) from actor;
avg
avg(统计的列名)
查询actor表的id平均值
select avg(id) from actor;
max/min
例如max(统计的列名)
查询actor表的id最大值
select max(id) from actor;
配合合计函数的语法——分组:group by
select 查询字段 from 表名 group by 分组字段;
例如
-- (1)显示每种岗位的雇员总数。平均工资
SELECT COUNT(empno),AVG(sal),job FROM emp GROUP BY job;#正确的
字符串函数
数学相关函数
日期相关函数
加密和系统函数
MySQL数据库的用户密码就是PASSWORD函数加密
查询增强
分页查询
select 查询字段 from 表名 限制条件 limit start, rows;
例如
-- 分页查询
-- 按雇员的id号升序取出,每页显示3条记录,请分别显示 第1页,第2页,第2页
-- 第一页
SELECT * FROM emp
ORDER BY empno
LIMIT 0, 3;
-- 第二页
SELECT * FROM emp
ORDER BY empno
LIMIT 3, 3;
数据分组的总结
如果select语句同时包含有[where]group by,having,limit,order by 那么他们的顺序是:
[where]group by,having,orderby,limit
多表查询
自连接
-- 思考题:显示公司员工名字和它的上级的名字
SELECT * FROM emp;
SELECT * FROM emp worker,emp boss;
SELECT worker.ename AS '员工', boss.ename AS '老板'
FROM emp worker,emp boss
WHERE worker.`mgr` = boss.`empno`;
-- 自连接的特点
-- 1. 把同一张表当作两张表使用
-- 2. 需要给表去别名 表名 表别名
-- 3. 列名不明确,可以指定列的别名 列名 as 列的别名
子查询
单列子查询
例如
请思考:如何显示与SMITH同一部门的所有员工?
/*
1. 先查询到 SMITH的部门号得到
2. 把上面的select 语句当做一个子查询来使用
*/
SELECT deptno
FROM emp
WHERE ename = 'SMITH';
SELECT *
FROM emp
WHERE deptno = (SELECT deptno
FROM emp
WHERE ename = 'SMITH');
查询和部门10的工作相同的雇员的
-- 名字、岗位、工资、部门号,但是不含10自己的信息
/*
1. 查询到10号部门有哪些工作
2. 把上面查询的结果当作子查询使用
*/
SELECT DISTINCT job
FROM emp
WHERE deptno = '20';
SELECT ename,job,sal,deptno
FROM emp
WHERE job IN (SELECT DISTINCT job
FROM emp
WHERE deptno = '10') AND deptno != 10;
多行子查询
如何显示工资比部门30的其中一个员工的工资高的员工的姓名、工资和部门号
常规思路
SELECT ename,sal,deptno
FROM emp
WHERE sal > (SELECT MIN(sal)
FROM emp
WHERE deptno = 30);#正确
上述代码其实可以用关键字ANY实现
SELECT ename,sal,deptno
FROM emp
WHERE sal > ANY(SELECT sal
FROM emp
WHERE deptno = 30);#正确
还有用关键字ALL实现
SELECT ename,sal,deptno
FROM emp
WHERE sal > ALL(SELECT sal
FROM emp
WHERE deptno = 30);#正确
多列子查询
例如
查找每个部门工资高于本部门平均工资的人的资料
SELECT AVG(sal) AS sal, deptno
FROM emp
GROUP BY deptno;
SELECT deptno, AVG(sal) AS sal
FROM emp
GROUP BY deptno;
SELECT ename, sal, avg_sal
FROM emp, (SELECT AVG(sal) AS avg_sal, deptno
FROM emp
GROUP BY deptno) temp
WHERE emp.`deptno` = temp.deptno AND emp.`sal` > temp.avg_sal;
-- 查找每个部门工资最高的人的详细资料
SELECT MAX(sal), deptno
FROM emp
GROUP BY deptno;
SELECT *
FROM emp
WHERE (sal, deptno) IN (SELECT MAX(sal) AS sal, deptno
FROM emp
GROUP BY deptno)
ORDER BY sal;#升序
使用临时表
SELECT emp.`sal`, temp.max_sal, emp.`deptno`
FROM emp, (SELECT MAX(sal) AS max_sal, deptno
FROM emp
GROUP BY deptno) temp
WHERE emp.sal = temp.max_sal AND emp.`deptno` = temp.deptno;
-- 显示每个部门的信息(包括:部门名,编号,地址)和人员数量
SELECT dname, dept.deptno, temp.aa AS '人数'
FROM dept, (SELECT COUNT(*) AS aa, deptno
FROM emp
GROUP BY deptno) temp
WHERE dept.`deptno` = temp.deptno;
-- 还有一种写法 表.* 表示将该表所有列都显示出来,可以简化sql语句
-- 在多表查询中,当多个表的列不重复时,才可以直接写列名
SELECT dname, temp.*
FROM dept, (SELECT COUNT(*) AS '人数', deptno
FROM emp
GROUP BY deptno) temp
WHERE dept.`deptno` = temp.deptno;
表复制
-- 表的复制
-- 为了对某个ssql语句进行效率测试,我们需要海量数据时,可以使用此法为表创建海量数据
表结构相同时
INSERT INTO my_tab_02
SELECT * FROM emp;
不同时则需要利用select查询子表赋值
INSERT INTO my_tab_01
(id, `name`, sal, job, deptno)
SELECT empno,ename,sal,job,deptno FROM emp;
合并查询
SELECT ename,sal,job FROM emp WHERE sal > 2500;
SELECT ename,sal,job FROM emp WHERE job='MANAGER';
-- union all 就是将两个查询结果合并,不会去重
SELECT ename,sal,job FROM emp WHERE sal > 2500
UNION ALL
SELECT ename,sal,job FROM emp WHERE job='MANAGER';
-- union 就是将两个查询结果合并,会去重
SELECT ename,sal,job FROM emp WHERE sal > 2500
UNION
SELECT ename,sal,job FROM emp WHERE job='MANAGER';
外连接
-- 使用左连接
-- (显示所有人的成绩,如果没有成绩,也要显示该人的姓名和id号,成绩显示为空)
将两个表联合,找到公共数据
SELECT `name`,stu.`id`,grade
FROM stu,exam
WHERE stu.`id` = exam.`id`;
-- 改成左外连接(如果左表有的数据,右表没有要查询的数据,则置为NULL)
SELECT `name`,stu.`id`,grade
FROM stu LEFT JOIN exam
ON stu.`id` = exam.`id`;
-- 改成右外连接(如果右表有的数据,左表没有要查询的数据,则置为NULL)
SELECT `name`,stu.`id`,grade
FROM stu RIGHT JOIN exam
ON stu.`id` = exam.`id`;
约束
主键primary key
1.primary key不能重复而且不能为null
2.一张表最多只能有一个主键,但可以是复合主键
3.主键的指定方式 有两种
直接在字段后指定:字段名 primary key
在表定义最后写 primary key(列名)
4.使用desc 表名,可以看到primary key的情况
5.实际开发中,每个表往往都会设计一个主键
CREATE TABLE t17
(id INT PRIMARY KEY, -- 表示id列是主键
`name` VARCHAR(32),
email VARCHAR(32));
CREATE TABLE t20
(id INT,
`name` VARCHAR(32),
email VARCHAR(32),
PRIMARY KEY (`name`)
);
CREATE TABLE t18
(id INT,
`name` VARCHAR(32),
email VARCHAR(32),
PRIMARY KEY (id, `name`) -- 这里就是复合主键
);
unique
和primary key语法一样,有两种定义方式。
1.如果没有指定 not null,则unique字段可以有多个null
2.一张表可以有多个unique字段
外键
foreign key(本表字段名) references 主表名(主键名或unique字段名)
-- 创建主表 my_class
CREATE TABLE my_class(
id INT PRIMARY KEY, -- 班级编号
`name` VARCHAR(32) NOT NULL DEFAULT '');
-- 创建 从表 my_stu
CREATE TABLE my_stu(
id INT PRIMARY KEY, -- 学生编号
`name` VARCHAR(32) NOT NULL DEFAULT '',
class_id INT, -- 学生所在班级的编号
-- 下面指定外键关系
FOREIGN KEY (class_id) REFERENCES my_class(id) -- 不能使用my_class.id
);
.1.外键指向的表的字段,要求是primary key 或者是 unique
2.表的类型是innodb,这样的表才支持外键
3.外键字段的类型要和主键字段的类型一致(胀肚可以不同)
4.外键字段的值,必须在主键字段中出现过,或者为null[前提是外键字段允许为null]
5.一旦建鲤主外键的关系,数据不能随意删除了
check
oracle和sql server均支持check,但是mysql5.7还不支持check,知错语法校验,但不会生效(mysql8生效)
在mysql中实现check的功能,一般是在程序中控制,或者通过触发器完成。
CREATE TABLE t23 (
id INT PRIMARY KEY,
`name` VARCHAR(32),
sex VARCHAR(6) CHECK (sex IN ('man', 'woman')),
sal DOUBLE CHECK ( sal > 1000 AND sal < 2000)
);
自增长
字段名 整形 primary key auto_increment
CREATE TABLE t25
(id INT PRIMARY KEY AUTO_INCREMENT,
email VARCHAR(32) NOT NULL DEFAULT '',
`name` VARCHAR(32) NOT NULL DEFAULT '');
下面是我练习时遇到的问题,以及找的资料:
sql自增长必须是主键吗?
mysql 只有主键能自动增长么 - 小程大序的猿 - 博客园
MySQL自增长可以设置多个吗?
MySQL如何同时自增自减多个字段_咔咔-的博客-优快云博客_mysql 多个自增字段
索引
索引的优势:查询速度块
底层实现:B+数
代价:
1.磁盘占用
2.对dml语句的效率影响
索引类型
1.主键索引,主键自动的为主索引(类型Primary key)
2.唯一索引 (UNIQUE)
3.普通索引(INDEX)
4.全文索引(FULLTEXT)[适用于MyISAM]
添加索引
主键索引
1.
CREATE TABLE t26 (
id INT PRIMARY KEY,
`name` VARCHAR(32));
2.
CREATE TABLE t26 (
id INT,
`name` VARCHAR(32)),
PRIMARY KEY (id)
);
3.
CREATE TABLE t26 (
id INT,
`name` VARCHAR(32)),
);
ALTER TABLE t26 ADD PRIMARY KEY (id);
ALTER TABLE t26 ADD PRIMARY KEY id; 错误的
4.
CREATE TABLE t27 (
id INT,
`name` VARCHAR(32));
ALTER TABLE t27 ADD PRIMARY KEY index_id (id);
唯一索引
1.
CREATE TABLE t25 (
id INT UNIQUE,
`name` VARCHAR(32));
2.
CREATE TABLE t27 (
id INT,
`name` VARCHAR(32),
UNIQUE (id)
);
3.
CREATE TABLE t25 (
id INT,
`name` VARCHAR(32));
CREATE UNIQUE INDEX id_index ON t25 (id);
CREATE UNIQUE INDEX id_index ON t25 id; 错误的
注意
一下三种都是不可以的
ALTER TABLE t27 ADD UNIQUE id_index (id);
ALTER TABLE t27 ADD UNIQUE (id);
ALTER TABLE t27 ADD UNIQUE id;
普通索引
1.
CREATE TABLE t27 (
id INT,
`name` VARCHAR(32)
);
CREATE INDEX id_index ON t27 (id);
2.
ALTER TABLE t27 ADD INDEX id_index (id);
全文索引
一般情况是很少使用mysql的全文索引,开发中考虑:Solr和ElasticSearch(ES)
删除索引
1.
删除索引
DROP INDEX id_index ON t27;
2.
删除主键索引
ALTER TABLE t27 DROP PRIMARY KEY;
显示索引
1.
SHOW INDEX FROM t27;
2.
SHOW INDEXES FROM t27;
3.
SHOW KEYS FROM t27;
4.
不全
DESC t27;
前三种一样的效果
最后一个
修改索引
先删除索引在添加索引
索引创建规则
1.较频繁的作为查询条件字段应该创建索引
2.唯一性太差的字段不适合单独创建索引,即使频繁作为查询条件
3.更新非常频繁的字段不适合创建索引
4.不会出现在where子句中字段不该创建索引
事务
什么是事务?
事务用于保证数据的一致性,它由一组相关的dml语句组成,改组的dml语句要么全部成功,要你全部失败(原子性)。
其实游戏中的回档就是事务的一种体现
经典例子:转账
小明要给小李转账100元
这是两个SQL语句,如果小明的语句执行成功,突然服务器崩了,那么小李的钱是没有的,但是小明失去了100元。
如何解救呢?
答案就是使用事务,在转账前开启事务。即初始保存点,如果发生意外返回保存点
-- 1. 创建一张测试表
CREATE TABLE t27
( id INT,
`name` VARCHAR(32));
-- 2. 开始事务
START TRANSACTION;
-- 3. 设置保存点
SAVEPOINT a;
-- 执行dml 操作
INSERT INTO t27 VALUES(100, 'tom');
DELETE FROM t27 WHERE id = 100;
SELECT * FROM t27;
SAVEPOINT b;
-- 执行dml操作
INSERT INTO t27 VALUES(200, 'jack');
SELECT * FROM t27;
-- 回退到 b
ROLLBACK TO b;
-- 继续回退 a
ROLLBACK TO a;
COMMIT;
细节
1.如果不开启事务,默认情况下,dml操作时自动提交的,不能回滚
2.如果开启一个事务,你没有创建保存点,你可以执行rollback,默认就是回退到你事务开始的状态
3.你可以在这个事务中(还没有提交时),创建多个保存点,比如:savepoint aaa;执行dml,savepoint bbb
4.你可以在事务没有提交前,选择回退到哪个保存点
5.mysql的事务机制需要innodb的存储引擎还可以使用,myisam不好使
6.开始一个事务start transaction,set autocommit = off;
隔离级别
1.多个连接开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个连接在获取数据时的准确性。(通俗解释)
2.如果不考虑隔离性,可能引发如下问题:
脏读
不可重复度
幻读
脏读
当一个事务读取另一个事务尚未提交的修改时,产生脏读
不可重复读
同一查询在同一事务中多次进行,由于其他提交事务所做的修改或者删除,每次返回不同的结果集,此时发生不可重复读
幻读
同一查询在同一事务中多次进行,由于其他提交事务所作的插入操作,每次返回不同的结果集,此时发生幻读
设置隔离级别
查看当前会话隔离级别
SELECT @@tx_isolation;
查看系统当前隔离级别
SELECT @@global.tx_isolation;
设置当前会话隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
设置系统当前隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL SERIALIZABLE;
设置默认隔离级别
表类型和存储引擎
查看所有存储引擎
SHOW ENGINES;
InnoDB
主要的存储引擎/表类型特点
细节说明
1.MyISAM不支持事务、也不支持外键,但其访问速度块,对事务完整性没有要求
2.InnoDB存储引擎提供具有提交、回滚和崩溃恢复能力的事务安全。但是比起MyISAM存储引擎,InnoDB写的处理效率差一下并且会占用更多的磁盘空间以保留数据和索引
3.MEMORY存储引擎使用存在内存中的内容来创建表。每个MEMORY表只实际对应一个磁盘文件。MEMORY类型的表访问速度非常快,因为它的数据是放在内存中的,并且默认使用HASH索引。但是一旦服务关闭,表中的数据就会丢掉,表的结构还在。
修改存储引擎
ALTER TABLE '表名' ENGINE = '存储引擎名';
视图
1.视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含列,其数据来自对应的真实表(基表)
2.视图和基表的关系
使用
-- 创建一个视图emp_vview01,只能查询emp表的(empno,ename,job和deptno)信息
创建视图
CREATE VIEW emp_view01
AS
SELECT empno,ename,job,deptno FROM emp;
视图其实还是一张表,表的操作同样适用于视图操作。
细节
创建视图后,到数据库去看,对应视图只有一个视图结构文件(形式:视图名.frm)
视图没有.ibd文件,没有内容
视图的最佳实践
MySQL管理
创建用户
-- 解读 (1) 'aaa'@'local' 表示用户的完成信息 'cuishuai' 用户名 'localhost' 登录的IP
-- (2) 123456 密码,但是注意 存放到 mysql.user表时,是password('123456') 加密后的密码
CREATE USER 'aaa'@'localhost' IDENTIFIED BY '123456';
修改密码
SET PASSWORD = PASSWORD('abcdef');
-- 修改其他人的密码,需要权限
SET PASSWORD FOR 'aaa'@'localhost' = PASSWORD('123456');
删除用户
DROP USER 'cuishuai'@'localhost';
分配权限
-- 给 Powering 分配 查看 news 表和 添加news的权限
GRANT SELECT,INSERT
ON testdb.news
TO 'Powering'@'localhost';
GRANT UPDATE
ON testdb.news
TO 'Powering'@'localhost';
回收权限
- 回收 Powering用户在 testdb.news 表的所有权限
REVOKE SELECT,UPDATE,INSERT ON testdb.news FROM 'Powering'@'localhost';
REVOKE ALL ON testdb.news FROM 'Powering'@'localhost';
细节
-- 在创建用户的时候,如果不指定Host,则为%,%表示所有IP都有连接权限
-- create user xxx;
CREATE USER jack; -- 等价 CREATE USER ‘jack’@‘%’;
SELECT `host`,`user` FROM mysql.user;
-- 你也可以这样指定
-- create user 'xxx'@'192.168.1.%' 表示 xxx用户在 192.168.1.*的ip可以登录mysql
CREATE USER 'tom'@'192.168.%';
-- 在删除用户的时候,如果 host 不是 %,需要明确指定 '用户'@'host值'
DROP USER jack; -- 默认就是 DROP USER 'jack'@'%'
DROP USER 'tom'@'192.168.%';
最后要说的话
最近JDBC也学完了,JDBC绝对是纯干货,我会把学习总结做出来的,我先缓缓,2+4个小时写完文章太肝了.。