数据库--学习记录2

 1.可视化工具操作数据库

1.1 pycharm进入数据库

1.2 连接数据库

test connect可以成功的前提是mysql的服务端是开启的

之前在终端不需要填用户名和密码,是因为我们在mysql的配置文件里面给自己的mysql自己的客户端程序,配置了用户名和密码。我们现在是使用pycharm作为客户端,所以是需要用户名和密码的

 

1.3 创建数据库

这里的schema和database是一样的,这种可视化工具,每一个操作背后对应的都是一条语句。

 1.4 创建数据表

在db6的数据库上面创建新表,comment是对这张表的备注。

 1.5 添加字段

添加id为主键:

先添加字段,设置not Null和Auto_increment之后,再将其设置为primary key.点击key之后双击选择id.再切换回columns.添加新的字段name,设置数据类型。emp就创建完毕了。

 

1.6 添加记录 

此时发现db6下面多了一张emp表,双击即可显示该表。

可以使用+来添加记录,只是需要添加name,id设置了auto_increment.点击小眼睛可以对插入的语句进行预览。可以直接submit就可以插入记录。点击向上箭头也可以直接添加记录。

 1.7 执行sql语句

console是书写sql命令的地方。如果它被关闭了,可以点击数据库,new->Query Console就可以显示出来了

2. 函数 

2.1 字符串处理函数

# --字符串拼接
select concat("a", "b", "c");
# --转小写
select lower('HELLO');
# --转大写
select upper('hello');
# --左填充
select lpad("hello",10,"-");
#-- 右填充
select rpad('hello',10,"-");
# --去除两端空格
select trim("    hello    ");
# --字符切片,从第二个字符开始切3个字符
select substring("hello world",2,3);

 

2.2 数值处理函数

select ceil(1.3); -- 向上取整 => 2
select floor(1.6); -- 向下取整 =>1
select mod(10,3); -- 获取10/3模 =>1
select rand(); -- 获取0-1之间的随机小数
select round(3.1415926,4) -- 对3.1415926四舍五入,保留4位小数 =>3.1416

2.3 时间处理函数

select '当前日期', curdate();					    -- 获取当前日期
select '当前时间', curtime();						-- 获取当前时间
select '当前日期时间', now();						-- 获取当前日期和时间
select '年', year('2023-10-08 18:36:59');		-- 获取date_time的年份
select '月', month('2023-10-08 18:36:59');		-- 获取date_time的月份
select '日', day('2023-10-08 18:36:59');			-- 获取date_time的日期
select '时', hour('2023-10-08 18:36:59');		-- 获取date_time的小时
select '分', minute('2023-10-08 18:36:59');		-- 获取date_time的分钟
select '秒', second('2023-10-08 18:36:59');		-- 获取date_time的秒

-- 时间差计算,interval单位:year,month,day,hour,minute,second, microsecond
select date_add(now(), interval 1 year); 						-- 获取从now()开始,1天后的时间
select date_add('2023-10-08 18:36:59', interval 1 month); 		-- 获取指定时间1月后的时间
select datediff('2025-10-08 18:36:59', now()); 					-- 获取两个时间之间的天数,第一个值减去第二个值
select timediff('2023-10-08 18:36:59', '2023-10-08 12:00:00');  -- 获取两个时间之间的时间差值

 

3. 流程控制语句

3.1 单分支

if(条件,条件满足,条件不满足)

-- 流程控制函数
-- 单分支,查询所有员工的名字和性别,并将性别显示为小哥哥,小姐姐
-- if(条件.条件满足,条件不满足)
-- ifnull(),判断是否为空,为空则为后面的字符串进行填充
select name,if(gender="male","小哥哥","小姐姐" ) as '性别' from emp;
select name, ifnull(notes,"未知") from emp;

结果图: 

3.2 多分支

when..then..else..end.

-- 多分支
-- 工资大于10000:核心员工
-- 工资5000-10000:普通员工
-- 工资5000以下:新员工
select name,salary,
	case when salary>10000 then "核心员工" when salary>5000 then "普通员工" else "新员工" end as "薪资级别"
from emp;

-- 技术部:高级技术顾问
-- 人事部:HR
-- 其他:销售经理
select name,dep,
	case dep when "技术部" then "高级技术顾问" when "人事部" then "HR" else "销售经理" end as "职务"
