mysql入门语法

初识MySQL:

数据库分类

关系型数据:

通过表和表之间,行和列之间的关系进行数据的存储,学院信息表,考勤表,…

  • MySQL
  • Oracle
  • sqlserver
  • DB2
  • sqlite

非关系型数据库

非关系型数据库,对象存储,通过对象的自身的属性来决定

  • Redis
  • mongDB

DBMS(数据库关系系统)

DDL(数据库定义语言):

操作数据库(了解)

操作数据库–> 数据库的表–> 数据库表中的数据

mysql 不区分大小写,但是约定俗成用小写

在这里插入图片描述

创建数据库
-- 创建数据库:create database [if not exists] 数据库名;
CREATE database yf03203;
删除数据库
-- 删除数据库:drop database [if exists] 数据库名;
drop database yf03203;
修改数据库
-- 修改数据库:alter database 数据库名  default character set 旧编码方式 collate 新编码方式

查询数据库
-- 查看创建数据库的语句
show create databases 数据库名 

-- 查看所有的数据库
show databases 

-- 使用数据库
use 表名;
数据类型:

在这里插入图片描述

数据库的字段属性(重点)

无符号(unsigned):声明该列不能为负数

零填充:不足的位数补零 5:0005

自增:

  • 自动在上一条记录的基础上+1(默认)
  • 通常用来设计唯一的主键 index ,
  • 必须是整数类型
  • 可以自定义设计主键自增的步长和起始值

非空(not null):不填值会报错

默认:设置默认值

长度:如果int型,设置了长度,只针对零填充时候零的长度,对实际没印象,比如(类型:int ,长度:1,数值:789)这个值还是789,如果设置了零填充的话就是(常规零填充是:000000456。 长度:5,值:456:00456),char 和varchar有影响。

拓展(阿里巴巴规范):

每个表 必须存在以下五个字段!,阿里巴巴规范, 学习阶段可以省略节约时间,做项目必须要

/*
id  主键
‘version'  乐观锁
is_delete  伪删除
gmt_create 创建时间
gmt_update 修改时间
*/

表的约束用于保证数据的完整性和准确性,分为
实体完整性约束
主键约束
域完整性约束
检查约束、默认值约束、唯一约束、非空约束
引用完整性约束
外键约束
自定义完整性约束
触发器

创建表(重点)
create table[if not exists] `表名`(
  `字段名1` 列类型 [约束条件],
  `字段名2` 列类型 [约束条件],
  ...
  `字段名n` 列类型 [约束条件]
)

在这里插入图片描述

删除表:
-- 删除表:drop table [if exists] 表名;
drop table student;

修改表
-- 修改表名
alter table student rename as teacher;

-- 增加表的字段
alter teble teacher add age int;

-- 修改表的字段(重命名,修改约束)
-- alter table 表名 modify 字段名 列属性[]
alter table teacher modify age varchar(11) -- 修改约束
-- alter table 表名 change 旧字段名 新字段名 列属性[]
alter table teacher change age age1 int;   -- 修改整个字段(约束+名字)

-- 删除表的字段 :alter table 表名 drop 字段名;
alter table teacher drop age1;
查看表
 -- 查看student 数据表的定义语句
show create table 表名

 -- 显示表的结构
desc student

DML(数据库操作语言)

CRUD:增加(Create)、检索(Retrieve)、更新(Update) 和 删除(Delete)

增(c:create)

添加数据:
-- 语法:
insert into student (字段名1,字段名2,字段3...) 
values (值1,值2,值3),
(值1,值2,值3),
(值1,值2,值3);

-- 字段可以省略,但是后面的值必须要一一对应。
insert into student (id,`name`,age,sex,`describe`)
values
(8,'张三',18,'男',null),
(9,'李四',11,'女','我们班美女');
删除数据:
-- 删除数据语法:
delete from 表名 [where 条件]

-- 清空数据
truncate 表名

delete 和 truncate 区别?

相同:都能删除数据,都不能删除表结构

不同:

  • truncate 重新设置 自增列计数器
  • truncate 不会影响事务
修改数据:
-- 语法:
update 表名 set 字段1 = 值1,字段2 = 值2 [where 条件]
update student set `describe` = '凤凰传奇真传奇' where id = 8;

注意点:

  • 没有条件的话,会修改所有的列,
  • 值可以是个变量

DQL(数据库查询语言)最重点

