了解MySQL
MySQL:关系型数据库管理系统
数据库管理系统包含的最基本的成员:
1:若干个数据库组成
2:管理软件
3:使用人员(DBA,以及普通人员)
数据库:什么是数据库。
所谓的数据库,就是一个存储数据的仓库,数据存储在仓库中,我们就可以通过管理软件提供的方式来对数据进行快速的crud。
目前数据库主要分为两大类:
1:关系型数据库 sql server MySQL Oracle…等
2:非关系型数据库 Redis es…等
如何区分一个数据库是否是关系型还是非关系型,关系型数据库这个名字意味着他跟一些东西有关系,这个东西就是sql规范,而所有的关系型数据库都必须要遵守sql规范。
SQL:结构化查询语句
SQL是一个为了实现特殊目的的编程语言,其主要目的就是针对关系型数据库的各种操作,以及数据库中数据的增删改查,SQL语言诞生于1974年,1980年美国的国家标准局数据库委员会将SQL定义成了关系型数据库语言的标准,当美国宣布不久之后,ISO(国际标准化组织)宣布将SQL定义为关系型数据库的国际标准。
SQL主要分为六大类:
1:DQL(数据查询语言,主要是查询数据)
关键字:SELECT(查) WHERE(筛选过滤)
2:DML(数据操作语言,主要是增删改)
关键字:INSERT(增加) UPDATE(修改) DELETE(删除)
3:TCL(事务控制语言)
DCL(数据控制语言,权限操作)
关键字:GRANT(赋予用户权限) REVOKE(回收权限)
5:DDL(数据定义语言)
关键字:CREATE(创建) DROP(删除) ALTER(修改)
6:CCL(指针控制语言)
Oracle – Oracle(收费) mysql(免费)
# 关于约束分类的一些争议
# 观点1: 约束分为列级约束与表级约束 列级约束:自增,默认值,非空,检查 表级约束:主键,外键,唯一
# 观点2: 约束分为行级与列级 行级约束:自增,默认值,非空,检查 列级约束:主键,外键,唯一
# 观点3: 约束分为行级与表级 行级约束:自增,默认值,非空,检查 表级约束:主键,外键,唯一
day29
MySQL>>>>数据库>>>>表>>>>列>>>>行
MySQL:是一个数据库管理系统。每个MySQL都能有很多数据库。
数据库:就是一个数据仓库,每个数据库都可以有很多表。
表:里面存放的是我们的数据,每个表都有任意个列。
列:用来指定了存放的数据类型,以及数据的长度,每个列可能有任意行。
行:单元格,里面存放了我们需要存储的数据。
如何用Java的目光看待数据库?
将表看成Java的类,表中的列看成类中的属性,每一行数据都对应着Java的对象。
创建用户
create user 'zx' identified by '123456';
drop user 'zx';
登录用户
mysql -uzx -p
查看当前登录用户
select user();
用户添加回收权限
grant create,insert,select, on aaa.* to 'zx';
revoke create,insert,select on aaa.* from 'zx';
用户编辑表需要先进数据库
use aaa;
创建删除数据库
create database aaa;
drop database aaa;
切换数据库
use aaa;
展示所有数据库
show databases;
展示数据库中的表
show tables;
查看表的建表语句
show CREATE table stu;
查看表的信息
desc user
创建表
create table m(id int,name varchar(20));
表里插入数据
insert into m values(1,'张三');
insert into user (id,name,n) values(2,'张三','1998-08-28 12:09:08');
insert user select * from user;#数据翻倍(一般用于测试大量数据时使用)
表里查看数据
select * from m;
#显示所有的职位,使用distinct可以把重复的数据去重
select distinct job from emp;
表里更新数据
update m set name='bbb' where id=1;
update user set name='沙和尚',hiberdate='2000-09-09' where id=1 and sex='男';
delete from user where id=3 or (id=2 and name='孙悟空' and sex is null) or (id=1 and name='沙和尚' and sex='男');
表里删除数据
delete from m;
delete from user where id=2;
truncate table stu;#直接删除表中的所有数据,不能加条件,效果和delete from user;一样,但是效率更高
delete与truncate的区别
1:delete后面可以跟条件进行删选,而truncate后面不能有任何条件
2:delete操作在日志中有记录,可以使用回滚,而truncate在日志中没有记录,不能使用回滚
3:delete是删除数据而已,而truncate是相当于删除了表,重新建立了一张表,原表还在,truncate效率更高
删除表
drop table user;
赋值与判断相等null
null的使用,判断某个值为空时不可以使用=null 要使用is null 判断不为空为is not null
#null值不能进行计算,所有的值与null 计算结果都为null
#使用ifnull(a,b)如果第一个值为null则使用第二个值,否则使用第一个值
select ename,(sal*15+comm*12) from emp;
select ename,(sal*15+ifnull(comm,0)*12) from emp;
#null默认等于0,但是0默认不等于空
select * from emp where comm!=0 or comm is not null;#结果为comm=0的也满足条件
#null值不能进行计算,所有的值与null 计算结果都为null
select ename,(sal*15+comm*12) from emp;
varchar与char
#varchar 用来表示字符串,字符串在数据库中需要指定长度,而varchar是可变字符串,例如varchar(20)虽然指定了这一列能存储20个字符,但是其占用空间是根据实际占用情况来看的,如果数据只占用了两个字符的话那实际占用空间就是2个字符,当最高占用不能超过20个字符,varchar最高能存储65532字节的数据
#char 用来表示字符串,不可变(例如sex(20),这里指定了sex每一行数据都最多能存储20个字符,但是如果只存放了一个字符,实际占用空间还是20个字符的空间
timestamp与data
data 数据类型,用来表示日期,没有具体到时分秒
timestamp 虽然会以年月日,时分秒来表示,但是本质上是时间戳。
bit
bit 只能存储数字0和1,对应Java布尔
(约束)DDL(数据定义语言)
约束:用来规定以及限制数据的内容。
#1:非空约束(not null) 约束列的值不能为空
#2: 唯一约束(unique) 列的值,在本列之内要唯一
#3:主键约束(primary key)非空+唯一,表示这一列的值既不能是null也不能重复。一般情况下第一列都是主键, auto_increment 自增长,只有主键有自增长。
#4:外键约束 跟父子表有关系,约束了字表的增加和父表的删除。
#自增,一般情况下在mysql中我盟的主键如果是int类型的话,可以使用自增长来让mysql自动维护主键的值。如果主键有自增长,插入时主键写null即可,mysql会自动填入主键。(有争议:当插入失败时主键也会自增,会造成主键下一次添加时会和上一个的主键值相差大于1)
#我盟可以使用default关键字来给列设置默认值,然后在插入数据的时候使用默认值进行插入。
CREATE table user(
id int primary key auto_increment, #id是主键,自增长
name VARCHAR(20) unique, #name 唯一约束,要求值不能重复
sex varchar(20) not null default '女', #sex 要求非空约束,
age int,
check(age between 18 and 25) #AGE检查约束,值必须在18到25之间,在mysql中无效
);
insert into user values(null,'张三',default,88);
insert into user values(1,'李四','男',88);
insert into user values(null,'hjk','男',88);
select * from user;
外键约束
#外键约束一般外键约束都在字表之内,由字表中的一列指向父类的主键foreign key(class_id) references class(id)
#增加的时候,由于class_id这一列绑定了class表的主键,所以class_id的值必须要在父表中存在,否则无法插入
##如果父表的主键值在字表中出现了,那么是不能直接删除的,需要先删除字表的数据,然后再删除父表。
CREATE table class(
id int PRIMARY Key,
name VARCHAR(20)
);
CREATE TABLE stu(
id int PRIMARY KEY,
name varchar(20),
class_id int,
FOREIGN key(class_id) references class(id)
);
INSERT INTO class VALUES(1,'中级一般');
INSERT into class VALUES(2,'中级二班');
-- INSERT into stu VALUES(1,'张三',3);#3在class中不存在,会出错
INSERT into stu VALUES(1,'张三',2);
SELECT * from class;
SELECT * from stu;
-- DELETE FROM class WHERE class_id=2;#无法删除父类,因为其绑定的stu对象存在
DELETE FROM stu WHERE class_id=2;
DELETE FROM class WHERE id=2;
alter修改
#增加列 number
alter table user add number int;
#修改列的类型
alter table user modify number VARCHAR(20);
#修改列的名称
alter table user change number num VARCHAR(20);#修改列明时要重新修改类型
#删除列
alter table user drop num;
#修改表名
alter table user rename to u;
#删除约束,删除自增长
ALTER TABLE U MODIFY id int;
#添加主键自增长
alter table u modify id int auto_increment;
#删除主键,主键如果有自增长时,需要先删除自增之后才能删除主键。主键在删除后会保留一个非空约束,只有主键有自增长,
alter table u DROP PRIMARY KEY;
#增加主键
alter table u add PRIMARY KEY(id);
#删除非空约束
alter TABLE u MODIFY sex VARCHAR(20);
#增加非空约束
alter TABLE u MODIFY sex VARCHAR(20) not null;
#删除唯一约束
alter table u drop key name;
#增加唯一约束
alter table u add constraint unique(name);
#删除外键约束(要根据约束的名称来删除)
alter table stu DROP foreign key class_id;#要使用外键
alter table stu DROP foreign key stu_ibfk_1;
#添加外键约束
alter TABLE stu add CONSTRAINT stu_class_id foreign key(class_id) REFERENCES class(id);
day30
查询指定行
select * from student limit 1,3;
in
#查询工资不在3000~1000之间的员工的所有信息
select * from emp where !(sal>1000 and sal<3000);
select * from emp where not (sal>1000 and sal<3000);
#使用in关键字进项条件匹配,in中可以写多个值,只要符合里面任意一个值都能匹配成功
select * from emp where sal in(800,1600,1250,2975,2450,2850);
#查询工资不是。。。或者部门不是。。的员工的所有信息
select * from emp where sal not in(5000,2450,1250) or (deptno not in(10,20));
ifnull
#使用ifnull(a,b)如果第一个值为null则使用第二个值,否则使用第一个值
select ename,(sal*15+ifnull(comm,0)*12) as '年薪' from emp;
#年薪为15薪,年底时决定给奖金小于300的员工提升为每人每月奖金500元,求每个人年收入
select ename,sal*15+if(ifnull(comm,0)<300,500,comm)*12 from emp;
升序降序
#按照年收入对员工进行升序排序,排序时order by后面的别名不能加单引号,默认排序是升序asc 降序为desc
select ename,sal*15+if(ifnull(comm,0)<300,500,comm)*12 '年薪' from emp order by 年薪 asc;
select ename,sal*15+if(ifnull(comm,0)<300,500,comm)*12 '年薪' from emp order by 年薪 desc;
#查询员工的所有信息m,按照工资降序排序.第一个值相同,按照第二个列进行排序
select * from emp order by sal desc limit 2,4;
select * from emp order by sal desc,ename asc;
求绝对值
select abs(-456);
取余
select 11%2;
select mod(11,2);
向上取整
select ceiling(55.34);
四舍五入
select round(85.45,1);
截取小数
select truncate(2001.154,0);
select truncate(2001.154,1);
select truncate(2001.154,2);
ascii编码值
select ascii('A');
字符串等
#字符串的长度
select length('rgerthrthgsrtgerthyhj');
#查询名字长度是5的员工emp表
select * from emp where LENGTH(ename)=5;
#字符串拼接
select concat('hello','jaava','hello','zhangsan');
#返回前面字符串在后面字符串中出现的位置,注意从1开始计算,如果没有就返回0
select locate('ja','hello java');
#返回后面字符串在前面字符串中出现的位置,注意从1开始计算,如果没有就返回0
select instr('hello java','ja');
#从左侧进行字符串截取
select left ('hello',2);
#从右侧进行字符串截取,空格也是字符串
select right('hello ',2);
#从中间截取,从第几位开始到截取几位,注意中间没有逗号
select substr('hello java' FROM 2 FOR 1);
select substr('hello java',2 );#从第二个开始截取剩余的全部
#去除字符串的空格
select trim(' oihohosg edtgrt dfgr ') '我的';
select ltrim(' oihohosg edtgrt dfgr ') '我的';#去除左侧空字符串
select rtrim(' oihohosg edtgrt dfgr ') '我的';#去除右侧空字符串
#字符串替换,前面是字符串,中间为需要替换的字符串,后面是替换后的字符串
select replace(' oihohosg edtgrt dfgr ',' ','');
#字符串翻倍
select repeat('又热有麻将房',50);
#字符串反转
select reverse('今天天气不错子');
#字符串替换,通过位置进行替换,从第二个位置开始,一个字符串替换成dfgh
select insert('ABCDEFGHI',2,1,'dfgh');
select insert('ABCDEFGHI',2,0,'dfgh');
#在字符串sdkjfhkjhfwfoiqewirfjioqweoqwr在第一个0后面插入狗生没有了希望
select insert('sdkjfhkjhfwfoiqewirfjioqweoqwr',14,0,'狗生没有了希望');
select insert('sdkjfhkjhfwfoiqewirfjioqweoqwr',locate('o','sdkjfhkjhfwfoiqewirfjioqweoqwr')+1,0,'狗生没有了希望')
select insert('sdkjfhkjhfwfoiqewirfjioqweoqwr',position('o' in 'sdkjfhkjhfwfoiqewirfjioqweoqwr')+1,0,'狗生没有了希望')
#字符串变成小写
lcase(str);
时间
#获得当前时间
select now();
#获得年月日
select curdate();
#获取时分秒
select current_time();
#返回星期的索引,星期六返回7,星期天返回1
select dayofweek(now());
select dayofmonth(now());#这个月过了多少天
select dayofyear(now());
#求出年份
select year(now());
#求出月份
select month(now());
#求出天
select day(now());
#求出时
select hour(now());
#求出分
select minute(now());
#求出秒
select second(now());
select day('2020-09-09');
#求出星期几所对应的英文名称
select dayname(now());
#求出月份的名称
select monthname(now());
#求出季度,春天为1,冬天为4
select quarter(now());
#根据参数决定求年月日时分秒
select extract(day from now());
select extract(hour from now());
select extract(minute from now());
#在时间上加上对应的 年月日时分秒
select date_add(now(),interval 30 year);
#在时间上减去对应的年月日时分秒
select date_sub(now(),interval 30 year);
#看如今距离2000-08-28多久了(前面日期减掉后面的日期)
select datediff(now(),'2000-08-28');
#日期转为天数
select to_days(now());
select DATE_ADD(CURDATE(),INTERVAL - day(CURDATE())+ 1 day);#本月第一天
select DATE_ADD(CURDATE()-day(CURDATE()) + 1,INTERVAL 1 MONTH);#下月第一天
select CURDATE()-10;#把日期变为20211208后减一,若减的数为10,则结果为20211199
select NOW()-1;#秒数减一
select to_days(curdate()-1);#天数减一后,转为天数(前提是减后格式符合日期标准格式)
select DATE_ADD(DATE_ADD(CURDATE(),INTERVAL - day(CURDATE())+ 1 day),INTERVAL 1 MONTH);#下个月的第一天
select to_days(DATE_ADD(CURDATE()-day(CURDATE()) + 1,INTERVAL 1 MONTH))-to_days(CURDATE());
当前数据库名称
select database();
查看当前的编码格式
select charset('多');
加密函数
select md5(1123);
select password(123);
统计平均最大等
select avg(sal) from emp;
select max(sal) from emp;
select min(sal) from emp;
#求数据的总数
select count(*) from emp;
select sum(sal) from emp; 里面可以有Boolean式,为true时自加一
day33
Switch类似方法
select case when <> then <> else <> end;
select case 1
when 1 then '这是1'
when 2 then '这是2'
when 3 then '这是3'
else '大于三'
end;
select username,IF(is_male=1,'男','女') from user
select username,case is_male when 1 then '男' when 0 then '女' end from user;
SQL执行顺序
#1:from 确定表
#2:on join 确定表(多表联查)
#3:where 筛选行,将不符合要求的数据进行筛选掉
#4:group by 对筛选之后的数据进行分组统计(列的别名在这一步之后才能使用)
#5:having 对分组之后的数据进行筛选
#6:select 确定列
#7:distinct 去除重读数据
#8:order by 对数据排序
#9:limit 分页显示数据
多表查询
#多表查询主要分为一下几种
#1:交叉连接
#2:自然链接
#3:内连接
#4:外连接
#5: 全连接
#6:交并不差
#7:(自连接)
#笛卡尔积:两个表的数据产生了乘积相当于x*y
#笛卡尔积会让数据变得极为庞大,所以我们编写SQL时候应该尽量避免它
#隐式交叉链接(产生笛卡尔积)
select * from emp,dept
#显式交叉链接(产生笛卡尔积)
select * from emp cross join dept
#自然链接 将两张表中等值的列自动排列到一起,并放在第一列显式,过滤到笛卡尔积显示给我们
select * from emp natural join dept
#隐式内连接,过滤掉笛卡尔积
select * from emp,dept where emp.deptno=dept.deptno
#显式内连接(使用inner join代替,然后使用on来做表关系的连接)
select * from emp inner join dept on emp.deptno=dept.deptno
#内连接问题,虽然避免了笛卡尔积的并且常用,但是不符合条件的数据是无法显示的,这时需要使用到外连接
#左右连接
select * from emp left join dept on emp.deptno=dept.deptno
select * from emp right join dept on emp.deptno=dept.deptno
#全连接
select * from emp full join dept
#交 mysql无法使用
select * from emp
interval
select * from emp where deptno=20
#并
select * from emp
union all
select * from emp where deptno=20
#补 使用下面的结果集对上一句SQL的结果进行补充,不会产生重复数据
select * from emp where deptno=20
union
select * from emp
#差 mysql不存在,使用上面的结果集,减掉下面的结果集,然后对剩余的数据进行补充
select * from emp
minus
select * from emp where deptno=20
#自连接
#求每个员工上级领导姓名
select e.ename,m.ename from emp e left join emp m on e.mgr=m.empno
#求每个部门工资最高的人员的姓名
select emp.ename 姓名,emp.deptno 部门编号 from
(select max(sal) m,deptno from emp group by deptno) e,emp
where e.m=emp.sal and e.deptno=emp.deptno;
select * from
(select max(sal) m,deptno from emp group by deptno) e right join emp
on e.m=emp.sal and e.deptno=emp.deptno;
#获取比普通员工最高薪水还要高的经理人的名称
select ename from
(select max(sal) m from emp where empno not in(select mgr from emp)) e,
(select ename,sal from emp where mgr in(select empno from emp)) m
where m.sal > e.m
day35
事务
A表
事务: TCL(事务控制语言) 事务实际上就是指我们要做的事情,那在sql语句中事务就代表
了要执行的sql语句。
张三给李四转账虽然是一件事情,但是对应到我们sql却需要两条,分别是1:修改张三的余额,
2:修改李四的余额,此时如果我们执行第一步之后系统出现问题,导致没有给李四增加上钱,
就会出现严重bug,此时我们就需要想办法将两条sql变成一件事情,这样的话两条sql要成功就
一起成功,要失败就一起失败,这就是为什么需要事务的原因。
在关系型数据库中默认每条sql语句都是一个单独的事务,当前我们也可以取消掉默认,让多条sql
语句变成一个事务。
事务的主要两个关键字:
COMMIT 提交事务,在开启事务的时候只有提交事务数据库才会发生改变。
ROLLBACK 回滚事务,回滚事务可以让数据库恢复到执行sql之前的状态。
事务被提交后便不可以使用回滚恢复数据
因为在mysql中默认每条sql语句都是单独的事务,所以在mysql中事务默认是自动提交的,在事务
开启的情况下只有提交事务才会对数据库执行更改的操作。
事务的四大特性
1: 原子性 在过去的最小单位,代表了不可进行分割,表示一个事务是一个原子性的整体,不能
对其进行分割,要么一起成功,要么一起失败。
2: 一致性 数据从一个状态转变成了另外一个状态(数据安全性,举例:张三1000元,李四1000
元,那么张三给李四转钱,无论怎么转最后数据库应该还是有2000元)。
3: 隔离性 为了防止多个事务之间,互相干扰。
1: 读未提交 READ UNCOMMITTED 是指,用户A没有提交的数据,被用户B读取到了(脏读,不可重复读,幻读)。
2: 读已提交 READ COMMITTED 可以避免脏读,会引发不可重复读。
3: 可重复读 REPEATABLE READ 可以避免脏读,不可重复读,会引发幻读。(mysql默认的隔离级别)
4: 串行化 SERIALIZABLE 相当于Java的单线程,在操控表的过程中,其余任何人都不能操作。串行化不会引发任何问题。
不可重复读:是指用户A在两次读取数据的中间,数据被用户B修改了,导致A两次读取的数据不一致。
幻读:是指用户A在连续操作数据的过程中,B增加了一条新的数据,影响到了A。
4: 持久性 将改变的数据持久化到可掉电设备(硬盘)中
CREATE TABLE u(
id int,
name varchar(20),
money int
);
INSERT into u values(1,'张三','1000');
INSERT into u values(2,'李四','1000');
# 张三给李四转钱,转500
UPDATE u SET MONEY=MONEY-500 WHERE ID=1;
这里出现了异常
UPDATE u SET MONEY=MONEY+500 WHERE ID=2;
# 上面的例子中,由于事务是mysql自动控制的,每条sql都是单独的事务,所以36出现bug不影响
# 35行sql的执行。
# 手动控制事务start transaction
START TRANSACTION;
UPDATE u SET MONEY=MONEY-500 WHERE ID=1;
这里出现了异常
UPDATE u SET MONEY=MONEY+500 WHERE ID=2;
COMMIT;
ROLLBACK;
SELECT * FROM U
****************************查看事务的隔离级别************************************
SELECT @@TX_ISOLATION
# 设置数据库的隔离级别读未提交,观察脏读
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION
SELECT * FROM U;
COMMIT;
# 设置隔离级别读已提交,解决脏读
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT * FROM U;
COMMIT;
# 观察不可重复度
START TRANSACTION;
SELECT * FROM U;
SELECT * FROM U;
COMMIT;
# 设置隔离级别可重复读,解决不可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT * FROM U;
SELECT * FROM U;
COMMIT;
# 观察幻读的出现,表面看起来可重复度,解决了幻读,但是真的解决了么?
START TRANSACTION;
SELECT * FROM U;
#SELECT * FROM U;
UPDATE U SET money=1000;
COMMIT;
# 解决幻读
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM U;
#SELECT * FROM U;
UPDATE U SET money=2000;
COMMIT;
B表
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
INSERT INTO U VALUES(3,'王五',50000);
COMMIT;
ROLLBACK;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
INSERT INTO U VALUES(3,'王五',50000);
ROLLBACK;
SELECT @@TX_ISOLATION;
# 观察不可重复度
START TRANSACTION;
UPDATE U SET MONEY=1 WHERE ID=2;
COMMIT;
# 设置隔离级别可重复读,解决不可重复读
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
UPDATE U SET MONEY=1 WHERE ID=1;
COMMIT;
# 观察幻读
START TRANSACTION;
INSERT INTO U VALUES(3,'王五',50000);
COMMIT;
# 解决幻读
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT * FROM U;
COMMIT;
锁
for update悲观排它表行锁… select * from emp where id=’’ for update;
lock in share mode;共享锁(s锁,读锁);
笑嘻嘻的,这个人很乐观
小黄,小蓝 共享单车,
锁:锁的主要目的就是为了保护东西,那数据库的锁主要目的就是为了保护数据,主要是为了防止多用户共同操控数据的时候,出现数据混乱。
乐观锁,悲观锁,共享锁,排它锁,表锁,行锁。
乐观锁:非常乐观的一个人,总是认为在自己操控数据的时间之内,肯定不可能有其他人来操控数据,乐观锁需要我们通过数据库设计来实现,一般我们使用乐观锁的话,
会在数据库之内加入一列叫版本号值是数字,或者是时间戳,然后在每次去修改数据库之前,都先查看当前版本号是多少,在修改的时候需要去对比版本号是否一致,如果
一致则修改成功,否则就是修改失败。
CREATE TABLE S(
ID INT,
NAME VARCHAR(20),
MONEY INT,
VERSION INT DEFAULT 1);
INSERT INTO S VALUES(1,'张三',1000,DEFAULT);
SELECT * FROM S;
# 乐观锁去修改数据时候的操作: 将id是1的人加1000块钱。
# 1: 先查出ID 1的人版本号多少
SELECT VERSION FROM S WHERE ID=1;
# 2: 将id是1的人加1000块钱。
UPDATE S SET MONEY=MONEY+1000,VERSION=VERSION+1 WHERE ID =1 AND VERSION=1;
# 悲观锁在修改数据的时候,总是认为会有人跟我抢车位,那如果对方跟我抢车位,我就要像个办法先占住
# 这个车位,共享锁和排它锁都是悲观锁的实现,数据库对悲观锁提供有关键字。
# 排它锁(X锁,写锁) 假设事务A对数据库对象o加了X锁之后,在此期间任何其他的事务都不能对o加锁。
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT * FROM EMP FOR UPDATE;
insert into emp (empno) values(1000);
COMMIT;
# 共享锁(S锁,读锁) 假如事务A对数据库对象o加了S锁之后,就可以对其进行查询,但是不能更新数据,并
# 且此时,其他的事务可以继续对数据库对象加S锁,但是不能加X锁。
START TRANSACTION;
SELECT * FROM EMP lock in SHARE MODE;
insert into emp (empno) values(2000);
COMMIT;