from emp;

 

4.多表查询

学习外键的时候,为了解决数据重复的问题,将数据分散在多张表里面这样也便于我们的管理。但是本质上这些表之间是有关联的,本质上面是一个整体。我们查询的时候,必须将分散的数据合并到一起查询

4.1 建表

create database db6 charset=utf8;
use db6;
create table dep(
	id int primary key auto_increment,
	name varchar(16) not null,
	notes varchar(64)
);
insert into dep(name) values
('总经办'),('技术部'),('市场部'),('人事部'),('财务部'),('后勤部');

-- 姓名,性别,年龄,工资,post,join_date,leader_id,dep_id
create table emp(
	id int primary key auto_increment,
	name varchar(16) not null,
	gender enum("male","female") not null,
	age int not null,
	salary float(10,2),
	post varchar(16),
	join_date date,
	leader_id int,
	dep_id int
);

-- 插入员工数据
insert into emp values
(1, '刘备', 'male', 32, 4000, '总经理', '2035-06-01', null, 1),
(2, '关羽', 'male', 20, 8000, '技术总监', '2035-06-05', 1, 2),
(3, '张飞', 'male', 25, 12000, '项目经理', '2035-06-10', 2, 2),
(4, '赵云', 'male', 19, 6800, '产品经理', '2035-06-10', 2, 2),
(5, '马超', 'male', 26, 11000, '后端开发', '2035-07-11', 2, 2),
(6, '黄忠', 'female', 48, 15000, '后端开发', '2035-07-22', 2, 2),
(7, '夏侯惇', 'male', 36, 34000, '后端开发', '2035-07-29', 2, 2),
(8, '典韦', 'male', 19, 6800, '后端开发', '2035-08-02', 2, 2),
(9, '吕布', 'female', 20, 9000, '前端开发', '2035-08-03', 2, 2),
(10, '周瑜', 'female',32, 36000, '前端开发', '2035-08-08', 2,  2),
(11, '文丑', 'male', 27, 24000, '测试', '2035-08-12', 2, 2),
(12, '诸葛亮', 'male', 27, 8000, '市场总监', '2035-06-05', 1, 3),
(13, '庞统', 'male', 37, 4200, '销售', '2035-06-06', 12, 3),
(14, '徐庶', 'male', 36, 4000, '销售', '2035-06-12', 12, 3),
(15, '荀彧', 'male', 25, 2400, '销售', '2035-06-10', 12, 3),
(16, '荀攸', 'male', 25, 2400, '销售', '2035-06-12', 12, 3),
(17, '鲁肃', 'male', 43, 4300, '销售', '2035-06-18', 12, 3),
(18, '司马懿', 'female', 44, 5000, '销售', '2035-06-20', 12, 3),
(19, '杨修', 'male', 19, 800, '销售', '2035-07-10', 12,  3),
(20, '丁仪', 'male', 49, 3500, '销售', '2035-07-11', 12, 3),
(21, '宋江', 'male', 30, 8000, '人事总监', '2035-06-05', 1, 4),
(22, '吴用', 'male', 38, 3000, '人事主管', '2035-06-06', 21, 4),
(23, '扈三娘', 'female', 42, 2500, '招聘专员', '2035-06-11', 21, 4),
(24, '顾大嫂', 'female', 38, 3300, '招聘专员', '2035-06-25', 21, 4),
(25, '孙二娘', 'female', 32, 2400, '绩效专员', '2035-07-22', 21, 4),
(26, '丁得孙', 'male', 32, 2800, '培训专员', '2035-08-10', 21, 4),
(27, '柴进', 'male', 30, 8000, '财务总监', '2035-06-05', 1, 5),
(28, '卢俊义', 'male', 44, 4000, '会计', '2035-08-19', 27, 5),
(29, '晁盖', 'male', 44, 3500, '出纳', '2035-08-20', 27, 5),
(30, '貂蝉', 'female', 36, 800, null, '2035-09-01', null, null);

 emp表的dep_id,关联的是dep的id,但不是强关联,两张表的自由度仍然很高。

 4.2 笛卡尔积

笛卡尔积就是两个集合里面的元素一一组合的情况