简单查询:
-- 语法
select [distinct] 字段1,字段2 from 表名 [where 条件]
[group by 字段名 [having 条件]] 
[order by 字段名 [asc|desc]]
[limit [offset]记录数]

distinct : 去重

场景:某个公司很多人,也很多部门,这时可以查看有哪些部门,就可以去重

where 子句
  • 关系运算符
  • in
  • between and
  • is null
  • like
  • and
  • or
  • 取别名(as)貌似,取别名后就不能使用原名字了

where 条件的运算符

运算符含义示例
=等于5=4:false
<> 或 !=不等于5<>4 : true
>大于
<小于
>=大于等于
<=小于等于
between…and…在… … 之间【2,5】闭区间
and和 (同java的&&)
or或(同java的||)
in在什么之中in(值1,值2)匹配括号里的
和and 的作用一样
like模糊匹配%:0个或任意个字符 _ : 一个字符
is null / is not null是否为空
/*
	where 子句
*/
#1)关系运算符的使用 = != <> < > <= >=

#查询不是吴好的学习的信息
select * from student1 where sname <> '吴好';
#查询年龄小于18岁的学生信息
select * from student1 where age <=18;

#2)in 指定了一些满足的值 
#查询姓名是吴好或者崔平的学生信息
select * from student1 where sname in('吴好','崔平','蔡徐坤');
#查询姓名不是蔡徐坤的学生信息
select * from student1 where sname not in('蔡徐坤');

#3) between A and B 在A 和 B 的范围内 A必须小于等于B
#查询年龄在18-19岁的学生的信息
select * from student1 where age between 18 and 19;

#4)查询字段为空的信息
#查询部门字段为空的学生信息
select * from student1 where dept is null;
#查询部门字段不为空的学生信息
select * from student1 where dept is not null;

#5)distinct 去掉重复的记录
select * from student1;
select distinct sname from student1;

#6) like 模糊查询
/* 需要配合通配符使用 共有四种匹配方式
	 1.% 表示长度大于等于0的任意一个字符串
	 2._ 表示长度为1的任意单个字符
	 3.[]指定一个字符、字符串或范围,要求所匹配对象为它们中的任一个
	 4.[^]表示不在括号所列之内的单个字符
	注意:如果要匹配'%' '_' 等特殊字符 需要使用[]
*/
#查询姓吴的学生
select * from student1 where sname like '吴%';
#查询姓吴并且名称中中至少有两个字的学生
select * from student1 where sname like '吴_%';
#查询不姓吴的学生
select * from student1 where sname not like '吴%';
#查询名称中带有_的人 使用escape 可以将指定字符后面的字符作为非转义字符
select * from student1 where sname like '%,%%' ESCAPE ',';

#7 A and B 两个条件都要满足才可以匹配到
#查询年龄大于18岁并且是女性的学生
select * from student1 where age>18 and sex='女';

#8 A or B 两者之间有一个满足就可以匹配到
#查询年龄小于20岁的学生或者音乐系的学生
select * from student1 where age<20 or dept ='音乐系';
#组合使用 and 和 or
#查询年龄小于20岁的学生或者音乐系的学生 并且 这些学生都是女性
select * from student1 where (age<20 or dept ='音乐系') and sex ='女';

#9 给表取别名
#给表取名字
select * from student1 s1 where s1.age>19;
select * from student1 as s1 where s1.age>20;
# 取别名 不是改名字
-- select * from s1 where s1.age>20; 
#10给列取别名
select sname 姓名, age 年龄 from student1;
select sname as '姓名', age as '年龄' from student1;
字段表达式
select 表达式 from 表名
select version() 				 -- 查看系统版本(函数)
select 100*7+4    			 -- 计算
select 100*7+4 as 计算   	-- 计算
select @@auto_increment_increment  -- 查看自增的步长(变量)

-- 年龄加100岁
select `name`,age = age+100 as age from student
联表查询(join on)

建表的数据: student_kuang.sql

-- 联表查询
-- 查询 学生ID,姓名,课程名称,课程成绩

/*
-- 分析:
         1. 这些字段来自哪个表,若两个表都有同一字段则需明确是哪个表的字段
				 2. 确定使用哪种连接查询(左连接,右连接,inner join)
				 3. 确定交叉点(这两个表中的数据哪个是相同的
				 4. 判断的条件
*/
-- 交集
select student.studentno,studentname,subjectno,studentresult
from student
INNER JOIN result
ON student.studentno = result.studentno;

