mysql
1、初始MySQL
javaEE:企业级java开放 Web
前端(页面:展示,数据!)
后台(练级点:连接数据库JBDC,链接前端(控制,控制视图跳转,给前端传递数据))
数据库(存数据,Txt,Excel,word)
只会代码,学号数据库--->混饭吃
操作系统,数据结构与算法--->不错的程序猿
离散数学,数字电路,体系结构,编译原理 + 实战经验---->高级的程序员
1.1、什么是数据库
数据库(DB database)
概念:数据仓库,软件,安装在操作系统(window,linux,mac、、、、)之上 SQL 可以存储数据
作用:存储数据,管理数据
1.2、数据库分类
关系型数据库
- MySQL,Oralce,Sql Server,DB2 SQLlite
- 通过表和表之间,行和列之间的关系进行数据的存储
非关系数据库
- Redis ,MongDB
- 非关系型数据库,对象存储,通过对象的自身属性来决定
DBMS(数据库管理系统)
- 数据库的管理软件,科学有效的管理数据,维护和获取数据
- MySQL,数据库管理系统
2、操作数据库
2.1操作数据库
1、创建数据库
CREATE DATABASE [IF NOT EXISTS] westos;
2、删除数据库
drop database [if exists] westos;
3、使用数据库
-- sql语句的注释符 tab键的上面,如果你的表名或者字段是一个特殊字数就需要使用
4、查看数据库
SHOW DATABASES --查看所有的数据库
2.2、数据库的列类型
数组
- tinint 十分小的数据 1个字节
- smallin 较小的数据 2个字节
- mediumint 中等大小的数据 3个字节
- int 标注的整数 4个字节 常用的
- bigint 较大的数据 8个字节
- float 单精度浮点数 4个字节
- double 双精度浮点数 8个字节
- decimal 字符串形式的浮点数 金融计算的时候,一般是使用decimal
字符串
- char 字符串固定大小的 0~255
- varchar 可变字符串 0~65525 常用的 相当于String
- tinytext 微型文本 2^8—1
- text 文本串 2^16—1 保存大文本
时间日期
- date YYY-MMM-DD 日期格式
- time HH:mm:ss 时间格式
- datatime YYY-MMM-DD HH:mm:ss 最常用的时间格式
- timestamp 时间戳 1970.1.1 到现在的毫秒级
- year 年份表示
null
- 没有值,未知
- 不要使用null进行运算,结果为null
2.3 数据库的字段属性
Unsigned:
- 无符号的整数
- 不能声明为负数
zerofill:
- 0填充的
- 不足的数,使用0来填充,
自增:
- 通常理解为自增,自动在上一条记录的基础上+1(默认)
- 通常用来设计唯一的主键,
- 可以自定义设计起始值和步长
非空:not null
- 假设设置为 not null ,如果不给它复制,就会报错
- null 如果不填写值,默认就是null
默认:
- 设置默认的值
- 设定后不填写,就为设置的值
扩展:
每一个表,都需要以下五个字段
id 主键
`versiion` 乐观锁
is_delate 伪删除
gmt_create 创建时间
gmt_update 修改时间
创建表
CREATE TABLE [IF NOT EXISTS] `表名`(
·字段名· 列类型 [属性] [索引] [注释],
·字段名· 列类型 [属性] [索引] [注释],
·字段名· 列类型 [属性] [索引] [注释],
....
·字段名· 列类型 [属性] [索引] [注释]
PRIMARY KEY(`自增列`)
)[表类型] [字符集设置] [注释]
常用命令
SHOW CREATE DATABASE school --查看创建数据库语句
SHOW CREATE TABLE `student` --查看创建表语句
DESC student --显示表的结构
2.4 数据表的类型
INNODB 默认使用
MYISAM 以前使用
| MYSIAM | INNODB | |
|---|---|---|
| 事务支持 | 不支持 | 支持 |
| 数据行锁定 | 不支持 | 支持 |
| 外键约束 | 不支持 | 支持 |
| 全文索引 | 支持 | 不支持 |
| 表空间大小 | 较小 | 较大 约为前者两倍 |
常规使用操作:
- MYISAM 节约空间,速度较快
- INNODB 安全性高,适合事务的处理,夺标多用户操作
所有的数据库文件都存储在data文件下
本质还是文件的存储
MySQL 引擎在物理文件上的区别
- innoDB 在数据库表中只有一个*.frm文件,以及上级目录下的 ibdata1 文件
- MYISAM
- *.frm-----表结构的定义文件
- *.MYD------数据文件(data)
- *.MYI -------索引文件(index)
2.5、修改删除表
修改
--修改表名: ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE teacher RENAME AS student
--增加表的字段:ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE student ADD age INT(11)
--修改表的字段(重命名,修改约束)
--ALTER TABLE 表名 MODIFY 列名 (修改后的)列属性[]
ALTER TABLE student MODIFY AGE varchar(11) ---修改约束--->属性
--ALTER TABLE 表名 CHANGE 旧列名 新列名 (可以是新)列属性[]
ALTER TABLE student CHANGE age age1 INT(11)
--删除表的字段;ALTER TABLE 表名 DROP 列名
ALTER TABLE student DROP age1
总结:
- change :可以修改 列名 和 列的属性 但是无论列名是否修改 都需要两个列名(前后可以相同)
- modify:只能更改列的属性 但是只需要一次列名
删除
--删除表(如果表存在)
DROP TABLE IF EXISTS student
所有的创建和删除最好都加上判断语句
3、MySQL数据管理
3.1、外键
方式一:在创建表的时候,增加约束(麻烦,比较复杂)
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(40) NOT NULL DEFAULT '123456' COMMENT'密码',
`sex` VARCHAR(2) NOT NULL DEFAULT'女' COMMENT '性别',
`birthday` DATETIME NOT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT'学生的年纪',
`address` VARCHAR(30) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`) ,
KEY `FK_gradeid`(`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
--学生表的gradeid列,要区引用年级表的gradeid
--定义外键key
--给这个外键增加约束(执行引用) reference 引用
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT'年级id',
`gradename` VARCHAR(40) NOT NULL COMMENT'年级名称',
PRIMARY KEY (`gradeid`)
)ENGINE = INNODB DEFAULT CHARSET=utf8
删除有外键关系表的时候,必须要先删除引用别人的表(主动引用方,如上面的student-->引用 grade) 再删除被引用的表
方式二:
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(40) NOT NULL DEFAULT '123456' COMMENT'密码',
`sex` VARCHAR(2) NOT NULL DEFAULT'女' COMMENT '性别',
`birthday` DATETIME NOT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT'学生的年纪',
`address` VARCHAR(30) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT'年级id',
`gradename` VARCHAR(40) NOT NULL COMMENT'年级名称',
PRIMARY KEY (`gradeid`)
)ENGINE = INNODB DEFAULT CHARSET=utf8
--创建表的时候没有外键关系
ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid` FOREIGN
--公式:ALTER TABLE 主表 ADD CONSTRAINT 约束名 FOREIGN KEY 作为外键的列) REFERENCES 从表 (列名)
以上的外键都是物理外键--->数据库级别的外键,不建议使用(避免数据库过多造成困扰)
-
数据库就是单纯的表,只用来存数据,只有行(数据)和列(类名)
-
通过外键可以使用多张表的数据,就是引用
3.2、DML语言
数据库意义:数据存储,数据管理
DML语言:数据操作语言
-
insert(插入)
-
update(添加)
-
delete(删除)
3.3、添加
--插入语句(添加)
--INSERT INTO 表名 (`列名1`,`列名2`,`列名3`) VALUES ('数据1'),('数据2'),('数据3')...
INSERT INTO `grade`(`gradename`) VALUES('大三')
--由于主键自增可以省略(如果不写列名,就会一一匹配)
--插入多个数据
INSERT INTO `grade`(`gradename`)
VALUES ('大二'),('大一')
INSERT INTO `student` (`name`) VALUES ('张三')
INSERT INTO `student` (`name`,`pwd`,`sex`) VALUES ('张三','aaa','男')
INSERT INTO `student`
VALUES (3,'niubi','123a','男','2020-01-19',1,'西安','emall')
语法:INSERT INTO 表名 (列名1,列名2,列名3) VALUES ('数据1'),('数据2'),('数据3')...
注意事项:
-
列名和列名直接用英文逗号隔开
-
列名是可以省略的,但是后面的值必须要一一对应,不能缺少
-
可以同时插入多条数据,VALUES后面的值,需要使用英文逗号隔开
3.4、修改
update 修改对象(条件) set 原来的数据 = 新的数据
---修改学员的名字 带了条件 修改指定条件下的值
UPDATE `student` SET `name` = '李四' WHERE id = 2
--不指定条件,会修改所有数据
UPDATE `student` SET `name` = '长江七号'
--修改多个属性,用逗号隔开列名
UPDATE `student` SET `name` = 'lobort' ,`email` = '2445890216@qq.com' WHERE id =1
UPDATE `student` SET `birthday` = CURRENT_TIME WHERE id = 2;
条件:where 语句
| 操作符 | 含义 | 事例 | 结果 |
|---|---|---|---|
| = | 等于 | 5 =6 | false |
| <>或 != | 不等于 | 5<>6 | true |
| > | |||
| < | |||
| <= | |||
| >= | |||
| betweem...and... | 再某个闭区间 | betweem 3 and 5 | |
| and | 并且 && 同真才真 | ||
| or | 或者 || 同假才假 |
语法:UPDATE 表名 SET 列名 = VALUES(新的数据) WHERE 条件
注意:
- 列名最好带上``,不然可能会出现关键字
- 筛选的条件,如果没有指定,则会修改所有的数据
- value,可以是一个具体的值,也可以是一个变量(大多数指时间--->CURRENT_TIME)
3.5、删除
delete 命令
--删除所有数据
DELETE FROM student
--删除指定数据
DELETE FROM student WHERE id = 3
TRUNCATE 命令
作用:完全清空数据库,表的结构和约束不会变
--清空grade表
TRUNCATE grade
delete 和 truncate 的区别
- 相同点:都能删除数据,不会删除表的结构
- 不同点
- TRUNCATE 重新设置自增列---->计数器会归零
- TRUNCATE 不会影响事务
--删除数据
DELETE FROM student WHERE id = 3
--情况grade表
TRUNCATE grade
--测试delete 和 truncate区别
CREATE TABLE `test`(
`id` INT(4) NOT NULL AUTO_INCREMENT,
`coll` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET = utf8
INSERT INTO test(`coll`) VALUES (1),(2),(3)
DELETE FROM test --不会影响自增
TRUNCATE test --自增会归零
DELETE删除的问题,重启数据库:
- innoDB:自增列胡重1开始(存在内存当中的,断电即失)
- MyISAM:继续重上一个自增量开始(存在文件中的,不会丢
4、DQL查询数据
4.1、DQL
(Data Query Language:数据查询语言)
- 所有的查询操作 Select
- 简单的查询,复杂的查询都可以
- 数据库中最核心的语言
- 使用频率最高的语言
4.3、查询指定数据
--查询学生信息
SELECT * FROM student
--查询指定 列 的数据
SELECT `studentname`,`studentno` FROM `student`
--修改列的名字 AS:可以修改列名,也可以给查询结果命名
SELECT `studentname` AS 学号,`studentno` AS 学生姓名 FROM `student` AS 26班
--函数 CONCAT(a,b)
SELECT CONCAT('姓名:',`studentname`) AS 新名字 FROM student
语法:SELECT 列名 FROM 表
可以给查询的列名和表名修改名字,AS关键字
去重 distinct
作用:去除查询结果中重复的数据,只显示一条
--查询参加考试的同学
SELECT `studentno` FROM result
--去除重复数据
SELECT DISTINCT `studentno` FROM result
数据库的列
SELECT VERSION() --查询数据库版本
SELECT 9*777+2 AS 计算结果 --计算数学表达式
SELECT @@auto_increment_increment --查询自增变量步长
--所有学员考试成绩 + 1
SELECT `studentno`,`studentresult` + 1 AS '提分后' FROM result
数据库中的表达式:文本的值,列,null,函数,计算表达式,系统变量、、、
group by ---指定结果按照那几个字段来分组
having----过滤分组的记录必须满足的次要条件
4.3、where 条件语句
作用:检索数据中符合条件的值
搜索的条件由一个或多个表达式组成
逻辑运算符
| 运算符 | 语法 | 描述 |
|---|---|---|
| and && | a and b a && b | 与:同真为真,一假就假 |
| or || | a or b a ||b | 或:一真就真,同假才假 |
| not ! | not a !a | 非:真假互换 |
模糊查询:比较运算符
| 运算符 | 语法 | 描述 |
|---|---|---|
| is null | a is null | 如果操作符为null,结果为真 |
| is not null | a is not null | 如果操作符不为null,结果为真 |
| 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、a3之中的一个,结果为真 |
其中 %代表0到任意个字符,__代表一个字符,仅配合like使用
--模糊查询(区间)
SELECT `studentno`,`studentresult` FROM result
WHERE studentno = 101
--查询姓张的同学
--like结合
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '张%'
--查询姓张的同学中,后面只有一个字的
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '赵_'
--查询名字之间有伟的
SELECT `studentno`,`studentname` FROM `student`
WHERE studentname LIKE '%伟%'
--=========IN=====
--查询1001,1002,1003号学员
SELECT `studentno`,`studentname` FROM `student`
WHERE studentno IN (1001,1002,1003)
4.3 select完整的语法:
select 去重(distinct) 要查询的列 from(注意:表和列 都可以另外取名)
as xxx(别名) join 要连接的表 on 等值判断
where(具体的值,子查询语句)
group by (通过那个列来分组)
having (过滤分组后的信息,条件和where一样的,只是位置不同)
order by (通过那个字段排序)[升序/降序]
limit start index pagesize
4.4、联表查询
Join
| 操作 | 描述 |
|---|---|
| Inner join | 如果表中至少有一个匹配,就返回行 |
| left join | 即使右表中没有匹配,也会返回左表中所有的值 |
| right join | 即使左表中没有匹配,也会返回游标中所有的值 |
where 和 on 的区别
- on和where都表示筛选条件,on先执行,where是在on筛选过后生成的临时表中继续筛选
自链接
父类
| categoryid | categoryName |
|---|---|
| 2 | 信息技术 |
| 3 | 软件开发 |
| 5 | 美术设计 |
子类
| pid | categoryid | categoryname |
|---|---|---|
| 3 | 4 | 数据库 |
| 2 | 8 | 办公信息 |
| 3 | 6 | web开发 |
| 5 | 7 | ps技术 |
--查询父子信息
SELECT a.`categoryname` AS '父类',b.`categoryname` AS '子类'
FROM `category` AS a,`category` AS b
WHERE a.`categoryid` = b.`pid`
4.5、分页和排序
排序
语法:ORDER BY 列名 ASC(升序) / DESC(降序)
分页
语法:LIMIT 从第几条数据显示 每页显示多少条数据
例子:LIMIT 5,10 -----> 从查出来的数据中第五条开始显示,每页显示10条数据
5、MySQL函数
5.1 数据库级别的MD5加密
什么是MD5?
主要增强算法复杂度和不可逆性
MD5不可逆,具体值的MD5是一样的
MD5破解网站的原理,背后有一个数据库有常用的数据加密后的值!
CREATE TABLE `testmd5`(
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
)ENGINE =INNODB DEFAULT CHARSET= utf8
INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456')
DROP TABLE `testmd5`
--加密
UPDATE testmd5 SET pwd = MD5(pwd) WHERE id =1
UPDATE testmd5 SET pwd = MD5(pwd) --加密全部
--插入的时候加密
INSERT INTO testmd5 VALUE(4,'xiaoming',MD5('123456'))
--如何校验:将用户传递进来的密码,进行md5加密,然后对比加密后的值
SELECT * FROM testmd5 WHERE `name` = 'xiaoming' AND pwd = MD5('123456')
6、事务transaction(ACID原则)
6.1、什么是事务
要么都成功,要么都失败
事务原则:ACID---原子性、一致性、隔离性、持久性
原子性
要么都成功,要么都失败(一个事务必须完全执行才算成功)
一致性
事务前后的数据完整性要保持一致
持久性
事务一旦提交则不可逆,被持久化到数据库中,不可以再修改这件事务
隔离性
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,各个事务之间要相互隔离。
事务隔离产生的问题
-
脏读:一个事务读取另一个未提交的数据。
-
不可重复读:一个事务范围内两个相同的查询却返回了不同数据。
-
幻读:一个事务范围内两个相同的查询却返回了不同数据。对应的是插入操作。
=======事务=====
--mysql事务是默认开启的
SET automommit = 0 --关闭自动提交
SET automommit = 1 --开启自动提交
--手动处理事务
SET autocommit = 0 -- 关闭自动提交
INSERT xx
INSERT xx
--提交成功-->持久化
COMMIT
--提交失败-->回滚
ROLLBACK
--事务结束
SET autocommit = 1 ---开启自动提交
---扩展
SAVEPOINT xx --->设置一个临时保存点
ROLLBACK TO SAVEPOINT xx --->回滚到xx临时保存点
RELEASE SAVEPOINT xx ---->撤销xx临时保存点
转账事务模拟
--转账
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
USE shop
`account`
CREATE TABLE`account` (
`id` INT(3) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(30) NOT NULL,
`money` DECIMAL(9,2) NOT NULL,
PRIMARY KEY(`id`)
)ENGINE = INNODB DEFAULT CHARSET = utf8
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'
UPDATE account SET money = money+500 WHERE `name` = 'B'
COMMIT; ----提交
ROLLBACK ; ----回滚
SET autocommit = 1;
7、索引
索引(Index)是帮助MySQL高效获取数据的数据结构。提取句子主干,就可以得到索引的本质:索引是数据结构
7.1、索引的分类
-
主键索引
- 唯一的标识,主键不可重复,智能又一个列作为主键
-
唯一索引
- 避免查询的列出现相同的数据,唯一索引可以重复,多个列都有可以标识为唯一索引
-
常规索引
- 默认的,index key 关键字来设置
-
全文索引
- 再特定的数据库引擎下才有,mylsam
- 快速定位数据
7.2、 索引原则
- 索引不是越多越好
- 不要对进程变动数据加索引
- 小数据两的表不需要加索引
- 索引一般加在常用来查询的字段上
索引的数据类型
hash类型的索引
Btree:innodb的默认数据结构
8、权限管理和备份
8.1、用户管理
--创建用户
CREATE USER `lobort` IDENTIFIED BY '123456'
--删除用户
DROP USER lobort
--修改密码 当前
SET PASSWORD = PASSWORD('123456')
--修改指定用户的密码
SET PASSWORD FOR wdd = PASSWORD('123456')
--重命名
RENAME USER lobort1 TO wdd
--用户授权 --all privilegs 全部权限
GRANT ALL PRIVILEGES ON *.* TO wdd
--查询权限
SHOW GRANTS FOR wdd --GRANT ALL PRIVILEGES ON *.* TO 'wdd'@'%' 没有 授权 权限
SHOW GRANTS FOR root@localhost --GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
--撤销权限 REVOKE 哪些权限 在那个库撤销 给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM wdd
8.2、数据库备份
为什么要被封?
- 保证重要数据不丢失
- 进行数据转移
mysql数据库备份方式
-
直接拷贝物理文件
-
在sqlyog可视化工具中手动导出
- 直接选中右键即可备份导出
-
使用cmd命令行导出 mysqldump 命令
#mysqldump -h 主机 -u 用户名 -p 密码 数据库 表名 >物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql #mysqldump -h 主机 -u 用户名 -p 密码 数据库 表名 >物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -p123456 school student grade >D:/a.sql #导入 #登录的情况下,切换到指定的数据库 mysql -uroot -p123456 #source 要导入的文件 source d:/a.sql
9、规范数据库设计
9.1、为什么需要规范设计
当数据库比较复杂的时候,我们就需要设计
糟糕的数据库设计:
- 数据冗余,浪费时间
- 数据库插入和删除都会麻烦,还会导致异常【屏蔽物理外键的使用】
- 程序的性能差
良好的数据库设计
- 节省内存空间
- 保证数据库的完整性
- 方便开发系统
软件开发中,关于的数据库的设计
- 分析需求:分析业务和需要处理数据的需求
- 概要设计:分析各个数据之间的关系图 E-R图
设计数据库的步骤:(个人博客)
- 收集信息,分析需求
- 用户表(用户登录注销,用户的个人信息)
- 分类表(文章分类,谁创建的)
- 文章表(文章的具体内容)
- 自定义表
- 评论表
- 友链表
- 说说表
- 标识实体
- 标识实体之间的关系
- 写博客:user--->blog
- 创建分类:user--->category
- 关注:user--->user
- 友链:links
- 评论:user--->user---->blog
9.2、三大范式
为什么需要数据规范化?
- 信息重复
- 更新异常
- 插入异常
- 无法正常显示信息
- 删除异常
- 丢失有效信息
三大范式
第一范式(1NF)
原子性:保证每一列不可再分
第二范式(2NF)
前提:必须满足第一范式
每张表只描述一个事情(后面的列必须和主键有关系且不能只与一部分主键有关)
第三范式(3NF)
前提:必须满足一二范式
第三范式需要确保数据表中的每一列都和主键直接相关,不能间接相关
规范性和性能的问题
关联查询的表不得超过三张表
- 考虑商业化的需求和目标(成本,用户体验) 数据库的性能更加重要
- 在规范型嫩固定问题的时候,需要适当的考虑规范性
- 故意给某些表增加一些冗余的字段(从夺标查询中变为单表查询)
- 故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
10、JDBC(重点)
10.1、数据库驱动
驱动:

程序会通过 数据库 驱动,和数据连接
10.2、JDBC
sun公司为了简化开发人的操作,提供了一个java操作数据库的规范 简称为JDBC
规范的实现由具体的厂商去做
对于开发人员,只需要掌握JDBC接口的操作

10.3、第一个JDBC数据库
创建测试数据库
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(1,'zhangsan','123456','zs@sina.com','1980-12-04'),
(2,'lisi','123456','lisi@sina.com','1981-12-04'),
(3,'wangwu','123456','wangwu@sina.com','1979-12-04')
1、创建项目
2、导入数据库驱动
- 项目新建lib文件夹,将数据库驱动复制过来,点击as a library
3、编写测试程序
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1、加载驱动
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//2、用户信息和url
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String usename = "root";
String password= "123456";
//3、连接成功,数据库对象
Connection connection = DriverManager.getConnection(url,usename,password);
//4、执行sql对象
Statement statement = connection.createStatement();
//5、执行sql的对象去执行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("pwd="+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();
}
步骤总计:
1、加载驱动
2、连接数据库DriverManager
3、获得执行sql的对象 statemant
4、获得返回的结果集
5、释放连接
DriverManger
Class.forName("com.mysql.jdbc.Driver");//固定写法,加载驱动
//connevttion 代表数据
//数据库自动提交 connection.setautocommit
//事务提交 connection.commit();
//事务回滚 connection.rollback();
URL
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
//mysql默认端口号--3306
//jbdc:mysql://主机地址:端口号/数据库名?条件1&条件2&
10.4、statement对象
jbdc中的statement对象用于向数据库发送SQL语句,也可以这个对象完成对数据库的增删改查
statement对象的executeupdate方法,用于向数据库发送增、删、改的sql语句,execute update执行完以后,会返回一个整数
statement.executequery方法用于向数据库发送查询语句,executequery方法返回代表查询结果的resultset对象
CRUD操作-create
使用executeupdate(string sql)方法完成数据添加操作,示例操作:
Statement statement = connection.createStatement();
String sql = "insert into user(...) values(...)";
int num = statement.executeUpdate(sql);
if(num>0){
System.out.println("插入成功");
}
增删改的操作一样 使用executeupdate
CRUD-red
使用executeUpdate(String sql)方法完成数据查询操作,示例操作:
Statement statement = connection.createStatement();
String sql = "select * from user where id =1";
ResultSet rs= statement.executeQuery(sql);
if(rs.next()){
System.out.println("");
}
代码实现
1、提取工具类
package com.lobort.lesson02.utils;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
public class JbdcUtils {
private static String driver = null;
private static String url = null;
private static String usename = null;
private static String password = null;
static {
try {
InputStream in = JbdcUtils.class.getClassLoader().getResourceAsStream("resoursces/db.properties");
Properties properties = new Properties();
properties.load(in);
driver = properties.getProperty("driver");
url = properties.getProperty("url");
usename = properties.getProperty("usename");
password = properties.getProperty("password");
//1、驱动只用加载一次
Class.forName(driver);
} catch (Exception e) {
e.printStackTrace();
}
}
//获取连接
public static Connection getConnnection() throws SQLException {
return DriverManager.getConnection(url,usename,password);
}
//释放连接
public static void release(Connection conn, Statement st, ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(st!=null){
try {
st.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
2、编写增删改的方法 executeupdate
package com.lobort.lesson02;
import com.lobort.lesson02.utils.JbdcUtils;
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 conn = null;
Statement st = null;
ResultSet rs = null;
try {
conn = JbdcUtils.getConnnection();
st = conn.createStatement();
String sql = "UPDATE users SET `NAME`='luo',`PASSWORD`='12334535',`email`='jahd83t7@qq.com' WHERE id=1";
int i = st.executeUpdate(sql);
if(i>0){
System.out.println("更新成功!");
}
}catch (SQLException e){
e.printStackTrace();
}finally {
JbdcUtils.release(conn,st,rs);
}
}
}
3、查询
package com.lobort.lesson02;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
Statement st = null;
ResultSet rs= null;
try {
conn = JbdcUtils.getConnnection();
st = conn.createStatement();
//sql语句
String sql = "select * from users where id = 1 ";
rs = st.executeQuery(sql); //查询会返回一个结果集
while(rs.next()){
System.out.println(rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JbdcUtils.release(conn,st,rs);
}
}
}
总结
- 建立连接
- 生成对象
SQL注入
package com.lobort.lesson02;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.*;
public class SqlInsert {
public static void main(String[] args) {
login("' or' 1=1","' or '1=1");
}
//登录业务
public static void login (String name,String password){
Connection conn = null;
Statement st = null;
ResultSet rs= null;
try {
conn = JbdcUtils.getConnnection();
st = conn.createStatement();
//sql语句
//SELECT * FROM users WHERE `NAME` = 'luo' AND `PASSWORD` = '123456'
//String sql = "select * from users where `NAME` = '' or '1=1' and `password`= '"+password+"' ";
String sql = "select * from users where `NAME` = '"+name+"' and `password`= '"+password+"' ";
rs = st.executeQuery(sql); //查询会返回一个结果集
while(rs.next()){
System.out.println(rs.getString("NAME"));
System.out.println(rs.getString("password"));
System.out.println("=======");
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
JbdcUtils.release(conn,st,rs);
}
}
}
万能钥匙: ‘ or 1=1 ’
10.5 、PreparedStatement对象
防止sql注入,效率更高
增加
package com.lobort.lesson03;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestInsert {
public static void main(String[] args) {
Connection coon = null;
PreparedStatement st = null;
try {
coon = JbdcUtils.getConnnection();
//区别:使用?占位 ?代替输入的数据
String sql = "insert into users (id,`NAME`,`PASSWORD`,`email`,`birthday`) values (?,?,?,?,?)";
st = coon.prepareStatement(sql);
//手动赋值
st.setInt(1,6);
st.setString(2,"luo");
st.setString(3,"123456");
st.setString(4,"2445890216@qq.com");
//注意:sql.date 数据库 java.sql.date()
// util.date java new date().gettime() 获得时间
st.setDate(5,new java.sql.Date(System.currentTimeMillis()));
//执行
int i = st.executeUpdate();
if(i>0){
System.out.println("插入成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JbdcUtils.release(coon,st,null);
}
}
}
删除
package com.lobort.lesson03;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestDelete {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JbdcUtils.getConnnection();
//预编写sql语句
String sql = "delete from users where id = ? or id = ?";
st = conn.prepareStatement(sql);
st.setInt(1,5);
st.setInt(2,6);
int i = st.executeUpdate();
if(i>0){
System.out.println("删除成功");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JbdcUtils.release(conn,null,null);
}
}
}
修改
package com.lobort.lesson03;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TestUpdate {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
try {
conn = JbdcUtils.getConnnection(); //建立连接
//预编译sql
String sql = "update users set `NAME`= ? where id = ?;";
st = conn.prepareStatement(sql);
//参数赋值
st.setString(1,"nichishi");
st.setInt(2,2);
int i = st.executeUpdate();
if(i>0){
System.out.println("成功了 ");
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JbdcUtils.release(conn,st,null);
}
}
}
查询
package com.lobort.lesson03;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestSelect {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JbdcUtils.getConnnection(); //建立连接
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.getString("NAME"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JbdcUtils.release(conn,st,rs);
}
}
}
防止sql注入
package com.lobort.lesson03;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class SqlZhuru {
public static void main(String[] args) {
login("luo","123456");
// login("' or' 1=1","' or '1=1");
}
public static void login(String name, String password){
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JbdcUtils.getConnnection();
//sql预编译
String sql = "select * from users where `NAME` = ? and `PASSWORD` = ?";
st = conn.prepareStatement(sql);
//传递参数
st.setString(1,name);
st.setString(2,password);
rs = st.executeQuery();
while (rs.next()){
System.out.println(rs.getString("NAME"));
System.out.println(rs.getString("password"));
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
JbdcUtils.release(conn,st,rs);
}
}
}
10.6、事务
1、建立连接 conn.setautocommit(false)
2、一组业务执行完毕,提交事务
3、可以在catch语句中显示的定义回滚,但是默认会自动回滚
package com.lobort.lesson04;
import com.lobort.lesson02.utils.JbdcUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class TestTransation {
public static void main(String[] args) {
Connection conn =null;
PreparedStatement st =null;
ResultSet rs =null;
try {
conn = JbdcUtils.getConnnection(); //建立连接
//关闭自动提交
conn.setAutoCommit(false);
//业务1
String sql1 = "update account set money = money-100 where name = 'A'";
st = conn.prepareStatement(sql1);
st.executeUpdate();
//业务2
String sql2 = "update account set money = money+100 where name = 'B'";
st = conn.prepareStatement(sql2);
st.executeUpdate();
//业务完毕, 提交事务
conn.commit();
System.out.println("成功");
} catch (SQLException e) {
try {
conn.rollback(); //如果失败就回滚
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
}finally {
JbdcUtils.release(conn,st,rs);
}
}
}

浙公网安备 33010602011771号