运行词条sql语句,就会查到180条记录。每个员工对应6个部门。但是我们其实需要的数据只是emp表的dep_id和dep表id相等的记录。

-- 笛卡尔积现象
select * from emp,dep;
-- 查询两张表关联的数据
select * from emp,dep where emp.dep_id=dep.id;

查询出来了两张表关联的数据,但是员工有30个只是出来了29.因为貂蝉不存在dep_id.所以此种条件查询不出来 。

虽然此种方式实现了连表查询,但是不建议使用。where本身不是用来做连表查询的,它本身只应该干过滤的事。 连表操作MySQL提供了特定的语法。

 4.3 连接查询

多表查询主要分为两大类,连接查询和子查询.在连接查询里面又分为内连接,外连接,自连接

4.3.1 内连接

内连接查询的是两者的交集部分->C

隐式内连接

select * from emp,dep where emp.dep_id=dep.id;

显示内连接

select * from <表a> [inner] join <表b> on 条件;
select * from emp inner join dep on emp.dep_id=dep.id; -- 显式内连接

4.3.2 外连接

左外连接

查询左表所有数据,包括交集部分A+C

select <字段> from <表a> left [outer] join <表b> on <条件>;
select * from emp left outer join dep on emp.dep_id=dep.id; -- 左外连接
-- 查询所有员工数据和部门信息
-- 因为两张表里面都是存在name,所以前面需要加上表名
select emp.name,dep.name from emp left outer join dep on emp.dep_id=dep.id;
-- 给表起别名后,所有的条件都是需要改为别名
select e.name,d.name from emp as e left outer join dep as d on e.dep_id=d.id;


右外连接 

查询右表所有数据,包括交集部分B+C

其实使用左外连接可以达到一样的效果.所以一般都是使用左外连接.

-- 查询所有部门数据,以及对应的员工数据,右外连接
select e.name,d.name from emp as e right outer join dep as d on e.dep_id=d.id;

-- 左外连接
select e.name,d.name from dep as d left outer join emp as e on e.dep_id=d.id;

 4.3.3 自连接

自连接一定要给表起别名,将一张表看为两张表.并且自连接可以使用内连接也可以使用外连接.

-- 自连接语法
select <字段> from <表a> <a> join <表a> <b> on <条件>;

-- 可以使用内连接,外连接

-- 查询员工和对应领导的名字
select e.name as "员工姓名",d.name as "领导名" from emp as e inner join emp as d on e.leader_id=d.id; -- 自连接之内连接

select e.name as "员工",d.name as "领导" from emp as e left outer join emp as d on e.leader_id=d.id; -- 自连接之左外连接

4.4 联合查询

将多次查询的结果连接在一起,关键字union,union all;

1)union和union all的区别在于,union会将重复的值提取成一个,union all在于每次查询的值都会显示出来,无论是否重复。

2)联合查询的优势在于,它可以同时查询多张表,就是select多张表。如果只是一张表则可以使用where进行替代。

3)联表查询时,如果是不同的列,那么索引出来的列的个数必须是一致的,否则会报错

-- 语法:select .. union [all] select ..;
-- 查询薪资>=15000,以及年龄大于等于45的员工
-- 薪资大于等于15000
select * from emp where salary>=15000;
-- 年龄大于等于45
select * from emp where age>=45;

-- union all实现
select * from emp where salary>=15000
union all
select * from emp where age>=45;

-- union实现
select * from emp where salary>=15000
union
select * from emp where age>=45;

-- where过滤条件单表实现
select * from emp where salary>=15000 or age>=45;

-- union多表条件查询
select * from emp where age>=45
union all
select * from dep; -- 两个表索引的列的个数不一致会报错

-- union多表条件查询
select id,name,age from emp where age>=45
union all
select * from dep; -- 两个表索引的列的个数一致success

年龄和薪资单个条件 

union all

 union

 where过滤条件单表实现

联合查询,查询不同的表 

 4.5 子查询

在mysql里面一条SQL语句可以嵌套另外一条SQL语句,这就叫做子查询。子查询可以放在select之后,from之后,where之后。子查询按照查询结果的不同,可以分为以下几类:

4.5.1 标量子查询