-- 左连接
select student.studentno,studentname,subjectno,studentresult
from student
LEFT JOIN result
ON student.studentno = result.studentno;

-- 查询缺考的同学 
select student.studentno,studentname,subjectno,studentresult
from student
LEFT JOIN result
ON student.studentno = result.studentno
where studentresult is null;

-- 右连接
select student.studentno,studentname,subjectno,studentresult
from student
RIGHT JOIN result
ON student.studentno = result.studentno;

-- 多表 
-- 学号,姓名是student表的,     subjectname 是subject表的,      studentresult 是result表的
-- 之间的关系,student 的 学号 和 studentresult 的学号是相同的
--           studentresult 的 课程编号 和 subject 的课程编号是一样的
select s.studentno,studentname,subjectname,studentresult 
from student s
INNER JOIN result r
ON s.studentno = r.studentno
INNER JOIN `subject` sub
on r.subjectno = sub.subjectno;

where 和 on的区别 :join on:连接查询 where :等值查询

  • where 先联表再查询,

  • on 是 查询再联表

自连接

把一张表拆分两张表来对应

-- 练习:自连接  把一张表拆分两张表来对应
select c.categoryname,p.categoryname
from category as c,category as p
where c.categoryid = p.pid;
-- 自连接数据库建表:
CREATE TABLE `school`.`category`( 
`categoryid` INT(3) NOT NULL COMMENT 'id', 
`pid` INT(3) NOT NULL COMMENT '父id 没有父则为1',
 `categoryname` VARCHAR(10) NOT NULL COMMENT '种类名字', 
PRIMARY KEY (`categoryid`) 
) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci; 

INSERT INTO `school`.`category` VALUES
(2, 1, '信息技术'),
(3, 1, '软件开发'),
(5, 1, '美术设计'),
(4, 3, '数据库'), 
(8, 2, '办公信息'),
(6, 3, 'web开发'),
(7, 5, 'ps技术');
分组和过滤

使用了聚合函数的话,必须使用分组

-- 练习:查询不同课程的平均分,最高分,最低分
-- 分组和过滤 GROUP BY 字段名 having 条件

select subjectname,AVG(studentresult) as 平均分,max(studentresult),min(studentresult)
from result as r
inner JOIN `subject` as sub
on r.subjectno = sub.subjectno
GROUP BY subjectname 
having 平均分>60

多条件分组

-- 多条件分组 
-- 练习: 统计各部门的男女各有多少人
-- 分析: 通过部门的名称和员工的性别分组 统计人数 
use supersys;
select  e_dept as 部门,e_sex as 性别,COUNT(1) as 人数 from employee
GROUP BY e_dept,e_sex


分页
-- limit :分页
-- 语法:limit [第几条数据开始]  记录数
select stu.studentno,studentname,subjectname,studentresult
from student as stu
inner JOIN result as res
on stu.studentno = res.studentno
INNER JOIN `subject` as sub
on sub.subjectno = res.subjectno
order by studentresult asc
LIMIT 0,3;
排序
-- order by:排序
-- 语法:order by 排序的字段 升序(asc)/降序(desc),排序的字段2 升序/降序
select stu.studentno,studentname,subjectname,studentresult
from student as stu
inner JOIN result as res
on stu.studentno = res.studentno
INNER JOIN `subject` as sub
on sub.subjectno = res.subjectno
order by studentresult asc;
-- 练习:查询java第二学年 课程成绩排名前十的学生,并且分数要及格的学生信息(学号,姓名,课程名称,分数)
select s.studentno,studentname,sub.subjectname,r.studentresult
from
student as s
inner join result as r
on s.studentno = r.studentno
inner join subject as sub
on r.subjectno = sub.subjectno
where s.gradeid =2 and subjectname like '%Java%' and studentresult>60
order by studentresult DESC
limit 10;
子查询

子查询比联表查询慢

