发布时间:2024-09-09 10:01
1.岗位需求
2.现在的世界,大数据时代,得数据库者得天下。
3.被迫需求: 存数据
4.数据库是所有软件体系中最核心的存在: DBA
数据库(DB,DataBase)
概念:数据仓库,软件 安装在操作系统上(windows,Linux,mac…) 可以存放大量的数据。
作用:存放数据,管理数据。
关系型数据库
非关系型数据库:(NoSQL) Not Only
DBMS(数据库管理系统)
安装
不要使用exe 文件,因为删不干净
尽可能使用压缩包文件
这里建议大家使用压缩版,安装快,方便.不复杂.
软件下载
mysql5.7 64位下载地址:
电脑是64位的就下载使用64位版本的!
安装步骤
1、下载后得到zip压缩包.
2、解压到自己想要安装到的目录,本人解压到的是D:\\Environment\\mysql-5.7.19
3、添加环境变量:我的电脑->属性->高级->环境变量
选择PATH,在其后面添加: 你的mysql 安装文件下面的bin文件夹
4、编辑 my.ini 文件 ,注意替换路径位置
[mysqld]
basedir=D:\\Program Files\\mysql-5.7\\
datadir=D:\\Program Files\\mysql-5.7\\data\\
port=3306
skip-grant-tables
5、启动管理员模式下的CMD,并将路径切换至mysql下的bin目录,然后输入mysqld –install (安装mysql)
6、再输入 mysqld --initialize-insecure --user=mysql 初始化数据文件
7、然后再次启动mysql 然后用命令 mysql –u root –p 进入mysql管理界面(密码可为空)
8、进入界面后更改root密码
update mysql.user set authentication_string=password(\'123456\') where user=\'root\'and Host = \'localhost\';
9、刷新权限
flush privileges;
10、修改 my.ini文件删除最后一句skip-grant-tables
11、重启mysql即可正常使用
net stop mysql
net start mysql
12、连接上测试出现以下结果就安装好了
无脑安装
mysql -uroot -p -- 连接数据库
update mysql.user set authentication_string=password(\'123456\') where user=\'root\'and Host = \'localhost\'; -- 修改密码
flush privileges; -- 刷新权限
-- 所有的语句(除切换语句外) 都使用;结尾
show databases; -- 查看所有的数据库
use userdb -- 切换数据库 use + 数据库名
show tables -- 查看数据库中所有的表
describe userdb -- 查看数据库中所有表的信息
DROP DATABASE IF EXISTS myschool -- 删除数据库
create database westos -- 创建一个数据库
exit -- 退出链接
-- 单行注释(SQL本来的注释)
/*
多行注释
*/
数据库 xxx 语言
DDL 定义
DML 操作
DQL 查询
DCL 控制
操作数据库 > 操作数据库中的表 > 操作数据库中表的数据
1.创建数据库
CREATE database if not EXISTS myschool
2.删除数据库
drop database [if EXISTS] myschool
3.使用数据库
use myschool
4.查询数据库
SHOW DATABASES
数值
字符串
时间日期
java.util.Date
null
Unsigned:
zerofill:
自增:
非空 NULL not null
拓展(听听就好)
/*每一个表,都必须存在以下五个字段!未来做项目用的,表示一个记录存意义
id 主键
`version` 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间
*/
-- 注意点,使用英文(),表的名称 和 字段 尽量使用 ``括起来
-- AUTO_INCREMENT 自增
-- 字符串使用,单引号括起来!
-- 所有的语句后面加,(英文的),最后一个不用加
-- PRIMARY KEY(`id`) 主键,一般一个表只有一个唯一的主键!
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT \'学号\',
`name` VARCHAR(20) NOT NULL DEFAULT \'匿名\' COMMENT \'姓名\',
`pwd` VARCHAR(20) NOT NULL DEFAULT \'123456\' COMMENT \'密码\',
`sex` VARCHAR(2) NOT NULL DEFAULT \'女\' COMMENT \'性别\',
`birthday` DATETIME DEFAULT NULL COMMENT \'出生日期\',
`address` VARCHAR(50) DEFAULT NULL COMMENT \'家庭住址\',
`email` VARCHAR(30) DEFAULT NULL COMMENT \'邮箱\',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
格式
CREATE TABLE [IF NOT EXISTS] `表名`(
`字段名` 列类型 [属性] [索引] [注释]
`字段名` 列类型 [属性] [索引] [注释]
......
`字段名` 列类型 [属性] [索引] [注释]
)[表类型] [字符集设置][注释]
常用命令
SHOW CREATE DATABASE `myschool` -- 查看数据库的创建语句
SHOW CREATE TABLE student -- 查看数据表的创建语句
DESC student -- 显示表的结构
-- 关于数据库引擎
/*
INNODB 默认使用
MYISAM 早些年使用的
*/
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间的大小 | 较小 | 较大,约为2倍 |
常规使用操作:
在物理空间存在的位置
所有的数据库文件都存在date目录下,一个文件夹就相当于一个数据库。
本地还是文件的存储!
MySQL 引擎在物理文件上的区别
设置数据库的字符集编码
CHARSET=utf8
不设置的话,会是mysql默认的字符集编码~ (不支持中文)
MySQL的默认编码是Latin1,不支持中文
在my.ini中配置默认的编码
character-set-server=utf8
修改表
-- 修改表的信息
-- 对表进行修改名字 ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE student RENAME AS student1
-- 添加字段名 ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE student1 ADD grade INT(6)
-- 修改字段 (修改字段名 和 约束)
-- 修改字段约束 ALTER TABLE 表名 MODIFY 字段名 列属性
ALTER TABLE student1 MODIFY grade VARCHAR(10)
-- 修改字段名称 ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性
ALTER TABLE student1 CHANGE grade grade1 INT(2)
-- 删除表中的字段名 ALTER TABLE 表名 DROP 字段名
ALTER TABLE student1 DROP grade1
删除表
DROP TABLE IF EXISTS teacher
创建和删除表尽量加上条件语句
注意点
方式一 : 在创建表的时候就进行外键连接。
CREATE TABLE `grade` (
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT \'年级编号\',
`gradename` VARCHAR(20) DEFAULT NULL COMMENT \'年级名称\',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 在创建表的时候就进行外键连接
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT \'学号\',
`name` VARCHAR(20) NOT NULL DEFAULT \'匿名\' COMMENT \'姓名\',
`pwd` VARCHAR(20) NOT NULL DEFAULT \'123456\' COMMENT \'密码\',
`sex` VARCHAR(2) NOT NULL DEFAULT \'女\' COMMENT \'性别\',
`birthday` DATETIME DEFAULT NULL COMMENT \'出生日期\',
`gradeid` INT(8) NOT NULL COMMENT \'年级编号\',
`address` VARCHAR(50) DEFAULT NULL COMMENT \'家庭住址\',
`email` VARCHAR(30) DEFAULT NULL COMMENT \'邮箱\',
PRIMARY KEY(`id`),
KEY `FK_gradeid`(`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
删除表的时候,如果该表含有外键;那么,该表不能进行删除。必须引用外键的表被删除后才能进行删除。
方式二:在创建表的时候就进行外键连接
CREATE TABLE `grade` (
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT \'年级编号\',
`gradename` VARCHAR(20) DEFAULT NULL COMMENT \'年级名称\',
PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 在创建表的时候就进行外键连接
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT \'学号\',
`name` VARCHAR(20) NOT NULL DEFAULT \'匿名\' COMMENT \'姓名\',
`pwd` VARCHAR(20) NOT NULL DEFAULT \'123456\' COMMENT \'密码\',
`sex` VARCHAR(2) NOT NULL DEFAULT \'女\' COMMENT \'性别\',
`birthday` DATETIME DEFAULT NULL COMMENT \'出生日期\',
`gradeid` INT(8) NOT NULL COMMENT \'年级编号\',
`address` VARCHAR(50) DEFAULT NULL COMMENT \'家庭住址\',
`email` VARCHAR(30) DEFAULT NULL COMMENT \'邮箱\',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 在表创建好的时候,进行外键的添加
ALTER TABLE student ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰,这里了解即可)
最佳实践
数据库的意义:用来存储数据,管理数据。
insert
update
delete
insert
-- 插入数据 INSERT INTO 表名 (`字段名1`,`字段名2`,`字段名3`) VALUES(`值1`),(\'值2\')....
-- 其他要么默认为NULL或自增主键
INSERT INTO grade (`gradename`) VALUES(\'大一\')
-- 如果前面没有相应的字段提示,那么字段与值之间必须一一对应
INSERT INTO grade VALUES (\'大二\') -- 此处相当于执行 INSERT INTO grade VALUES (\'大二\',null)不匹配
-- 插入多个数据
INSERT INTO grade (`gradename`) VALUES(\'大二\'),(\'大四\')
语法:INSERT INTO 表名 (
字段名1,
字段名2,
字段名3) VALUES(
值1),(\'值2\')....
注意事项:
修改 谁 (条件) set 原来的值=新值
-- 修改 谁 (条件) set 原来的值=新值
-- 修改简介
UPDATE `student` SET `name`=\'狂神\' WHERE id=1
-- 整列修改
UPDATE `student` SET `name`=\'长江七号\'
UPDATE `student` SET `email`=\'2398291@qq.com\' WHERE id = 1
-- 语法
-- UPDATE 表名 SET column_name=value,[column_name=value] WHERE column_name=特定的值
条件:where 子句 运算符 id等于某个值,大于某个值,小于某个值
返回的是 布尔值
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=6 | false |
<> 或 != | 不等于 | 5<>6 | true |
> | |||
< | |||
>= | |||
<= | |||
BETWEEN…AND… | [2,5] | ||
AND | 且 && | 5>1 AND 1<2 | false |
OR | 或 || | 5>1 OR 1<2 | true |
-- 通过多个条件定位数据
UPDATE student SET `sex`=\'女\' WHERE `name`=\'长江七号\' AND `pwd`=\'12345\'
语法: UPDATE 表名 SET column_name=value,[column_name=value] WHERE column_name=特定的值
注意:
column_name 是数据库中的列,需要加上``
条件: 如果没有筛选条件,就会修改所有的列
value,是一个具体的值,也可以是一个变量
多个设置的属性之间使用英文的逗号隔开
UPDATE student SET `birthday`=CURRENT_TIME WHERE `name`=\'长江七号\' AND `sex`=\'女\'
delete命令
语法: delete from 表名 [where 条件]
-- delete 删除数据 (删除表的全部数据) 不建议使用
DELETE FROM `student`
-- 删除指定的数据
DELETE FROM `student` WHERE `id`=1
TRUNCATE 命令
作用:完全清空数据库中表中的数据
-- 删除数据库表中的所有的数据
TRUNCATE `student`
delete 和 TRUNCATE 的区别
相同点: 都可以清空表中的数据 ,都不会表的结构和约束
不同点 :
了解即可:delete删除的问题
,重启数据库,现象
[Data Query Language 数据查询语言]
所有的查询操作都使用它 select
简单的以及复杂的查询都是使用它
数据库中最核心的语言,最重要的语句
使用频率最高的语句
顺序很重要
-- 查询学生信息表的所有字段
SELECT * FROM student
-- 查询学生信息表的指定字段
SELECT `studentno`,`studentname` FROM student
-- 起别名 AS 字段名 as 新名字 表名 as 新名字 别名只是在此语句中起作用,而实际上并未改变数据库中的字段名和表名
SELECT `studentno` AS 学号,`studentname` AS 学生姓名 FROM student AS s
-- 函数 concat
SELECT CONCAT(\'姓名:\',`studentname`) AS 新名字 FROM student
语法 :SELECT 字段,... FROM 表名
有的时候,列名字不是那么的见名知义。所以我们会对其起别名 AS 字段名 as 新名字
去重 :distinct 直接加在需要去重的字段名前,就能对其去重
-- 对查询出来的数据进行去重
SELECT DISTINCT `studentno` FROM `student`
数据库的列(表达式)
-- 查询数据库的版本(函数)
SELECT VERSION()
-- 对算术表达式进行计算(表达式)
SELECT 100*3 - 1 AS 计算结果
-- 显示查询步长(变量)
SELECT @@auto_increment_increment
SELECT `studentno`,`studentresult` + 1 AS 新成绩 FROM `result` -- 变量可以进行计算
数据库中的表达式:文本值,列,NULL,函数,计算表达式,系统变量…
select 表达式 from 表
作用:查询符合条件的值
运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a && b | 两个为真才为真 |
or || | a or b a ||b | 两个为假才为假 |
Not ! | not a !a | 取反 |
尽量使用英文
-- 查询学生成绩在 85~100之间的学生学号 和 学生成绩
SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult`>=85 AND `studentresult`<=100
SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult`>=85 && `studentresult`<=100
SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult` BETWEEN 85 AND 100
-- 查询学生成绩不等于60的学生学号 和 学生成绩
SELECT `studentno`,`studentresult` FROM result
WHERE `studentresult` != 68
SELECT `studentno`,`studentresult` FROM result
WHERE NOT `studentresult`=60
模糊查询:比较运算符
运算符 | 语法 | 描述 |
---|---|---|
is null | a is null | 如果a 为空则返回真 |
is not null | a is not null | 如果a 不为空则返回真 |
between | a between b and c | 如果a处于b和c之间则返回真 |
like | a like b | SQL匹配,如果a匹配b,则返回真 |
in | a in (a1,a2,a3…) | 假设a在a1,或者a2其中的某一个值中,则返回真。 |
like 结合 % (0 到任意个字符) _(一个字符)
SELECT * FROM student
-- 查询姓赵的同学信息
SELECT * FROM student
WHERE `studentname` LIKE \'赵%\'
-- 查询姓赵且名字个数为2的同学信息
SELECT * FROM student
WHERE `studentname` LIKE \'张_\'
-- 查询住址中包含朝字的同学信息
SELECT * FROM student
WHERE `address` LIKE \'%朝%\'
-- 查询学生学号是(1000,1001)这两个数中其中一个的学生的信息
SELECT * FROM student
WHERE `studentno` IN (1000,1001)
-- 查询出生日期 为NULL的学生信息
SELECT * FROM student
WHERE `borndate` IS NULL
-- 查询出生日期 不为NULL的学生信息
SELECT * FROM student
WHERE `borndate` IS NOT NULL
join 对比
思路:
- 分析需求,分析查询的字段来自哪些表(连接查询)
- 确定使用哪种连接查询 ?(7种)
确定交叉点(这两个表中哪个数据是相同的)
判断的条件:学生表的 studentNo = 成绩表 studentNo
-- ===========联表查询===========
-- 查询参加了考试的同学的 studentno studentname subjectno studentresult
/*
1. 分析需求,分析查询的字段来自哪些表(连接查询)
2. 确定使用哪种连接查询 ?(7种)
确定交叉点(这两个表中哪个数据是相同的)
判断的条件:学生表的 studentNo = 成绩表 studentNo
*/
-- INNER JOIN 实现的是 两个表之间的并集
SELECT s.studentno,studentname,subjectno,studentresult
FROM student s
INNER JOIN result r
ON s.studentno=r.studentno
-- LEFT JOIN 以左表为主 会返回左表的所有信息
SELECT s.studentno,studentname,subjectno,studentresult
FROM student s
LEFT JOIN result r
ON s.studentno=r.studentno
-- RIGHT JOIN 以右表为准,会返回右表的所有信息
SELECT s.studentno,studentname,subjectno,studentresult
FROM student s
RIGHT JOIN result r
ON s.studentno=r.studentno
-- join on 连接查询
-- where 等值查询
字段都是并集
操作 | 描述 |
---|---|
Inner join | 如果表中至少有一个匹配,就返回行(不会查出多余的字段和空字段,使用最为频繁) |
left join | 会从左表中返回所有的值,即使右表中没有匹配 |
right join | 会从右表中返回所有的值,即使左表中没有匹配 |
-- 查询参加了考试的所有学生的 studentno studentname subjectname studentresult
SELECT s.studentno,studentname,subjectname,studentresult
FROM result r
LEFT JOIN student s
ON r.studentno=s.studentno
INNER JOIN `subject` sub
ON r.subjectno=sub.subjectno -- subjectname 没有模棱两可的地方
-- 我要查询哪些数据 select...
-- 从哪几个表中 查 from 表 xxx join 连接的表 on 交叉条件
-- 假设 存在一种多张表的查询,慢慢来,先查询两张表然后再慢慢增加
-- from a left join b
-- from a right join b
自连接
核心就是:将自己这张表拆成一模一样的两张表进行操作
父类:
categoryid | categoryname |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类:
pid | categoryid | categoryname |
---|---|---|
3 | 4 | 数据库 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
2 | 8 | 办公信息 |
父类和子类的连接表
pcategoryname | categoryname |
---|---|
软件开发 | 数据库 |
软件开发 | web开发 |
美术技术 | ps 技术 |
信息技术 | 办公信息 |
-- 自连接
SELECT a.categoryname AS \'父栏目\',b.categoryname AS \'子栏目\'
FROM category a ,category b
WHERE a.categoryid=b.pid
-- where 等值查询
排序
-- 排序 升序asc 降序 desc
-- ORDER BY 字段名称 排序方式
SELECT * FROM result
ORDER BY studentresult DESC
分页
为什么需要分页?
缓解数据库压力,给人的体验更好,瀑布流
-- 分页
SELECT * FROM result
LIMIT 1,2
-- 语法: limit (起始值,页面大小)
-- [n : 总页数]
-- [(n - 1) * pagesize : 起始值]
-- [pagesize : 页面大小]
-- [总页数 = 总数 / pagesize]
语法:limit (起始值,页面大小)
where (这个值是计算出来的)
本质: 在where语句中嵌套一个子查询语句
where(select * from 表名)
-- 查询 分数不小于80 且 课程名称为 高等数学-1 的学生的 学号 和名字
-- 联表查询
SELECT s.`studentno`,`studentname`
FROM student s
INNER JOIN result r
ON s.`studentno`=r.`studentno`
INNER JOIN `subject` sub
ON r.`subjectno`=sub.`subjectno`
WHERE `studentresult`>80 AND `subjectname`=\'高等数学-1 \'
SELECT s.`studentno`,`studentname`
FROM student s
INNER JOIN result r
ON s.`studentno`=r.`studentno`
WHERE `studentresult`>80 AND `subjectno` = (
SELECT `subjectno` FROM SUBJECT
WHERE `subjectname`=\'高等数学-1 \'
)
-- 子查询 在改造(由里及外)
SELECT `studentno`,`studentname` FROM student WHERE `studentno` IN (
SELECT `studentno` FROM result WHERE `studentresult`>80 AND `subjectno` = (
SELECT `subjectno` FROM `subject` WHERE `subjectname`=\'高等数学-1 \'
)
)
-- ==========常用函数========
-- 数学运算
SELECT ABS(-8) -- 绝对值
SELECT CEILING(9.4) -- 向上取整
SELECT FLOOR(9.8)-- 向下取整
SELECT RAND() -- 0~1之间的随机数
SELECT SIGN(10) -- 判断一个数的符号 0-0 负数返回-1,正数返回1
-- 字符串函数
SELECT CHAR_LENGTH(\'狂神说努力就会成功\') -- 返回字符串长度
SELECT CONCAT(\'我\',\'爱\',\'你们\') -- 拼接字符串
SELECT INSERT(\'我爱编程helloworld\',1,2,\'超级热爱\') -- 从某个位置开始替换字符串
SELECT LOWER(\'KUANGSHEN\')
SELECT UPPER(\'kuangshen\') -- 转换大小写
SELECT INSTR(\'kaungshen\',\'sh\') -- 返回第一次出现的字串的索引
SELECT REPLACE(\'狂神说坚持就能成功\',\'坚持\',\'努力\') -- 替换出现的指定字符串
SELECT SUBSTR(\'狂神说坚持就能成功\',4,6) -- 截取指定的字符串 (源字符串截取的位置,截取的长度)
SELECT REVERSE(\'清晨我上马\') -- 反转字符串
-- 时间日期函数
SELECT CURRENT_DATE() -- 获取当前日期
SELECT CURDATE() -- 获取当前日期
SELECT NOW() -- 获取当前的时间
SELECT LOCALTIME() -- 本地时间
SELECT SYSDATE() -- 获去系统时间
SELECT YEAR(NOW())
SELECT MONTH(NOW())
SELECT DAY(NOW())
SELECT HOUR(NOW())
SELECT MINUTE(NOW())
SELECT SECOND(NOW())
-- 系统
SELECT SYSTEM_USER()
SELECT USER()
SELECT VERSION()
函数名称 | 描述 |
---|---|
COUNT() | 计数 |
SUM() | 求和 |
AVG() | 求平均值 |
MAX() | 求最大值 |
MIN() | 求最小值 |
-- =======聚合函数====
SELECT COUNT(subjectno) FROM result -- COUNT(指定字段) 会忽略null值
SELECT COUNT(*) FROM result -- COUNT(*) 不会忽略所有的null值 本质 : 计算行数
SELECT COUNT(1) FROM result -- COUNT(1) 不会忽略所有的null值 本质 : 计算行数
SELECT SUM(`studentresult`) FROM result
SELECT AVG(`studentresult`) FROM result
SELECT MAX(`studentresult`) FROM result
SELECT MIN(`studentresult`) FROM result
-- group by 字段 以什么字段分组
-- HAVING 等价于 where 但是 where时表示在分组之前 HAVING 是在分组之后
什么是MD5?
主要增强算法复杂度和不可逆性。
MD5不可逆,具体的值的md5是一样的
MD破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值
CREATE TABLE `test05`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(60) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
-- 明文密码
INSERT INTO `test05` VALUES(1,\'张三\',\'123456\'),
(2,\'李四\',\'123456\'),
(3,\'王五\',\'123456\')
DROP TABLE test05
-- 加密
UPDATE test05 SET pwd=MD5(pwd) WHERE id=1 -- 对指定的密码加密
UPDATE test05 SET pwd=MD5(pwd) -- 对全部的密码进行加密
-- 插入的时候进行 加密
INSERT INTO test05 VALUES(4,\'赵四\',MD5(\'567899\'))
-- 两次MD5加密后 密码就是相同了的
-- 如何校验 : 先将顾客输入的密码进行加密,然后 在进行比对
SELECT * FROM test05 WHERE `name`=\'张三\' AND pwd=MD5(\'123456\')
要么成功,要么失败。
将一个 SQL 放在一个批次去执行。
事务原则:ACID原则 原子性 一致性 持久性 隔离性 脏读 不可重复读 幻读
原子性
要么都成功,要么都失败。
一致性
事务前后的完整性要保证一致 比如转钱前后的钱总数一致
隔离性
事务的隔离性是多个用户并发的访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,事物之间要相互隔离。
持久性
事务一旦提交,那么就会被持久化到数据库。
脏读:
指一个事务读取了另外一个事务未提交的数据。
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
幻读:
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
执行事务
-- ======事务处理=======
-- mysql 是默认开启事务自动提交的
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启自动提交
-- 手动处理事务
SET autocommit = 0 -- 关闭自动提交
-- 事务开启
START TRANSACTION -- 标记一个事务的开始,从这个之后的sql都在一个事务中
INSERT xx
INSERT xx
-- 提交 : 持久化(成功!)
COMMIT
-- 回滚 : 回到原来的样子(失败!)
ROLLBACK
-- 事务结束
SET autocommit = 1 -- 开启自动提交
-- 了解
SAVEPOINT 保存点名 -- 保存点名 设置一个事务的保存点
ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名 -- 撤销保存点
模拟场景
-- =====模拟场景=========
CREATE DATABASE `shop` CHARACTER SET utf8 COLLATE utf8_general_ci
USE `shop`
CREATE TABLE `account`(
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
DROP TABLE `account`
INSERT INTO `account` (`name`,`money`)VALUES(\'A\',2000.00),(\'B\',10000.00)
SET autocommit = 0 -- 关闭自动提交
START TRANSACTION -- 开启事务
UPDATE `account` SET money = money - 500 WHERE `name` = \'A\' -- A 减 500
UPDATE `account` SET money = money + 500 WHERE `name` = \'B\' -- B 加 500
COMMIT -- 提交成功 提交到数据库 (被持久化了!)
ROLLBACK -- 回滚
SET autocommit = 1 -- 开启自动提交
MySQL官方对索引的定义为:索引是帮助MySQL高效获取数据的数据结构。
索引的本质:索引是数据结构。
在一个表中,主键索引唯一,而唯一索引可以为多个
-- =======索引====
SHOW INDEX FROM student -- 显示所有的索引信息
ALTER TABLE student ADD FULLTEXT INDEX `studentname`(`studentname`) -- 向表中添加索引
-- EXPLAIN查看sql语句的执行情况
-- EXPLAIN + 相应的sql语句
测试索引
-- P31 创建app_user表格
CREATE TABLE `app_user` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT \'\',
`eamil` VARCHAR(50) NOT NULL,
`phone` VARCHAR(20) DEFAULT \'\',
`gender` TINYINT(4) UNSIGNED DEFAULT \'0\',
`password` VARCHAR(100) NOT NULL DEFAULT \'\',
`age` TINYINT(4) DEFAULT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
-- 插入100万数据.
DELIMITER $$
-- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO `app_user`(`name`,`eamil`,`phone`,`gender`)VALUES(CONCAT(\'用户\',i),\'19224305@qq.com\',\'123456789\',FLOOR(RAND()*2));
SET i=i+1;
END WHILE;
RETURN i;
END;
SELECT mock_data() -- 执行此函数 生成一百万条数据
SELECT * FROM app_user WHERE `name`=\'用户99999\' -- 1.175 sec
EXPLAIN SELECT * FROM app_user WHERE `name`=\'用户99999\'
-- 2.创建索引的另一种方式 : create index 索引名 on 表名(字段名)
CREATE INDEX id_app_user ON app_user(`name`) -- 普通索引
SELECT * FROM app_user WHERE `name`=\'用户99999\' -- 0.035 sec
EXPLAIN SELECT * FROM app_user WHERE `name`=\'用户99999\'
在数据还是少量的时候,索引的用处不大,在大数据的情况下,索引能够加快查询速度。
索引的数据结构
Hash类型的索引
Btree:InnoDB默认的
参考博客:CodingLabs - MySQL索引背后的数据结构及算法原理
SQLyog可视化管理
SQL 命令
-- 创建用户CREATE USER 用户名 IDENTIFIED BY \'密码\'
CREATE USER kuangshen IDENTIFIED BY \'123456\'
-- 修改密码(修改当前用户密码)
SET PASSWORD = PASSWORD(\'123456\')
-- 修改密码(修改指定用户密码)
SET PASSWORD FOR kuangshen = PASSWORD(\'123456\')
-- 重命名 RENAME USER 原名字 TO 新名字
RENAME USER kuangshen TO kuangshen2
-- 用户授权ALL PRIVILEGES 全部的权限,库.表
-- ALL PRIVILEGES 除了给别人授权,其他都能干
GRANT ALL PRIVILEGES ON *.* TO kuangshen2
-- 查询权限
SHOW GRANTS FOR kuangshen2
SHOW GRANTS FOR root@localhost
-- root 用户权限:GRANT ALL PRIVILEGES ON *.* TO \'root\'@\'localhost\' WITH GRANT OPTION
-- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM kuangshen2
-- 删除用户
DROP USER kuangshen2
为什么要备份?
MySQL数据库备份的方式
#mysqldump -h 主机 -u 用户名 -p 密码 数据库名 表名 >导出位置
mysqldump -hlocalhost -uroot -p123456 myschool student >D:/a.sql
#mysqldump -h 主机 -u 用户名 -p 密码 数据库名 表1 表2 表3 >导出位置
mysqldump -hlocalhost -uroot -p123456 myschool student result >D:/b.sql
#mysqldump -h 主机 -u 用户名 -p 密码 数据库名 >导出位置
mysqldump -hlocalhost -uroot -p123456 myschool >D:/c.sql
#导入
#在登陆的情况下,切换到指定的数据库
#source 备份文件
source D:/a.sql
#没有登陆的情况下
mysql -u用户名 -p密码 库名<备份文件
当数据库比较复杂的时候,我们就需要设计
糟糕的数据库设计:
良好的数据库设计:
软件开发中,关于数据库的设计:
设计数据库的步骤:(个人博客)
为什么需要数据规范化?
三大范式(了解)
第一范式
要求数据库的每一列都是不可再分的原子项
第二范式
前提:满足第一范式
每一张表只描述一件事情
第三范式
前提:满足第一范式和第二范式
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。
(规范数据库的设计)
规范性和性能的问题
关联查询的表不能超过三张表
驱动:声卡,显卡,数据库
我们的程序会通过数据库驱动和数据库打交道。
sun公司为了简化开发人员的(对数据库的统一)操作,提供了一个(java操作数据库的)规范,俗称JDBC。
这些规范的实现有具体的产商去做。
对于开发人员来说,我们只需要掌握JDBC接口的操作即可!
java.sql
javax.sql
还需要导入一个一个数据库驱动包。mysql-connector-java-5.1.47
创建测试数据库
CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
USE jdbcStudy;
CREATE TABLE `users`(
id INT PRIMARY KEY,
NAME VARCHAR(40),
PASSWORD VARCHAR(40),
email VARCHAR(60),
birthday DATE
);
INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)
VALUES(3,\'zhansan\',\'123456\',\'zs@sina.com\',\'1980-12-04\'),
(2,\'lisi\',\'123456\',\'lisi@sina.com\',\'1981-12-04\'),
(3,\'wangwu\',\'123456\',\'wwu@sina.com\',\'1979-12-04\')
1.创建一个普通项目
2.导入数据库驱动
在项目目录下建一个lib目录,再导入jar包,然后右键操作。
3.编写测试代码
package study;
import java.sql.*;
public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//1.加载驱动
Class.forName(\"com.mysql.jdbc.Driver\");
//2.获得用户信息和密码
String url = \"jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true\";
String username=\"root\"; //第一次出错原因: 用户名错误。
String password = \"123456\";
// 3.连接数据库 connection 代表数据库
Connection connection = DriverManager.getConnection(url, username, password);
//4.获得执行sql语句的对象 statement 代表sql对象
Statement statement = connection.createStatement();
//5.执行sql语句获得结果集
String sql = \"SELECT * FROM users\";
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
System.out.println(\"id=\" + resultSet.getObject(\"id\"));
System.out.println(\"name=\" + resultSet.getObject(\"NAME\"));
System.out.println(\"password=\" + resultSet.getObject(\"PASSWORD\"));
System.out.println(\"email=\" + resultSet.getObject(\"email\"));
System.out.println(\"birth=\" + resultSet.getObject(\"birthday\"));
System.out.println(\"=====================\");
}
//6.释放连接
resultSet.close();
statement.close();
connection.close();
}
}
DriverManager
//1.加载驱动
//DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName(\"com.mysql.jdbc.Driver\"); // 固定写法,加载驱动
Connection connection = DriverManager.getConnection(url, username, password);
// connection 代表数据库
// 数据库提交
//数据库回滚
// 数据库自动提交
connection.commit();
connection.rollback();
connection.setAutoCommit();
URL
String url = \"jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true\";
// 协议://主机地址:端口号/数据库名?参数1&参数2&参数3
// Oralce -- 1521
// jdbc:oracle:thin:@localhost:1521:sid
statement 执行SQL的对象 connection.prepareStatement() statement.executeQuery();// 执行的是查询语句 statement.execute();// 可以执行任意的SQL语句 效率较低 statement.executeUpdate(); // 执行的是 更新,插入,删除
resultSet 是一个结果集,里面封装了全部的结果。
resultSet.getObject() // 不知道列类型的情况下使用
// 知道列类型的情况下 使用特定的
resultSet.getString()
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();
遍历:指针
resultSet.beforeFirst();// 移动到最前面
resultSet.afterLast();// 移动到最后面
resultSet.previous();// 移到前一行
resultSet.next(); // 移动到后面一行
resultSet.absolute(row); // 移动到指定行
释放资源
//6.释放连接
resultSet.close();
statement.close();
connection.close();//很耗资源
jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。
Statement对象的executeUpdate方法,用于向数据库发送增,删,改,查的SQL语句,executeUpdate执行完毕后,将会返回一个整数(即增删改查语句导致了数据库几行数据发生了改变)。
Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象。
CRUD操作-create
使用executeUpdate(String sql)方法完成数据添加操作,实例操作:
Statement st = connection.createStatement();
String sql = \"INSERT INTO 表名 (`字段名1`,`字段名2`,`字段名3`) VALUES(`值1`),(\'值2\').... \";
int num = st.executeUpdate(sql);
if(num > 0){
System.out.println(\"添加成功!\");
}
CRUD操作-delete
使用executeUpdate(String sql)方法完成数据删除操作,实例操作:
Statement st = connection.createStatement();
String sql = \"DELETE FROM `student` WHERE `id`=1 \";
int num = st.executeUpdate(sql);
if(num > 0){
System.out.println(\"删除成功!\");
}
CRUD操作-update
使用executeUpdate(String sql)方法完成数据更新操作,实例操作:
Statement st = connection.createStatement();
String sql = \"UPDATE 表名 SET column_name=value,[column_name=value] WHERE column_name=特定的值\";
int num = st.executeUpdate(sql);
if(num > 0){
System.out.println(\"删除成功!\");
}
CRUD操作-Query
使用executeQuery(String sql)方法完成数据查询操作,实例操作:
//4.获得执行sql语句的对象 statement 代表sql对象
Statement statement = connection.createStatement();
//5.执行sql语句获得结果集
String sql = \"SELECT * FROM users\";
ResultSet resultSet = statement.executeQuery(sql);
while(resultSet.next()){
System.out.println(\"id=\" + resultSet.getObject(\"id\"));
System.out.println(\"name=\" + resultSet.getObject(\"NAME\"));
System.out.println(\"password=\" + resultSet.getObject(\"PASSWORD\"));
System.out.println(\"email=\" + resultSet.getObject(\"email\"));
System.out.println(\"birth=\" + resultSet.getObject(\"birthday\"));
System.out.println(\"=====================\");
}
1.提取工具类
package study01;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JdbcUtils {
private static String driver = null;
private static String url = null;
private static String username = null;
private static String pwd = null;//字符串类型
static {
try {
InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream(\"db.properties\");//从相应的文件中获取输入流
Properties properties = new Properties();//获取资源
properties.load(in);//获取资源
driver = properties.getProperty(\"driver\");
url = properties.getProperty(\"url\");
username = properties.getProperty(\"username\");
pwd = properties.getProperty(\"password\");
Class.forName(driver);//驱动只需要加载一次
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,username,pwd);
}
//释放连接 参数是调用者进行传参
public static void release(Connection conn, Statement st, ResultSet rt){
if(rt != null){
try {
rt.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(st != null){
try {
st.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
package study;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class JdbcDemo02 {
public static void main(String[] args) {
Connection connection = null;
Statement st = null;
ResultSet rt = null;
try {
connection = JdbcUtils.getConnection();// 获取连接
st = connection.createStatement();//获取SQL对象
String sql = \"INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)\" +
\"VALUES(4,\'mazi\',\'456728\',\'zs@sina.com\',\'1989-11-14\')\";
int num = st.executeUpdate(sql);
if(num > 0){
System.out.println(\"插入成功!\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(connection,st,rt);//释放资源
}
}
}
package study;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestDelete {
public static void main(String[] args) {
Connection connection = null;
Statement st = null;
ResultSet rt = null;
try {
connection = JdbcUtils.getConnection();// 获取连接
st = connection.createStatement();//获取SQL对象
String sql = \"DELETE FROM users WHERE `id` = 4\";
int num = st.executeUpdate(sql);
if(num > 0){
System.out.println(\"删除成功!\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(connection,st,rt);//释放资源
}
}
}
package study;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestUpdate {
public static void main(String[] args) {
Connection connection = null;
Statement st = null;
ResultSet rt = null;
try {
connection = JdbcUtils.getConnection();// 获取连接
st = connection.createStatement();//获取SQL对象
String sql = \"UPDATE users SET `name` = \'kuangshen\' where `id` = 1\";
int num = st.executeUpdate(sql);
if(num > 0){
System.out.println(\"更新成功!\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(connection,st,rt);//释放资源
}
}
}
3.executeQuery 实现查询
package study;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestQuery {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rt = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = \"SELECT * FROM users\";
rt = st.executeQuery(sql);
while(rt.next()){
System.out.println(rt.getInt(\"id\"));
System.out.println(rt.getString(\"NAME\"));
System.out.println(rt.getString(\"PASSWORD\"));
System.out.println(rt.getString(\"email\"));
System.out.println(rt.getDate(\"birthday\"));
System.out.println(\"====================\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rt);
}
}
}
SQl注入问题
SQL存在漏洞,会导致数据泄露 本质就是or导致的
package study;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class Test03 {
public static void main(String[] args) {
//login(\"kuangshen\",\"123456\"); 登陆成功
login(\"\' or \'1=1\",\"\' or \'1=1\");//SQL注入导致
/*
kuangshen
123456
====================
zhangsan
123456
====================
lisi
123456
====================
*/
}
public static void login(String username,String pwd){
Connection conn = null;
Statement st = null;
ResultSet rt = null;
try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
//SELECT * FROM users WHERE `NAME` = \'kuangshen\' AND `PASSWORD` = \'123456\'
//SELECT * FROM users WHERE `NAME` = \'\' or \'1=1\' AND `PASSWORD` = \'\' or \'1=1\'
String sql = \"SELECT * FROM users WHERE `NAME` = \'\"+ username +\"\' AND `PASSWORD` = \'\"+ pwd +\"\'\";
rt = st.executeQuery(sql);
while(rt.next()){
System.out.println(rt.getString(\"NAME\"));
System.out.println(rt.getString(\"PASSWORD\"));
System.out.println(\"====================\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rt);
}
}
}
PreparedStatement可以防止SQL注入,效率更高。
1.增删改
package study02;
import study01.JdbcUtils;
import java.sql.Connection;
import java.util.Date;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test01 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();//获取连接
String sql = \"INSERT INTO `users`(id,NAME,PASSWORD,email,birthday)\" +
\"VALUES(?,?,?,?,?)\";//使用 ? 代表参数
st = conn.prepareStatement(sql);//参数需要一个预编译的SQL语句
st.setInt(1,4);
st.setString(2,\"狂生\");
st.setString(3,\"234516\");
st.setString(4,\"23457125@qq.com\");
st.setDate(5,new java.sql.Date(new Date().getTime()));//填入参数
int i = st.executeUpdate();//执行
if(i > 0){
System.out.println(\"插入成功\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,null);
}
}
}
package study02;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
public class Test02 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();//获取连接
String sql = \"delete from users where `id`=?\";//使用 ? 代表参数
st = conn.prepareStatement(sql);//参数需要一个预编译的SQL语句
st.setInt(1, 4);//填入参数
int i = st.executeUpdate();//执行
if (i > 0) {
System.out.println(\"删除成功\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(conn, st, null);
}
}
}
package study02;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test03 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();//获取连接
String sql = \"update users set `NAME`=? where `id`=?\";//使用 ? 代表参数
st = conn.prepareStatement(sql);//参数需要一个预编译的SQL语句
st.setString(1,\"狂生\");
st.setInt(2,1);//填入参数
int i = st.executeUpdate();//执行
if (i > 0) {
System.out.println(\"更新成功\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(conn, st, null);
}
}
}
2.查询
package study02;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Test04 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();
String sql = \"Select * from users where `id`=?\";
st = conn.prepareStatement(sql);
st.setInt(1,1);
rs = st.executeQuery();
while(rs.next()){
System.out.println(rs.getInt(\"id\"));
System.out.println(rs.getString(\"NAME\"));
System.out.println(rs.getString(\"PASSWORD\"));
System.out.println(rs.getString(\"email\"));
System.out.println(rs.getDate(\"birthday\"));
System.out.println(\"=====================\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
3.防止SQL注入
本质是 将输入的参数看作是字符
然后含有转义字符的,自动过滤。
package study02;
import study01.JdbcUtils;
import java.sql.*;
public class Test05 {
public static void main(String[] args) {
//login(\"lisi\",\"123456\"); //登陆成功
login(\"\' or \'1=1\",\"\' or \'1=1\");//SQL注入导致
}
public static void login(String username,String pwd){
Connection conn = null;
PreparedStatement st = null;
ResultSet rt = null;
try {
conn = JdbcUtils.getConnection();
//SELECT * FROM users WHERE `NAME` = \'kuangshen\' AND `PASSWORD` = \'123456\'
//SELECT * FROM users WHERE `NAME` = \'\' or \'1=1\' AND `PASSWORD` = \'\' or \'1=1\'
String sql = \"SELECT * FROM users WHERE `NAME` = ? AND `PASSWORD` = ?\";
st = conn.prepareStatement(sql);
st.setString(1,username);
st.setString(2,pwd);
rt = st.executeQuery();
while(rt.next()){
System.out.println(rt.getString(\"NAME\"));
System.out.println(rt.getString(\"PASSWORD\"));
System.out.println(\"====================\");
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rt);
}
}
}
连接数据库
连接成功后,选择数据库
双击数据库查看数据
更新数据
连接失败,查看原因
要么成功,要么失败。
将一个 SQL 放在一个批次去执行。
事务原则:ACID原则 原子性 一致性 持久性 隔离性 脏读 不可重复读 幻读
原子性
要么都成功,要么都失败。
一致性
事务前后的完整性要保证一致 比如转钱前后的钱总数一致
隔离性
事务的隔离性是多个用户并发的访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,事物之间要相互隔离。
持久性
事务一旦提交,那么就会被持久化到数据库。
脏读:
指一个事务读取了另外一个事务未提交的数据。
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
幻读:
是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
代码实现
1.关闭自动提交 ,并自动开启事务。conn.setAutoCommit(false);
2.提交数据至数据库 conn.commit();
3.如果失败则回滚 conn.rollback();
package study;
import study01.JdbcUtils;
import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransaction {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();//连接数据库
conn.setAutoCommit(false);// 关闭自动提交 ,并开启事务
st = conn.createStatement();
String sql1 = \"update account set `money` = `money` - 100 where `NAME`=\'A\'\";
st.executeUpdate(sql1);
String sql2 = \"update account set `money` = `money` + 100 where `NAME`=\'B\'\";
st.executeUpdate(sql2);
conn.commit();// 提交数据至数据库
System.out.println(\"成功\");
} catch (SQLException throwables) {
try {//如果失败,则进行回滚
conn.rollback();
} catch (SQLException e) {
e.printStackTrace();
}
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}
}
}
数据库连接 — 执行完毕 — 释放
连接 – 释放 十分浪费资源
池化技术:准备一些预先的资源,过来就连接预先准备好的。
------- 开门–业务员 : 等待 – 服务 —
常用连接数 10个
最小连接数 : 10
最大连接数 :15 业务最高承载上限
排队等待
等待超时:100ms
编写连接池,实现一个接口 DataSource
开源数据源实现
DBCP
C3P0
Druid : 阿里巴巴
使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库代码。
DBCP
需要用到的jar包
commons-dbcp-1.4 commons-pool-1.6
C3P0
需要用到的jar包
c3p0-0.9.5.5 mchange-commons-java-0.2.19
结论
无论使用什么数据源,本质还是一样的,DataSource接口不变,方法就不会变。