子查询的结果是单个值.因为标量子查询的结果是单个值,所以可以放在比较运算符的地方。还有这是多表查询,不要和单表查询的distinct混淆了。

-- 查询技术部,所有员工的信息
-- 现在的emp表里面只是存在技术部的id
    -- 1.查询技术部的id
select id from dep where name="技术部"; -- 子查询出来的结果只是一个值,id为2
    -- 2. 查询技术部所有员工信息
select * from emp where dep_id=2;
-- 将两个SQL语句嵌套在一起,()包裹子查询语句
select * from emp where dep_id=(select id from dep where name="技术部");


-- 查询薪资比黄忠还高的员工信息
    -- 1.查询黄忠的薪资
select salary from emp where name="黄忠"; -- 标量子查询,单个值salary,15000
    -- 2.查询薪资比黄忠高的员工
select * from emp where salary>15000;
-- 合并在一起
select * from emp where salary>(select salary from emp where name="黄忠");

4.5.2 列子查询

子查询的结果是一列。一列一行也是一列,一列多行也是一列。主要看一列多行。它的操作运算符主要有以下几个:

in

not in

any:子查询的列表中,有任何一个满足即可

some:同any,用some的地方都可以使用any

all:子查询列表的值都必须满足

-- 比市场部所有人入职都晚的员工信息
    -- 1.获取市场部的id
select id from dep where name="市场部";
    -- 2.获取市场部的所有人的入职日期
select emp.join_date from emp where dep_id=3;
    -- 3.-- 比市场部所有人入职都晚的员工信息
select * from emp where join_date>all(select emp.join_date from emp where dep_id=3);
-- 合在一起
select * from emp where join_date>all(select join_date from emp where dep_id=(select id from dep where name="市场部"));

-- 第二种方式,取日期的最大值,一直使用标量子查询
select max(emp.join_date) from emp where dep_id=(select id from dep where name="市场部");
select * from emp where join_date> "2035-07-11";
select * from emp where join_date>(select max(emp.join_date) from emp where dep_id=(select id from dep where name="市场部"));

4.5.3 行子查询

子查询的结果是一行,操作符有=,!=,in,not in

4.5.4 表子查询

子查询的结果是多行多列,操作符就是in 和not in.当然表子查询除了可以放在where后面之外,还可以放在from后面

快捷键

pycharm快速移动行首和行尾:

shift+home,shift+end

练习

-- 职位等级表
create table job_grade(
    id int primary key auto_increment,
    grade varchar(16),
    min_salary int,
    max_salary int
);

insert into job_grade(grade, min_salary, max_salary) values
('p1', 0, 4999),
('p2', 5000, 9999),
('p3', 10000, 14999),
('p4', 15000, 19999),
('p5', 20000, 29999),
('p6', 30000, 39999);


-- 查询所有员工的职位等级
-- 连接条件: emp.salary>min_salary and emp.salary < max_salary
-- 两张表没有字段关联
select emp.name,emp.salary,job_grade.grade from emp left outer join job_grade on emp.salary>=min_salary and emp.salary <= max_salary;
select emp.name,emp.salary,job_grade.grade from emp left outer join job_grade on emp.salary between min_salary and max_salary; -- between..and是闭区间,前后都包含

查询所有员工职位等级 

查询人事部所有员工信息,以及他们的职级

-- 查询人事部所有员工信息,以及他们的职级
select *
from emp
where emp.dep_id = (select id from dep where name = "人事部"); -- 表子查询
select e.*, job_grade.grade
from (select * from emp where emp.dep_id = (select id from dep where name = "人事部")) as e
         left outer join job_grade on e.salary between min_salary and max_salary;

-- 表:emp dep job_grade
-- 连接条件:emp.salary>min_salary and emp.salary < max_salary  emp.dep_id=dep.id
-- 过滤条件:dep.name = "人事部"
select emp.*, dep.name, job_grade.grade
from emp
         left outer join job_grade on emp.salary > min_salary and emp.salary < max_salary
         left outer join dep on emp.dep_id = dep.id
where dep.name = "人事部";

 查询薪资低于每个部门平均值的员工信息