-- 子查询 
-- 练习:查询参加C语言-1 学生的学生信息(学号,名字,成绩) 
/*
 分析:
 			1.学生学号,姓名 在 student 表中,    成绩在 result 表中      科目名 在 subject 表中
 			2.共通点:学号 是 student 和 result表的相同字段      科目编号是 result 和 subject 表的相同字段
 			
 			3.查学号,姓名,成绩  在哪个表中,条件是什么(相同点):学号
 			4.什么样的学号能返回?科目编号相同的,
 			5.什么样的科目编号能返回?科目名是‘C语言-1’的;
*/
use school;
select  s.studentno,studentname,studentresult
from student as s,
result as r
where s.studentno in (
select r.studentno from result where r.subjectno =(
select sub.subjectno from `subject` as sub where subjectname = 'C语言-1'
)
);

-- 联表的方式
-- 联表
select s.studentno,studentname,studentresult
from student as s
INNER JOIN result as r
on s.studentno = r.studentno
INNER JOIN `subject` as sub
on r.subjectno = sub.subjectno
where sub.subjectname like '%C语言%'
order by studentresult DESC
limit 0 5;

select 小结:

select [distinct] *| 字段....
from 表 (多表用逗号隔开)
xxx join 表 on 条件 (可以多个联表)
where 条件 (还可以子查询)
group by 字段 having 条件
order by 字段 升序asc|降序desc
limit 第几条记录 记录数

  • 顺序不能错,但是可以省略

MySQL函数:

常用函数(不常用)
-- 数学运算
select abs(-9); -- 绝对值
select ceiling(9.8) -- 向上取整
select floor(9.8) -- 向下取整
select RAND() -- 返回一个 0 -1 之间的随机数
select SIGN(10) -- 负数返回-1   0返回0   正数返回1

-- 字符串函数
select CHAR_LENGTH('我就是玩儿'); -- 字符串长度
select CONCAT('我','还','就是玩'); -- 拼接字符串
select LOWER('XXhh'); -- 全转小写
select upper('XXhh'); -- 转大写
select SUBSTR('键盘敲烂月薪过万', 5 ,2) -- 截取字符串

-- 练习:查询姓张的同学,换成章
select REPLACE(studentname,'张','章') 
from student
where studentname like '张%';

-- 时间和日期
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());
聚合函数(常用)
函数名称描述
count()计数
sum()求和
avg()求平均值
max()最大值
min()最小值
-- 聚合函数
-- 计数  -- 三个结果都一样
use 
select COUNT(studentname) from student; -- 会忽略null值
select COUNT(*) from student; -- 不会忽略null值
select count(1) from student; -- 不会忽略null值  

-- 练习:查询不同课程的平均分,最高分,最低分
-- 分组和过滤 GROUP BY 字段名 having 条件
-- 聚合函数必须使用分组
select subjectname,AVG(studentresult) as 平均分,max(studentresult),min(studentresult)
from result as r
inner JOIN `subject` as sub
on r.subjectno = sub.subjectno
GROUP BY subjectname
having 平均分>60

注意:使用了group by后,select后出现的字段要么只能出现在group by子句中,要么只能出现在聚合函数中

扩展:数据库级别的MD5加密

什么是MD5?

增强算法复杂度,且不可逆

-- ======== 测试MD5 加密===========
-- 建表
create table testmd5 (
 id int not NULL,
 `name` varchar(20) not null,
 pwd varchar(100) not null,
 primary key (id)
)ENGINE = INNODB default charset =utf8

-- 添加数据
-- 明文密码
insert into testmd5 values
(1,'张三','12345'),
(2,'李四','12345'),
(3,'王五','12345');

-- 加密
update testmd5 set pwd=MD5(pwd)

-- 插入数据的时候加密
insert into testmd5 values
(4,'小明',md5('123456'))

-- 如何校验:将用户传递过来的密码,进行md5加密
select * from testmd5 where `name`='小明' and pwd = MD5('123456')

事务

什么是事务

要么都成功,要么都失败,

将一组SQL放在一个批次中执行

事务管理(ACID)是指数据库管理系统DBMS)在写入或更新资料的过程中,为保证事务是正确可靠的,所必须具备的四个特性:

  • 原子性(atomicity,或称不可分割性):要么都成功,要么都失败,
  • ==一致性 consistency):==事务前后的数据完整性要保持一致,
  • ==隔离性(Isolation),又称独立性):==事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
  • (脏读 虚读)
  • 持久性(Durability)::持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

参考博客链接:https://blog.csdn.net/dengjili/article/details/82468576

-- 事务
-- MySQL 是默认开启事务自动提交的

set autocommit = 0 -- 关闭
set autocommit = 1 -- 开启 (默认)

