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: 约束分为行级与表级 行级约束:自增,默认值,非空,检查 表级约束:主键,外键,唯一
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;一样,但是效率更高
1:delete后面可以跟条件进行删选,而truncate后面不能有任何条件
2:delete操作在日志中有记录,可以使用回滚,而truncate在日志中没有记录,不能使用回滚
3:delete是删除数据而已,而truncate是相当于删除了表,重新建立了一张表,原表还在,truncate效率更高
drop table user;
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 用来表示字符串,字符串在数据库中需要指定长度,而varchar是可变字符串,例如varchar(20)虽然指定了这一列能存储20个字符,但是其占用空间是根据实际占用情况来看的,如果数据只占用了两个字符的话那实际占用空间就是2个字符,当最高占用不能超过20个字符,varchar最高能存储65532字节的数据 #char 用来表示字符串,不可变(例如sex(20),这里指定了sex每一行数据都最多能存储20个字符,但是如果只存放了一个字符,实际占用空间还是20个字符的空间
data 数据类型,用来表示日期,没有具体到时分秒 timestamp 虽然会以年月日,时分秒来表示,但是本质上是时间戳。
bit 只能存储数字0和1,对应Java布尔
约束:用来规定以及限制数据的内容。 #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;
#增加列 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);
select * from student limit 1,3;
#查询工资不在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(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);
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时自加一
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;
#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
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;