-- 查询薪资低于每个部门平均值的员工信息
-- 表:emp dep
-- 连接条件 emp.dep_id=dep.id
-- 查询条件 select dep_id,avg(salary) as avg_salary from emp group by dep_id having avg_salary> emp.salary
--
-- 使用group by直接失败
select dep_id, dep.name, avg(salary) as avg_salary
from emp
         left outer join dep on emp.dep_id = dep.id
group by dep_id;

-- 正确做法
-- 查询薪资低于每个部门平均值的员工信息
-- 1.查询每个部门的平均薪资
select avg(emp.salary) from emp where dep_id = 3; -- 先查一个部门的
-- 每条记录的dep_id是在动态变化的
select a.*, (select avg(b.salary) from emp as b where b.dep_id = a.dep_id) as "avg_salary"
from emp as a
where salary < (select avg(b.salary) from emp as b where b.dep_id = a.dep_id);

 5.数据库控制语言(DCL)

管理数据库用户,控制数据库访问权限

用户a -> db1

用户b -> db1 db2

用户管理:控制哪些用户可以访问数据库

权限控制:每一个用户各自有什么样的访问权限(运维,DBA(Database Administrator))

5.1 用户管理

5.1.1 创建用户

创建用户是特定的语法和我们的查询语法不一样.查询语法需要通过库来找.创建用户这个语法,它会自己找mysql的user表,所以不需要切换数据库也可以执行

-- 创建用户
-- 语法
create user '用户名'@'主机名' identified by '密码';
create user 'hao'@'localhost' identified by '123';
create user 'hao'@'%' identified by '123'; -- 可以任意主机访问

可以看到hao用户下面的很多字段都是N,这是权限,也就是说hao用户没有权限。 我们现在只是创建了用户,它拥有访问mysql的权限,但是没有访问其他数据的权限,甚至连创建数据库的权限都是没有的。

information_schema 是虚拟文件夹,它是存放在内存里面的。里面都是数据库启动之后的信息。比如数据类型和访问权限等

5.1.2 删除用户

-- 删除用户
drop user "用户名"@"主机名";
drop user "hao"@"localhost";

5.1.3 修改用户

修改用户的密码,不要使用双引号

-- 修改用户密码
alter user '用户名'@'主机名' identified with mysql_native_password by "新密码" -- 指定了密码的加密方式

-- 修改用户密码
alter user 'hao'@'localhost' identified with mysql_native_password by '456';

-- 修改主机名,这里的主机名可以是%,也可以是你的ip地址
update mysql.user set host="主机名" where user="用户名";

update mysql.user set host="%" where user="hao";

5.1.4 查询用户

-- 查询用户
select * from mysql.user;

5.2 权限控制

all/all privileges:所有权限

insert:插入数据权限

delelte:删除数据权限

update:修改数据权限

select:查询数据权限

create:创建数据库/表权限

drop:删除数据库/表/视图权限

alter:修改表/字段权限

5.2.1 查询权限

-- 查询权限 (grants 授权)
show grants for '用户名'@'主机名';

-- 查询hao用户权限
show grants for 'hao'@'localhost';
-- 查询他root用户权限
show grants for 'root'@'localhost';

5.2.2 分配权限(授予权限)

-- 分配权限
grant 权限列表 on 库名.表名 to '用户名'@'主机名';

-- 将db6下面所有表的权限都分配给hao用户
grant all on db6.* to 'hao'@'localhost';

5.2.3 撤销权限

-- 撤销权限(revoke 废除,撤销)
revoke 权限列表 on 库名.表名 from '用户名'@'主机名';

-- 撤销用户hao关于数据库db6的所有权限
revoke all on db6.* from 'hao'@'localhost';

5.2.4 刷新权限

有时候我们修改完权限信息没有效果,是因为我们修改的权限信息,没有及时被服务端进程读取。此时我们可以使用此语句刷新一下。

-- 刷新权限(privilege 特权)
flush privileges

6.事务

一组操作的集合(多条sql语句的集合),这个集合是一个不可分割的工作单位,它会将集合里面内的所有操作一起提交,如果提交的过程中,有任何一条sql语句出现了错误,那么便会回退到整个十五之前的状态。即:要么同时成功,要么同时失败。

和银行转账的操作相同,要么转账成功。转账失败时,之前的所有操作都要回滚到之前的状态。

6.1 转账操作