-- 手动处理事务
set autocommit = 0

-- 事务开启
start transaction -- 标记一个事务的开始,从这个之后的SQL都在同一个事务内
insert ...

-- 提交:持久化(成功)
commit 
-- 回滚:回到原来的样子 (失败)
rollback

-- 事务结束
set autocommit = 1 -- 开启自动提交


-- 
set autocommit = 0;
start TRANSACTION;
use shop ;
update shop set money = money -500 where `name` = '张三';
update shop set money = money +500 where `name` = '李四';

commit;
rollback;

set autocommit = 1;

索引

MySQL 官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构,提取橘子主干,就可以得到索引的本质,索引是数据结构。

索引分类
  • 主键索引(primary key):唯一标识,主键不可以重复,
  • 唯一索引(unique key):避免重复的列出现,唯一索引可以重复,多个列都可以标识
  • 常规索引(index)
  • 全文索引(FullText)

基础语法

-- 索引的使用
-- 1.在创建表的时候给字段添加所有
-- 2.创建完毕后,增加所有

-- 显示所有的所有信息
show index from student

-- 增加一个全文索引
alter table student add fulltext index `studentname_idx`(studentname);

-- explain 分析SQL执行的情况
explain select * from student; -- 非全文索引
explain select * from student where match(studentname) asainst('章');
测试索引
-- 建表
CREATE TABLE `app_user` (
`id` int(20)  NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50)   ,
`email` VARCHAR(50) NOT NULL  ,
`phone` VARCHAR(20)   ,
`gender` TINYINT    ,
`password` VARCHAR(100) NOT NULL  ,
`age` TINYINT(4)    ,
`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 COMMENT = 'app用户表'


-- 插入100万数据.
DELIMITER $$
-- 写函数之前必须要写,标志
CREATE FUNCTION mock_data ()
RETURNS INT
DETERMINISTIC
BEGIN
	DECLARE num INT DEFAULT 1000000;
	DECLARE i INT DEFAULT 1001;
	WHILE i<num DO
		INSERT INTO `app_user`(`name`,`email`,`phone`,`gender`)VALUES(CONCAT('用户',i),'19224305@qq.com','123456789',FLOOR(RAND()*2));
		SET i=i+1;
	END WHILE;
	RETURN i;
END;

SELECT mock_data() -- 执行此函数 生成一百万条数据



-- =================================这里开始才是重点=================================================

-- 增加索引1 :命名方式:idx_表名_字段名
-- 为name 这个字段添加索引
-- 格式: create index 索引名 on 表名(字段名)
create index idx_app_user_name on app_name(`name`)

-- 没有索引的速度
select * from app_user where name = '用户858789'; -- 时间: 2.602s
explain select * from app_user where name = '用户858789'; -- 查了1990281行

-- 加了索引的速度 添加索引也很耗时间,所以小量数据的时候大可不必建索引,反而浪费时间
create index idx_app_user_name on app_user(`name`);
select * from app_user where name = '用户824389';  -- 第一次:时间:0.022s   第二,三,四,五次:时间: 0.001s  第二次或更多次时会比第一次快
explain select * from app_user where name = '用户824389'; -- 查了2行 (有两条数据


-- 增加索引2 全文索引
use school ;
alter table student add fulltext index `studentname_idx`(studentname);
explain select * from student where match(studentname) against('章');

索引原则

  • 索引不是越多越好
  • 不要多经常变动数据加索引
  • 小数据的表不需要加索引
  • 索引一般加载常用来查询的字段上!

课外知识:索引的数据结构

参考博客:http://blog.codinglabs.org/articles/theory-of-mysql-index.html

权限管理

在这里插入图片描述

数据库备份

为什么要备份:

  • 保证重要的数据不丢失
  • 数据转移
  • 防止删库跑路

怎么备份:

  • 复制物理文件

  • 在Navicat可视化工具中手动导出

在这里插入图片描述

  • 命令行,mysqldump

    -- 导出
    #mysqldump -h主机 -u 用户名 -p 密码 数据库 表名 >物理路径
    
    -- 导入
    source 备份文件路径
    
    mysqldump -hlocalhost -uroot -p123456
    

规范数据库设计

为什么需要设计

当数据库比较复杂的时候,我们就需要设计了

糟糕的数据库设计:

  • 数据冗余,浪费空间
  • 数据库插入和删除都会麻烦,异常
  • 程序性能差

良好的数据库设计

  • 节省内存空间
  • 包装数据库的完整性
  • 方便开发

软件开发中,关于数据库的设计

  • 分析需求:分析业务和需要处理的数据库的需求
  • 概要设计:设计关系图E-R图
设计数据库案例

设计数据库的步骤(个人博客)

  • 收集信息,分析需求
    • 用户表(用户登入注销,用户的个人信息,写博客,创建分类
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 友链表(友链信息)
  • 标识实体(把需求落地到每个字段)
  • 标识实体之间的关系
    • user --> blog:写博客
    • user -->category:分类
    • user- -> user -->blog:评论

ant design pro elements 前端组件

三大范式

参考博客:https://www.cnblogs.com/wsg25/p/9615100.html

第一范式:

原子性:保证每一列不可再分

第二范式:

前提:满足第一范式

每张表只描述一件事情

第三范式:

前提:满足第一范式 和 第二范式

第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

规范性 和 性能的问题

关联查询的表不得超过三张表

  • 考虑商业化的需求和目标,(成本,用户体验!) 数据库的性能更加重要
  • 在规范性能的问题的时候,需要适当的考虑一下 规范性!
  • 故意给某些表增加一些冗余的字段。(从多表查询中变为单表查询)
  • 故意增加一些计算列(从大数据量降低为小数据量的查询:

JDBC(重点)

sun公司为了简化开发人员的(对数据库的同一)操作,提供了一个(java操作数据库的)规范,俗称jdbc

java.sql

javax.sql

数据库驱动

需要导入一个数据库驱动包

参考博客:https://blog.csdn.net/weixin_43173093/article/details/103135955

mySQL Connector 8.0.11:https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.11

第一个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,'zhansan','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')

添加数据库驱动

右击项目—> 建一个目录文件: lib —> 将下载的驱动jar包拖过来,—> 右击jar包有一个 add as Library.—>ok

编写测试代码

package testJDBC;
import java.sql.*;

// 我的第一个JDBC 程序
public class TestJDBCDemo1 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        //1. 加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver");

        //2.用户信息和 url  serverTimezone=UTC
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=false";
        String username = "root";
        String password = "adminxhb";

        // 3.连接成功,返回数据库duixiang
        Connection connection = DriverManager.getConnection(url,username,password);

        //4.执行SQL 的对象 Statement 执行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("PASSWORD=" + resultSet.getObject("PASSWORD"));
            System.out.println("email=" + resultSet.getObject("email"));
            System.out.println("birthday=" + resultSet.getObject("birthday"));
            System.out.println("==========");
        }

        //6.释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

//1. 加载驱动 固定写法

Class.forName("com.mysql.cj.jdbc.Driver");//5.0:com.mysql.jdbc.Driver

URL

String url = "jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=false";
//   协议://主机地址:端口号/数据库名/参数1&参数2&参数3

DriverManager 驱动管理者

Connection connection = DriverManager.getConnection(url,username,password);

// connection 代表数据库
// 数据库设置自动提交
connection.setAutoCommit();
// 事务提交
connection.commit();
// 事务回滚
connection.rollback();

Statemen 执行SQL的对象: 写SQL语句的t

statement.executeQuery();  // 查询操作 返回resultSet对象
statemnet.execute(); // 执行任何sql,
statemnet.executeUpdate();// 更新,插入,删除,都是用这个,返回一个受影响的行数

ResultSet 查询的结果集:封装了所有的查询结构

获得指定的数据类型

resultSet.getObject();  // 不知道列类型的话可以用object接收

//知道就用指定类型接收
resultSet.getString();
resultSet.getInt();
.......

释放资源

//6.释放连接
resultSet.close();
statement.close();
connection.close();
statement 对象

Jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

1、提取工具类(db.properties , JdbcUtils)

# db.properties 配置文件工具类

driver = com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=false
#   jdbc:mysql://localhost:3306/jdbcstudy?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&&useSSL=false;

username=root
password=adminxhb
// JdbcUtils 工具类

package utils;

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 password = null;
    static {
        try{
            InputStream is = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(is);
            driver=properties.getProperty("driver");
            url=properties.getProperty("url");
            username=properties.getProperty("username");
            password=properties.getProperty("password");

            // 1. 驱动只用加载一次
            Class.forName(driver);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    // 获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    // 释放连接资源
    public static void release(Connection connection, Statement statement, ResultSet resultSet){
        if (resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if (statement!=null){
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }

        if(connection!=null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

statement 增删改查

增删改是用 statement.executeUpdate()

查询是用statement.executeQuery()

package testJDBC;

import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestInsert {
    public static void main(String[] args)   {

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            //1 建立连接 返回数据库对象
             connection = JdbcUtils.getConnection();

             //2.获取操作数据库执行对象(表
            statement = connection.createStatement();

            //3.操作数据的sql语句
            // 增加一条数据
            String sqlInsert = "insert into users(id,name,PASSWORD,email,birthday)values(7,'张三','123456','1350099076@qq.com','2001-10-26');";
            // 删除一条数据
            String sqlDelete = "delete from users where id = 6";
            // 修改一条数据
            String sqlUpdate = "update users set name = '凤凰传奇',email='2830105247@qq.com' where name='张三'";

            // 返回受影响的行数  增删改都是用executeUpdate    查询使用executeQuery
            int i = statement.executeUpdate(sqlUpdate);
            if(i>0){
                // System.out.println("插入成功");
                // System.out.println("删除成功");
                System.out.println("修改成功");
            }

            // 查询
            String sqlSelect = "select id,name from users where name='凤凰传奇'";
            resultSet = statement.executeQuery(sqlSelect);

            while (resultSet.next()){
                System.out.println("id="+resultSet.getObject("id"));
                System.out.println("name="+resultSet.getObject("name"));
            }
            resultSet.beforeFirst(); // 结构像链表 回到第一个
            while (resultSet.next()){
                System.out.println("id="+resultSet.getObject("id"));
                System.out.println("name="+resultSet.getObject("name"));
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            // 释放资源
            JdbcUtils.release(connection,statement,resultSet);
        }
    }
}
Statement SQL注入问题

SQL 存在漏洞,会被攻击导致数据泄露

直接看代码

package testJDBC;

import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 *  SQL注入问题
 */
public class SQLInjection {
    public static void main(String[] args) throws SQLException {
        String username = "凤凰传奇";
        String password = "123456";
        // 正常写法
      //  login(username,password);
        // 带有注入的写法 及时没有输入正确的用户名和密码也能破解掉
        // 相当于:select * from users where name = '' or 1=1 or '' and password ='' or 1=1 or''
        username = "' or 1=1 or '";
        password = "' or 1=1 or '";
        login(username,password);
    }

    private static void login(String username, String password) throws SQLException {
       // 连接数据库
        Connection connection = JdbcUtils.getConnection();

        // 返回数据库执行对象
        Statement statement = connection.createStatement();
        String sql = "select * from users where name='"+username+"' and password = '"+password+"'";

        // 接收查询的数据 结果集
        ResultSet resultSet =  statement.executeQuery(sql);
        while (resultSet.next()){
            System.out.println("id="+ resultSet.getString("id"));
            System.out.println("name="+ resultSet.getString("name"));
            System.out.println("password="+ resultSet.getString("password"));
            System.out.println("=====================================");
        }

        // 释放资源
        JdbcUtils.release(connection,statement,null);
    }
}
PreparedStatement 对象

PreparedStatement 可以防止SQL注入。效率更好!

package testJDBC;

import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class PrepareStatementDemo {
    public static void main(String[] args) throws SQLException {
        // 获取数据库连接对象
        Connection connection = JdbcUtils.getConnection();

        // 没有注入问题的sql执行对象
        String sql = "insert into users (id,name,password,email,birthday) values (?,?,?,?,?)";
        // 预处理 sql 语句
        PreparedStatement pstatement = connection.prepareStatement(sql);
        //给 预处理的SQL 语句的问号 附具体值   1 :代表第一个问号,后面则是内容
        pstatement.setInt(1,7);
        pstatement.setString(2,"李四");
        pstatement.setString(3,"123456789");
        pstatement.setString(4,"1350099076@qq.com");
       // pstatement.setDate(5,java.sql.Date.valueOf("2001/10/26"));
        pstatement.setDate(5,new java.sql.Date(new java.util.Date("2001/10/26").getTime()));
        // 执行SQL语句   注意:这里使用参数的,前面已经预处理了 返回受影响的行数
        int i =pstatement.executeUpdate();
        if(i>0){
            System.out.println("插入成功");
        }else {
            System.out.println("插入失败");
        }

        // 释放资源
        JdbcUtils.release(connection,pstatement,null);
    }
}
PreparedStatement 防注入问题

防止注入原理:传递过去的 ’ 会被转义,所以也不会报错也不会出结果

直接看代码

package testJDBC;

import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class SQLInjection_pStatement {
    public static void main(String[] args) {
        String username = "李四";
        String password = "123456789";
        // 正常的查询
     //   login(username,password);
        // 带注入的查询  这样是查询不出来的,因为这个' 会被转义了。所以不会报错也不会有效
        username = "'' or 1=1";
        password = "'' or 1=1";
        login(username,password);
    }

    private static void login( String username,String password) {
        Connection connection=null;
        PreparedStatement pstatement = null;
        ResultSet resultSet = null;
        try {
            // 获取数据库连接对象
             connection = JdbcUtils.getConnection();

            // 获取数据库执行对象 预处理sql
            String sql = "select * from users where name = ? and password = ?";
            pstatement = connection.prepareStatement(sql);
            pstatement.setString(1,username);
            pstatement.setString(2,password);

            // 执行sql  返回结果集
            resultSet = pstatement.executeQuery();
            while(resultSet.next()){
                System.out.println("id="+resultSet.getInt("id"));
                System.out.println("name="+resultSet.getString("name"));
                System.out.println("password="+resultSet.getString("password"));
            }

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            // 释放资源
            JdbcUtils.release(connection,pstatement,resultSet);
        }
    }
}

使用IDEA连接数据库
  1. 添加数据库
    在这里插入图片描述

  2. 用户名密码登入数据库
    在这里插入图片描述

    8.0 以上的还好设置时区 在上面直接点击测试连接 他会报错给出提示,点一下也可以。手动添加亦可

    在这里插入图片描述

  3. 选择数据库

在这里插入图片描述

  1. SQL控制台

在这里插入图片描述

java代码写事务

ACID 原则 :

原子性:要么全部完成,要么都不完成

一致性:总数不变

持久性:一旦提交不可以,持久化到数据库了

隔离性:多个事务互不干扰

隔离性问题:

脏读:一个书屋读取了另一个没有提交的事务

不可重复读:在同一事务内,重读读取表中的数据,表数据发生了改变

虚读(幻读):在一个事务内,读取到别人插入的数据,导致前后读取的结果不一致

# 建表
CREATE TABLE `account` (
                           `id` int NOT NULL AUTO_INCREMENT,
                           `NAME` varchar(40) DEFAULT NULL,
                           `money` float DEFAULT NULL,
                           PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8
// 事务代码

package testJDBC;

import utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class Sql事务 {

    public static void main(String[] args) {
        Connection connection = null;

        // 1.建立数据库连接
        try {
            connection = JdbcUtils.getConnection();

            // 2.关闭数据库自动提交,会自动开启事务
            connection.setAutoCommit(false);

            //2.获取数据库执行对象
            String sql1 = "update jdbcstudy.account  set money  = money-100 where name='A'; ";
            PreparedStatement ps = connection.prepareStatement(sql1);
            ps.executeUpdate();

            String sql2 = "update jdbcstudy.account  set money  = money+100 where name='B'; ";
            ps = connection.prepareStatement(sql2);
            ps.executeUpdate();

            // 业务完成 提交事务
            connection.commit();
            System.out.println("ok");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            try {
                // 若失败 则回滚
                connection.rollback();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}
数据库连接池

数据库连接 — 执行完毕 — 释放

连接 — 释放 十分浪费系统资源

池化技术:准备一些预先的资源,过来就连接预先准备好的

编写连接池,只需要实现一个接口 DataSource

开源数据源实现

DBCP

C3P0

Druid:阿里巴巴

使用了连接池之后,我们在项目开发中就不需要编写连接数据库的代码了

JDBC:Java DataBase Connectivity,java连接数据库和执行SQL语句的API。

数据源:Data Source。就是将IP、数据库、用户名、密码封装起来对外只提供一个JNDI名称,在应用中只要调用这个JNDI就能连接数据库,而不需要在代码中写入用户名密码等信息。这样做的好处是,当用户名密码乃至数据库变化时只需要去修改JNDI的xml文件而不需要去修改代码

JNDI:Java Naming and Directory Interface,Java命名和目录接口。J

DBCP:DataBase Connection Pool,数据库连接池。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值