00 MySQL
时间:2022-03-14 01:55
1数据库 1.1名词解释 DB:数据库Database,用于存放数据仓库 DBMS:数据库管理系统 DataBase Management System,管理数据库 table : 表,用于描述实体(对象)集合,需要提供行和列 1.2数据库分类 网状型数据库 层次型数据库 关系型数据库(Relationship DataBase Management System) 非关系型数据库:NoSql (not only sql) 1.3关系型数据库种类 DB2 : IBM公司,收费 Oracle : oracle公司,收费 MS sql server : 微软,收费,只适合window平台 Mysql : 免费
2 Mysql数据库 2.1介绍 2.2安装 其中MySQLInstanceConfig.exe可用于绿色版Mysql的设置. mysql默认端口:3306 mysql将UTF-8编码称为:UTF8(只此一家) mysql默认账号:root
2.3mysql启动和停止 手动方式(了解) cmd> mysqld --console 使用window服务 服务开发方式:运行 “services.msc” 启动 cmd> net start mysql 停止 cmd> net stop mysql
2.4mysql登录 方式1(推荐):格式 “mysql -u账号 -hip地址 -p密码” 例: cmd> mysql -uroot -h192.168.18.98 -p1234 方式2: 例: cmd> mysql --user=root --host=192.168.18.98 --password=1234
2.5mysql常用命令 显示当前数据库服务器中的数据库列表 mysql> show databases; 显示当前所使用的数据库名称 mysql> select database(); 显示当前数据库的状态 mysql> status; 使用数据库 mysql> use 要使用已存在的数据库名称; 显示数据库中的数据表 mysql>show tables; 显示当前数据库中某表的表结构 (DESCRIBE ) mysql> desc user; 显示所支持的字符集 show character set; 使用sql语句,注意:sql语句必须以分号(;)结尾 %mysql% 表示mysql的安装目录 %mysql%/data/mysql 表示mysql核心数据,切记不能删除
3 SQL语句 3.1介绍 sql:结构化查询语言(structured query language), 是操作和检索(查询)关系型数据库的标准语言. ?注:ANSI(American National Standards Institute,美国国家标准学会)制定的标准 各个数据库生产厂商,要遵循sql标准,同时又开发出自己数据特有的特性 3.2SQL分类 DDL,Data Definition Language,数据定义语言 管理表的结构和索引的结构 -- 【结构】 保留字:CREATE (create 创建)),DROP (drop 删除),ALTER (alter 修改) DML,Data Manipulation Language,数据操作语言 用于添加,修改和删除表中的行(记录) -- 【数据】 保留字:INSERT (insert 录入),DELETE(delete 删除)和TRUNCATE ,UPDATE(update 更新) DQL,Data Queries Language,数据查询语言 用以从表中获得数据 -- 【查询(检索)】 保留字:SELECT (select 查询),WHERE (where 条件),GROUP BY (group by 分组),having和order by(order by 排序) DTL,Data Transaction Language,事务处理语言 确保被DML语句影响的表的所有行及时得以更新 -- 【事务】 保留字:BEGIN TRANSACTION (begin transaction 开启事务),COMMIT (commit 提交事务)和ROLLBACK(rollback 回滚事务) DCL,Data Control Language,数据控制语言 授权用户或用户组操作和访问数据的权限 --【权限】 保留字:GRANT(grant 授权)或REVOKE (revoke 取消权限)
3.3DDL:数据定义语言 对数据库、表、列 进行结构的操作 3.3.1数据库操作 创建数据库 mysql> create database [IF NOT EXISTS] 数据库名称 [character set 字符集] ; 数据库默认使用 平台设置编码(my.ini文件) 删除数据库 mysql> drop database [IF EXISTS] 数据库名称; 修改数据库 mysql> alter database character set 修改数据库字符集;(不建议) 3.3.2表操作 创建表 mysql> create table 表名(字段描述1,字段描述2, … ); * 多个字段描述 使用逗号分隔 * 最后一个字段描述没有逗号 字段描述的格式:字段名 字段类型 [约束] 删除表 mysql> drop table 表名; 修改表 mysql> alter table 表名 rename [to] 新表名; 3.3.3列操作 添加列 mysql> alter table 表名 add [column] 字段描述 删除列 mysql> alter table 表名 drop [column] 字段名 修改列 mysql> alter table 表名 change [column] old_字段名 new_字段描述
3.4字段类型 3.4.1字符串
mysql类型 | java类型 | 描述 |
char(n) | java.lang.String | char表示固定字符串,n表示字符个数。 例如:char(5) , 当前字段必须写5个字符. 如果录入的数据”abc”,右侧自动添加空格,结果“abc空空” |
varchar(n) | java.lang.String | varchar表示可变字符串,n表示字符个数. 例如:varchar(5),当前字段最多存放5个字符. 如果例如的数据”abc”,存放的就是”abc” |
3.4.4大数据 字节大数据: blob ,Binary Large Object 字符大数据: clob , Character Large Object
3.5 DML数据操作语言 对指定的表中的数据进行:添加、删除、修改 ?录入数据 格式1: mysql> insert into 表名 values(字段对应的值,值2,值3,….); 格式2: mysql> insert into 表名(字段名1,字段名2,…) values(值1, 值2,….) ?修改数据 格式1: mysql> update 表名 set 字段=值,字段=值,….. #将表中所有的字段都进行修改 格式2: mysql> update 表名 set 字段=值,字段=值,…. where 条件 # 将符合条件的字段进行修改 ?删除数据 格式1: mysql> delete from 表名; #清空表中的所有数据 格式2: mysql> delete from 表名 where 条件; #删除符合条件
3.6DQL数据查询语言 select distinct 字段|* from 表名 where 条件 group by 分组字段 having 分组条件 order by 排序字段 asc|desc 3.6.1准备数据 create table t_user( id varchar(22) primary key, firstname varchar(22), age smallint, secondname varchar(22), counts smallint ); insert into `t_user`(`id`,`firstname`,`age`,`secondname`,`counts`) values (‘u001‘,‘张‘,18,‘飞‘,60), (‘u002‘,‘赵‘,20,‘云‘,58), (‘u003‘,‘关‘,22,‘羽‘,80), (‘u004‘,‘刘‘,25,‘备‘,98), (‘u006‘,‘黄‘,18,‘盖‘,NULL), (‘u005‘,‘王‘,12,‘子云‘,20), (‘u007‘,‘诸葛‘,24,‘亮‘,100);
3.6.2没有条件查询 查询所有 mysql> select * from t_user; 查询部分信息 select secondname,age from t_user; select id, firstname, age, secondname, counts from t_user; #等价于查询所有,推荐写法 查询用户编号、姓名,及格 select id,concat(firstname,secondname),counts-60 from t_user; ?修改上面查询显示字段名称,用"姓名"表示姓名,用"及格"表示及格 #字段的别名格式:字段名 [as] 别名 select id,concat(firstname,secondname) as 姓名,counts-60 及格 from t_user; select id,concat(firstname,secondname) as ‘姓 名‘,counts-60 及格 from t_user; #引号可以使用 select id,concat(firstname,secondname) as `姓 名`,counts-60 及格 from t_user; #
3.6.3带有条件查询 查询分数等于60的学生 select * from t_user where counts=60; #如果是数字,可以使用单引号,一般不用。 查询姓"张"学生 select * from t_user where firstname = ‘张‘; #注意:如果是字符串必须使用引号,建议是单引号 查询年龄大于18的学生 select * from t_user where age > 18; 显示分数在60-80的学生 select * from t_user where counts >=60 and counts <=80; select * from t_user where counts between 60 and 80; 查询编号为u001和u002的学生 select * from t_user where id = ‘u001‘ or id = ‘u002‘; select * from t_user where id in (‘u001‘, ‘u002‘); 查询年龄是18或20的学生 select * from t_user where age = 18 or age = 20; select * from t_user where age in (18, 20); 查询名中含有"云"的学生 ### like语句,模糊查询,不完全匹配查询 ### 格式:字段 like 值 ## 特殊符号:% _ % 匹配若干 ‘%云‘,必须以“云”结尾 ‘云%‘,必须以“云”开头 ‘%云%‘,含有“云” _ 匹配一个字符 # 查询名中含有"云"的学生 select * from t_user where secondname like ‘%云%‘; # 查询名中第二字还有"云"的学生 select * from t_user where secondname like ‘_云%‘; 查询分数小于60 或 大于90分的学生 //这种情况下属于两边,不能用between and, 而只能是or, 何况or和and功能强大得多. select * from t_user where counts < 60 or counts > 90; 查询分数等于60 或者 分数大于90并且年龄大于23 select * from t_user where counts = 60 or counts > 90 and age > 23; #优先级问题: and 优先 or select * from t_user where counts = 60 or (counts > 90 and age > 23); 查询没有考试的学生 select * from t_user where counts is null; 查询所有考试的学生 select * from t_user where counts is not null;
3.6.4聚合函数(同查询结果进行相应统计,显示一行一列数据) count(): 用于计数,查询共有有多少条记录 select count(*) from t_user; select count(id) from t_user; #统计指定字段值 select count(counts) from t_user; #且不进行null计数 select count(1) from t_user; 平均成绩 avg() select avg(counts) from t_user; #不计算null select sum(counts)/count(*) from t_user;#计算null,指的是所有人的平均分,包含没 参加考试的. 最高成绩 max() select max(counts) from t_user; 最小年龄 min() select min(age) from t_user; 班级总成绩 sum() select sum(counts) from t_user; 查询所有的年龄数 select age from t_user; ### 去重复 select distinct age from t_user;
3.6.5排序 格式:select.... order by 排序字段名1 asc|desc, 字段2 asc|desc, ....; asc:表示升序,默认值,可以不写 desc:表示降序 select age,money from person order by money desc,age asc; *指先使用money进行降序的排列,如果数据重复,在按照age排序 10 18 10 20 10 23 9 20
3.6.6分组 #1添加班级字段(classes) alter table t_user add column classes varchar(3); update t_user set classes = ‘1‘ where id in (‘u001‘,‘u002‘,‘u003‘,‘u004‘); update t_user set classes = ‘2‘ where id in (‘u005‘,‘u006‘,‘u007‘); #2查询1班和2班的平均成绩 #2.1 查询所有平均成绩 select sum(counts)/count(*) from t_user; #2.2 使用班级进行分组 ### 分组格式:select .... group by 分组字段 having 分组条件; select classes,sum(counts)/count(*) from t_user group by classes; 注意:如果使用分组,select查询字段处,只能使用“聚合函数”或“分组字段” select id,classes,sum(counts)/count(*) from t_user group by classes; #此处id没有意义 #3查询班级平均成绩不及格的班级成员信息 3.1 查询班级平均成绩不及格(包含没参加考试的) select classes as 班级, sum(counts)/count(*) as 平均分 from t_user group by 班级 having 平均分<60; 3.2 2班的班级成员信息 select * from t_user where classes = ‘2‘;
3.3 整合 新建表二: create table t_user2( name varchar(20) not null, classes varchar(16) not null ); 再insert to数据 insert into t_user2 (name, classes) values (‘作者‘, ‘1‘), (‘小明‘, ‘2‘); 最终得到 ### 多表操作 , 表名 [as] 别名 select * from A,B where A.classes = B.classes; ### 表的别名 select a.* from A as a,B as b where a.classes = b.classes;
例如 select * from t_user as A , t_user2 as B where A.classes=B.classes; select A.* from t_user as A , t_user2 as B where A.classes=B.classes; //应该是笛卡尔(直积)全部串起来 ,然后再select 元素的排列. 列举出那些班级平均分<60的所有学生 思路:将列表一 和 结果select修饰过后的表二拼起来即可. 法一: select A.* from t_user as A, (select classes, sum(counts)/count(*) as avgcount from t_user group by classes having avgcount < 60) as B where A.classes = B.classes; 法二: 暂时没想到.不写了
4 cmd中文乱码处理 1,2,4 client/connection/results 此三项必须保持一致,且与事实符合 client:在服务器端设置的客户端的编码 connection:在服务器端设置的客户端与服务器的连接编码 results:在服务器端设置的服务器响应给客户端数据的编码 mysql 服务器端环境变量:character_set_database,设置数据库的编码,如果不出现乱码,设置的字符集支持中文即可,GBK或UTF-8或GB2312等 修改服务器端设置: mysql> set names GBK:
5数据库备份与还原 备份 格式:mysqldump -u账号 -p密码 数据库名称 > 位置 cmd# mysqldump -uroot -p1234 day14 > d:/day14.sql 还原 格式: mysql -u账号 -p密码 数据库名称 < 位置 cmd# mysql -uroot -p1234 day14_bak < d:/day14.sql 注意:必须手动先创建数据库
6修改root账号的密码 手动启动mysql服务器,且进行无权限验证方式的启动 cmd> mysqld --console --skip-grant-tables 使用root账号登陆,不需要密码 cmd> mysql -uroot 修改账号的密码,mysql数据库,user表中 update user set password = password(‘1234‘) where host = ‘%‘; #需要使用 password() 函数对密码进行加密 删除用户 语法: DROP USER ‘账号’@’host’ 例如: mysql> drop user ‘root‘@‘%‘; 密码不正确
7约束 7.1主键约束: 被约束的字段的内容,非空不重复 关键字:primary key 一个表中只能由一个主键 但一个主键不表示只是一个字段,可以是联合主键 使用 方式1 : 声明字段时,同时声明主键 方式2 : 声明字段之后,在约束区域声明主键 constraint primary key (id) 方式2 可以声明 联合主键:多个字段组合在一起,是一个主键,内容合并在一起不重复。 方式3 : 在创建表之后,修改表结构,声明主键 alter table pk03 add [constraint] primary key (id);
7.2唯一约束(被约束的字段的内容,不能重复) 方式1 : 声明字段时,同时声明unique约束. 方式2 : 声明字段之后,在约束区域声明主键 constraint unique (id) 方式3 : 在创建表之后,修改表结构,声明主键 alter table pk03 add [constraint] unique (id);
7.3非空约束(被约束的字段的内容,不能为null) 关键字:not null 使用:在声明字段时,声明非空
7.4 Mysql特有字段:自动增长列 关键字:auto_increment 自动增长列:被约束字段的内容,可以自动累加, 所以录入数据时,可以不操作自动增长列 删除 delete from ai01; #清空表中的数据,但不重置“自动增长列”的累加数 truncate table ai01;#清空表中的数据,但重置“自动增长列”的累加数 (先删除表,再创建表)
7.5 外键约束 关键字:foreign key 外键: 1 在从表添加一个字段 2 类型:必须与主表主键的一致 名称:自定义,建议:user_id 或 uid 内容:从表外键的内容,必须是主表主键的引用 特点: 从表的外键不能添加(更新),主表主键不存在的内容 主表的主键不能删除(更新),从表外键已经引用的内容 //可以拿学籍注册举例
8.1一对多 实例: 国家(1) -- (*)城市 教室(1) -- (*)学生 用户(1) -- (*)书籍 需要使用主外键关系描述:一对多 #添加的格式:alter table 从表表名 add constraint [外键名称] foreign key (从表外键) references 主表表名 (主表主键); #删除的格式:alter table 表名 drop foreign key 外键名称; //所以最好以后每个key都要自己起名字.
通过案例学习 # 主表:user表 create table t_user( id varchar(32), username varchar(50), password varchar(32) #MD5加密 ); ### 主表的主键 alter table t_user add constraint primary key (id); # 从表:book表 create table t_book( id varchar(32), title varchar(50), author varchar(50), user_id varchar(32) #外键,类型t_user.id一致 ); #添加外键 alter table t_book add constraint foreign key (user_id) references t_user (id); #插入数据 insert into t_user(id,username,password) values(‘u001‘,‘jack‘,‘1234‘); insert into t_user(id,username,password) values(‘u002‘,‘rose‘,‘1234‘); insert into t_user(id,username,password) values(‘u003‘,‘tom‘,‘1234‘); insert into t_book(id,title,author,user_id) values(‘b001‘,‘javaweb‘,‘任童‘,‘u001‘); #成功,外键是主键引用 insert into t_book(id,title,author) values(‘b002‘,‘javaweb2‘,‘任童2‘); #成功,user_id = null,外键可以为null,而且我发现可以插入多个null. 这不太好吧. insert into t_book(id,title,author,user_id) values(‘b003‘,‘android‘,‘小华华‘,‘u001‘); insert into t_book(id,title,author,user_id) values(‘b004‘,‘菊花是怎么成长的‘,‘强哥‘,‘u002‘); #1 笛卡尔积,两个表的乘积集合 select * from t_user,t_book; select count(*) from t_user,t_book; #12条 #2 隐式内连接 ## 例如:查询某人借某了某书 select * from t_user,t_book where t_user.id = t_book.user_id; select t_user.username,t_book.title from t_user,t_book where t_user.id = t_book.user_id; #可以起表的别名哦. 下面这句话用隐式内连接实现(借阅人和借阅数据的列表) select U.username, B.title from t_user as U , t_book as B where U.id = B.user_id; #3 内连接 ## 格式:select ... from A inner join B on 条件 select U.username, B.title from t_user as U inner join t_book as B on U.id = B.user_id; 和隐式内连接一样 #4 外连接 # 左外连接:查询A表的所有内容,B表的内容是否显示,取决条件是否成立,成立显示,不成立显示null ### 格式:select ... from A left outer join B on 条件 ### 例如:统计用户借阅书籍情况 select * from t_user u left outer join t_book b on u.id = b.user_id; # 右外连接:查询B表的所有内容,A表的内容是否显示,取决条件是否成立,成立显示,不成立显示null ### 格式:select ... from A right outer join B on 条件 ### 例如:统计书籍被解决情况 select * from t_user u right outer join t_book b on u.id = b.user_id;
8.2多对多 实例: 教师(*) -- (*)学生 人(*) -- (*)角色 角色(*) -- (*)权限 学生(*) -- (*)课程【】 ##多对多 (many) ## 主表:学生表 create table m_student( id varchar(32) primary key, #主键 `name` varchar(50), age int ); ## 主表:课程表 create table m_course( id varchar(32) primary key, #主键 content varchar(50), teacher varchar(50) ); ## 从表:中间表,学生课程表 create table m_student_course( student_id varchar(32), #学生表对应外键 course_id varchar(32) #课程表对应外键 ); ##### 关系 ### 中间表与学生表 :主外键关系 alter table m_student_course add constraint foreign key (student_id) references m_student (id); ### 中间表与课程表 :主外键关系 alter table m_student_course add constraint foreign key (course_id) references m_course (id); ### 联合主键 alter table m_student_course add constraint primary key (student_id,course_id); ### 外键删除 alter table 表名 drop foreign key 外键名称; ### 测试: insert into m_student(id,name,age) values(‘s001‘,‘jack‘,18); #成功 insert into m_course(id,content,teacher) values(‘c001‘,‘java基础‘,‘自摸‘); #成功 insert into m_student_course(student_id,course_id) values(‘s001‘,‘c001‘);#成功,多对多关系通过中间数据维护 insert into m_student(id,name,age) values(‘s002‘,‘rose‘,21); insert into m_course(id,content,teacher) values(‘c002‘,‘java web‘,‘梁少‘); insert into m_course(id,content,teacher) values(‘c003‘,‘android‘,‘侃哥‘); insert into m_student_course(student_id,course_id) values(‘s001‘,‘c002‘); insert into m_student_course(student_id,course_id) values(‘s001‘,‘c003‘); insert into m_student_course(student_id,course_id) values(‘s002‘,‘c002‘); insert into m_student_course(student_id,course_id) values(‘s002‘,‘c003‘); ### 查询:某人学某课 ##隐式内用多对多看来是高级连接操作吧 select s.name , c.content from m_student s , m_student_course sc , m_course c where s.id = sc.student_id and sc.course_id = c.id; ##内连接,三个的内连接也是高级的内连接吧 select s.name ,c.content from m_student s inner join m_student_course sc on s.id = sc.student_id inner join m_course c on sc.course_id = c.id; 8.3一对一 (不讲)
SQL注入 select * from t_user where username = ‘jack‘ or 1=1 or 1=‘‘ and password = ‘12345678‘ select * from t_user where username = ‘\‘‘ and password = ‘‘ # 手动防止sql注入,将所有的单引号替换成 "\‘"
2预处理对象 2.1介绍 接口:javax.sql.PreparedStatement 预处理对象,预先处理sql语句,使用户的输入的内容,只是执行的参数,而不是sql语句语法的一部分。 2.2编写流程 1 提供一个已经处理过的sql语句,让预处理对象进行编译。 -- 将实际参数使用?替换 String sql = "select * from t_user where username = ? and password= ? "; 2 使用已经处理过的sql,获得预处理对象 PreparedStatement psmt = conn.prepareStatement(sql); //此处提供sql语句 3 设置实际参数 psmt.setXxx(1,"jack"); //给第一个?设置实际参数 psmt.setString(2,"1234"); //给第二个?设置实际参数 4 执行sql语句 int r = psmt.executeUpdate(); //注意:此处不提供sql语句 ResultSet rs = psmt.exeucteQuery(); 2.3应用场景 ①防sql注入: sql注入:用户输入的内容,是sql语句语法的一部分 ②大数据:blob字节大对象、clob 字符大对象 数据库可以保存:图片、视频、小说等 注意:图片、视频等不会保存数据库,如果需要图片,则完成文件上传,将图片等保存服务器端,将服务器端保存的路径,保存数据库中。 ③批处理 : 批量的处理sql语句 Statement 批处理 : 一次性可以执行多条sql语句,需要编译多次。 * 应用场景:系统初始化 (创建表,创建数据等) * api 添加sql语句,st.addBatch(sql) --添加sql语句 批量处理sql语句,int[] st.executeBatch() 清除缓存: st.clearBatch(); PreparedStatement 批处理 : 执行一条sql语句,编译一次,执行sql语句的参数不同。 * 应用场景:表数据初始化 * api 添加批量参数:psmt.addBatch() --添加实际参数,执行之前,需要执行psmt.setXxx()设置实际参数 执行批处理:int[] psmt.executeBatch() 清除缓存:pstm.clearBatch();
3事务 transaction 3.1介绍 事务:业务中存在一组操作,要么全部成功,要么全部不成功。 例如:转账 3.2事务特性 ACID 原子性:一个事务不可分割。【整体】 一致性:事务的前后数据一致。【数据】 隔离性:多个事务并发性。【并发】 持久性:事务操作之后不可改变状态。【不可变】--如果事务提交了,将不可改变。 3.3mysql事务的操作 开启事务:start transaction 提交事务:commit 回滚事务:rollback 3.4数据的隔离问题 脏读:一个事务读到另一个事务没有提交的数据。 不可重复读:一个事务读到另一个事务提交的数据。(update 更新) 幻读(虚读):一个事务读到另一个事务提交的数据。(insert 录入) 3.5数据隔离级别 数据的隔离级别,解决不用隔离问题。提供4种隔离级别 read uncommitted ,读未提交:一个事务读到另一个事务没有提交的数据。存在问题:3个 read committed ,读已提交:一个事务读到另一个事务调剂的数据。存在问题2个:不可重复读、幻读。解决问题:脏读 repeatable read,可重复读:一个事务中读到数据重复的。存在问题1个:幻读。解决问题:脏读、不可重复读 serializable ,串行化:单事务。没有问题,解决问题:脏读、不可重复读、幻读。 对比: * 性能:read uncommitted > read committed > repeatable read > serializable * 安全:read uncommitted < read committed < repeatable read < serializable mysql 默认隔离级别:repeatable read Oracle默认隔离级别:read committed Connection提供常量: TRANSACTION_READ_COMMITTED,指示不可以发生脏读的常量;不可重复读和虚读可以发生。 TRANSACTION_READ_UNCOMMITTED ,指示可以发生脏读 (dirty read)、不可重复读和虚读 (phantom read) 的常量。 TRANSACTION_REPEATABLE_READ ,指示不可以发生脏读和不可重复读的常量;虚读可以发生。 TRANSACTION_SERIALIZABLE,指示不可以发生脏读、不可重复读和虚读的常量。
3.6隔离级别演示 3.6.1准备工作 查询数据库隔离级别:mysql> show variables like ‘%iso%‘; mysql 系统环境变量查询:mysql> select @@tx_isolation; 设置数据库的隔离级别: mysql> set session transaction isolation level 隔离级别 3.6.2读未提交 A 隔离级别:读未提交 read uncommitted AB开始事务 A查询 B更新 A再查询 -- 查询到,A读到B没有提交的数据 B 回滚 A再查询 -- B更新之前的数据。 3.6.3读已提交 A 隔离级别:读已提交 read committed AB开启事务 A查询 B更新 A再查询 -- 没有查询到,解决:脏读 B提交 A再查询 -- 查询到,存在问题:不可重复读 3.6.4可重复读 A隔离级别:可重复读 repeatable read AB开启事务 A查询 B更新 A再查询 -- 没有查询到,解决:脏读 B提交 A再查询 -- 没有查询到,解决:不可重复读 A提交或回滚 A 再查询 -- 查询到,新事物 3.6.5串行化 A隔离级别:串行化 serializable AB开启事务 A查询 B更新 -- 等待 (A提交或回滚B继续操作;B等待超时) 3.7lost update 丢失更新 丢失更新:两个事务同时操作,A事务更新的数据,被B事务更新的数据覆盖了,导致A事务更新的数据丢失 解决 * 乐观锁:丢失更新肯定不会发生。提供版本字段,进行数据的有效操作。 * 悲观锁:丢失更新肯定会发生。采用mysql数据库的锁机制 * 读锁:共享锁,一个表可以存在多个读锁 mysql> select .... lock in share mode; * 写锁:排他锁,一个表只能由一个写锁。(独占) mysql> select .... for update; 注意:mysql的锁必须在事务中 所有的update语句都使用写锁
4事务案例 4.1JDBC事务 一个连接Connection 就表示一个事务 api conn.setAutoCommit(false); //开启事务 -- 将自动提交关闭了 conn.commit(); //提交事务 conn.rollback(); //回滚事务 mysql事务默认情况自动提交
4.2JDBC事务管理--service层() 4.2.1模板1:(必须学会) Connection conn = null; try{ //0 获得连接 conn = ....; //1 开启事务 conn.setAutoCommit(false); A步骤 B步骤 C步骤 D步骤 //2 在不报错的情况下, 提交事务 conn.commit(); } catch(e){ //3 回滚事务 conn.rollback(); } finally{ //释放资源 conn.close(); }
4.2.2模板2: # AB是必选项(A和B是一个整体),CD可选项(C和D一个整体)。 #需要通过Savepoint 保存点进行部分内容管理 Connection conn = null; Savepoint savepoint = null; try{ //0 获得连接 conn = ....; //1 开启事务 conn.setAutoCommit(false); A步骤 B步骤 // 设置一个保持点 savepoint = conn.setSavepoint(); C步骤 D步骤 //2 提交事务 conn.commit(); } catch(e){ if(savepoint == null){ //AB 其中之一存在异常,回滚AB选项 conn.rollback(); } else { //CD存在异常 // * 将CD进行回滚 conn.rollback(savepoint); //回滚到保存点之前,也就是AB之后 // * 提交AB conn.commit(); } } finally{ //释放资源
conn.close();}
4.3案例:转账 transfer,详见案例1,2.
5连接池 java.lang中类 ThreadLocal<T>, 详见案例3.