对于MySQL来说,事务是默认自动提交的。也就是我们在执行增删改语句的时候,只要语句一执行完,事务就默认自动提交了,数据也就被永久修改了。

如果要将多条sql语句放在一个事务里面,就需要手动开启事务,事务执行完成之后,再手动提交事务。如果过程中间出现了异常,还是需要手动回滚事务。

现在的问题是出现异常之后100元不翼而飞了。所以需要解决这个问题,就要将转账操作放到一个事务里面。

现在我们没有手动开启事务,默认也是存在事务的。一条sql语句就是一个事务,事务执行完成之后就是会自动提交。所以前两条语句执行完成之后,李白的小钱钱就被修改了,回不去了。

-- 账户表
create  table account(
    id int primary key auto_increment,
    name varchar(16),
    balance int
);
-- 插入数据
insert into account(name,balance) values("李白",500),("杜甫",1000);

-- 正常情况
-- 1.查询李白余额
select * from account where name="李白";
-- 2. 给李白账户-100
update account set balance=balance-100 where name="李白";
-- 3. 给杜甫账户增加100
update account set balance=balance+100 where name="杜甫";

-- 异常情况
-- 1.查询李白余额
select * from account where name="李白";
-- 2. 给李白账户-100
update account set balance=balance-100 where name="李白";
print("出现异常了")
-- 3. 给杜甫账户增加100
update account set balance=balance+100 where name="杜甫";

6.2 开启事务

开启事务主要有两种实现方式:

1. 修改事务的提交方式

2.可以使用start transaction(事务)或是begin

------------------------------------修改事务的提交方式-----------------------------------------

0)查看当前事务的提交方式,值为1时表明事务是自动提交的

1)将当前会话的事务设置为手动提交,但是修改的是当前会话,断开连接再重新连就没有效果了

2)刚刚设置了手动提交,只是对当前窗口有效,这里执行完成事务之后,还没有提交事务,在另外窗口看是看不到结果的

3)提交事务之后,事务里面的操作效果才会显示在另外的窗口

4)事务里面的操作出现异常时:虽然值在另外的窗口没有变化,我们还是要回滚事务。因为我们设置了当前事务为手动提交,我们如果既不提交事务,也不回滚事务,后续的sql语句操作,都会被认为在同一个事务内。

5)结束事务的方式有两种,提交事务和回滚事务

-- 查看当前事务的提交方式
-- 值为1时表明事务是自动提交的
select @@autocommit;

-- 将当前会话的事务设置为手动提交
-- 修改的是当前会话,断开连接再重新连就没有效果了
set @@autocommit=0;

-- 刚刚设置了手动提交,只是对当前窗口有效,这里执行完成事务之后,还没有提交事务,在另外窗口看是看不到结果的
-- 1.查询李白余额
select * from account where name="李白";
-- 2. 给李白账户-100
update account set balance=balance-100 where name="李白";
-- 3. 给杜甫账户增加100
update account set balance=balance+100 where name="杜甫";

-- 提交事务
commit;

-- 将当前会话的事务设置为手动提交
-- 修改的是当前会话,断开连接再重新连就没有效果了
set @@autocommit=0;

-- 出现异常情况
-- 1.查询李白余额
select * from account where name="李白";
-- 2. 给李白账户-100
update account set balance=balance-100 where name="李白";
print("出现异常情况")
-- 3. 给杜甫账户增加100
update account set balance=balance+100 where name="杜甫";

-- 虽然值在另外的窗口没有变化,我们还是要回滚事务
-- 因为我们设置了事务为手动提交,我们如果既不提交事务,也不回滚事务,后续的sql语句操作,都会被认为在同一个事务内
-- 结束事务的方式有两种,提交事务和回滚事务
-- 回滚事务
rollback ;

-- 查看当前事务的提交方式
-- 值为1时表明事务是自动提交的
set @@autocommit=1;
select @@autocommit;

-- transaction(事务)
-- 可以使用start transaction或是begin
start transaction;
begin;
select @@autocommit; -- 提交方式还是1

-- 出现异常情况
-- 1.查询李白余额
select * from account where name="李白";
-- 2. 给李白账户-100
update account set balance=balance-100 where name="李白";
print("出现异常情况")
-- 3. 给杜甫账户增加100
update account set balance=balance+100 where name="杜甫";

-- 回滚事务
rollback;

 

 6.3 ACID 

事务的四大特性

  • 原子性(Atomicity):事务是不可分割的最小操作单元,这个操作单元要么全部成功,要么全部失败
  • 一致性(Consistency):事务完成的时候,必须使得所有的数据都保持一致的状态。(李白和杜甫转账前后的金额应该是一致的)
  • 隔离性(Isolation):在并发的时候,A事务和B事务都在操作数据库。A事务在操作的时候,它不会影响B事务的执行。B事务在操作的时候,也不会影响A事务
  • 持久性(Durability):事务不管是提交还是回滚,他对数据库里面数据的改变都是永久的(都是持久化到磁盘里面的,而在事务执行过程中修改的数据都是存储在内存里面的)

 6.4 并发事务问题

在innodb存储引擎里面分为内存结构和磁盘结构。磁盘结构就是数据文件。内存结构里面有很大一块区域叫做buffer pool(缓冲池)。事务提交之前存储在内存里面,其实就是存储在这个缓冲池里面。

当一个事务对数据进行修改的时候,就会先查看缓冲池里面有没有这个数据。如果没有,就会将对应的数据从磁盘里面读取出来,然后存在缓冲池。接下来事务对于数据的修改,修改的就是缓冲池里面的数据,磁盘里面的数据,并不会发生变化。

事务提交前对于数据的修改都是存储在内存的,这个时候其他事务来访问这个数据,它也会先看内存。

这时候就会出现问题,假设事务a执行之后还没有提交,但是此时事务已经储存到了服务端内存。这时候b事务又来读取这个数据的话,数据就是可以读取到的。因为数据已经在缓冲池里面了,它就不会从磁盘里面读取。但是如果此时事务a又执行了回滚操作,b事务读取到的数据就是无效的数据。

6.4.1 脏读

一个事务读取到另外一个事务还没有提交的数据

6.4.2 不可重复读

一个事务先后读取同一条记录,但两次读取到的数据不同

6.4.3 幻读

一个事务查询某一条记录的时候,没有对应的记录。但是插入记录的时候,又发现这条记录已经存在。就好像出现了幻觉一样

6.5 事务的隔离级别

serializable:串行化,不管是什么并发事务到这里都会变为串行执行

 6.5.1 脏读

脏读,不可重复读,幻读都是并发事务引发的问题。所以我们至少需要开启两个事务。

脏读,就是一个事务读取到另外一个事务未提交的数据。通过设置隔离级别read committed可解决脏读问题。

脏读现象: 

修改隔离级别为read-committed之后: 

 

 6.5.2 不可重复读

一个事务先后读取同一个记录,读取到的数据不同。解决不可重复读的方法是将隔离级别设置为repeatable read.隔离级别read commit会存在不可重复读问题。

不可重复读现象:

修改隔离级别为repeatable read之后:

6.5.3 幻读

一个事务查询一条记录的时候不存在,但是插入数据的时候又显示已存在,好像出现了幻觉一样. 

幻读现象: 

 修改隔离级别为serializable之后:

7.虚拟机

7.1 网络配置

1) 打开网络配置文件,ifconfig-ens33就是网络配置文件

2)将配置文件里面的ONBOOT改为yes,让系统启动的时候,自动获取网络接口。我这里是自己配置的静态配置的。其实可以BOOTPROTO可以让其为dhcp,让其自动获取ip地址

3) 重启网络服务,service network restart

4) 我们现在需要一个干净的系统,不安装任何软件。将该系统先关机。init 0

 

 7.2 克隆新的虚拟机

步骤:右键->管理->克隆->下一步->下一步->链接克隆->选择位置安装即可。

链接克隆:更加节省磁盘空间,他会引用原虚拟机,但是又会有自己独立的配置,比如磁盘操作。并且两台虚拟机的磁盘操作都是互不影响的。

7.3 安装终端模拟器

Tabby - a terminal for a more modern age

1) 下载:在github上面进行下载https://github.com/Eugeny/tabby/releases/tag/v1.0.211

2)配置:点击设置->配置和连接,新配置->SSH连接->名称,主机,用户名,密码->连接

3)连接成功,使用SFTP进行上传文件

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值