jdbc学习情况总结

day33

晨写

# 晨写
​
## 1.DML语句添加/删除/修改的操作语法 (表的记录)
​
```sql
-- 插入全表的字段
insert into 表名 values(值1,值2...值n),(值1,值2,...值n) ,(...) ;
-- 插入部分字段
insert into 表名(字段名称1,字段名称2,...字段名称n) values(值1,值2,...值n),(....),(....) ;
​
-- 删除(带条件删除)
delete from 表名 where 字段名称  = 值 ;
delete from 表名 where 字段名称  = 值 and 字段名称2 = 值2.... ;
-- 删除全表
delete from  表名;
​
-- 修改(带条件修改)
update 表名 set 字段名称=  值 ,字段名称2 =值2 ...where 非业务字段id = 值 ;
-- 批量修改
update 表名 set 字段名称 = 值 ,字段名2=值2...;
```
​
## 2.delete from 表名 和truncate table 表名的区别?
​
```markdown
共同点:
    两个都是将整个表的所有记录数全部删除
不同点:
1)是否会删除表
    delete from 表名 ;仅仅是将表的所有记录数删除,不会删除这张表
    truncate  table 表名; 会将表直接删除(所有数据清空了)
2)是否会影响自增主键id值
    delete from 表名,由于不会删除表,表的结构还在,只是表的数据清了,再次去插入数据,会在上次基础上id继续自增(不影响自增长主键id值)
    truncate table 表名,由于删除表,自动一张一模一样的空表,将之前的结构就删除了,直接影响了自增长主键id的值;
```
​
## 3.DQL语句 中的聚合函数列举
​
```sql
-- 查询某列的最大值
select max(字段名称) from 表名 ; -- min(字段名称)最小值
-- 查询某列的平均分
select avg(字段名称) from 表名 ;
-- 某列的总数:求和
select sum(字段名称) from 表名 ;
-- 统计表的总记录数(总条数)
select count(非业务字段) from 表名;
​
```
​
​
​
## 4.DQL语句中模糊查询的语法
​
​
​
```sql
select 指定的字段名称(字段列表) from 表名 where 某个字段名称 like '%关键字%' ; -- '关键字%'
```
​
​
​
## 5.基本的带条件的查询语法
​
```sql
select 字段列表 from 表名 where 某个字段名称=  值;
select 字段列表 from 表名 where 某个字段名称=  值 and 字段名称2 = 值2 ;-- 多个条件
select 字段列表 from 表名 where 某个字段名称 <=或者 >=,!=,<>  某个值  -- 比较运算符
                                        -- between 值1  and 值2 ;
```
​
----
​
-----
​
​
​
# 今日内容
​
## 1.DQL语句
​
```
1.where条件查询 ----and 并列多个条件
2.                  多个or 或 的关系
select  字段列表  from 表名 where 某个字段名称 = 值1 or 字段名称 = 值2 or 字段名称=值3;
3.                                      某个字段名称 in(值1,值2,值3) ; 等价于上面
4.排序oder by   和where一块使用----where在前面 ,order by 在后面
5.分组查询 group by
6.having :帅选...
7.分页查询 limit 
```
​
## 2.关于数据库的备份和还原
​
```
备份和还原
 --图形界面化方式备份和还原 (简单易于上手)
 --命令行的备份和还原(记住一些指令)
```
​
## 3.数据库的约束 (约束用户操作库中的某张表的行为)
​
```
每一张表的id,不重复(唯一),非空,设置自增长
​
```
​
## 4.设计数据库的三大范式(了解) ---表和表的关系
​
```
1NF:最起码的基本要求:每一张表的字段必须独立的列!
2NF
3NF
```
​
## 5.多表查询
​
```
内连接
    隐式内连接
    显示内连接
外连接
    左外/右外 (推荐左外)
子查询: select 嵌套select
    1)聚合函数---和select语句嵌套
    2)in(指定的字段的名称:select语句)子查询
    3)通过select语句---查询来多行多例的数据---(虚表)和另一张表 进行多表查询
```
​
​

MYsql2

​
-- DQL语句其他的语法
-- 条件查询---in关键字 (值1,值2,值3,,,值n) ; 代表多个or连接(多个并集查询)
-- 需求:查询student3表中年龄是18或者30或者45岁的学生的所有信息
SELECT 
  * 
FROM
  student3 
WHERE age = 18 
  OR age = 30 
  OR age = 45 ;
  
SELECT 
  * 
FROM
  student3 
WHERE age IN(18,30,45) ; 
​
-- 条件查询:查询指定的字段是null的信息
-- select 字段列表 from 表名 where 某个字段名称 is null ;
-- 需求:查询student3表中english是null的学生的所有信息
/*
select 
  * 
from
  student3 
where english = null ; -- 错误语法
*/
SELECT 
*
FROM 
student3
WHERE english IS NULL ;
​
-- 查询某个字段不是null的信息: is not null 
-- 需求: 查询英语成绩不是null的学生的所有信息
SELECT 
  * 
FROM
  student3 
WHERE english IS NOT NULL ;
​
-- DQL语句之排序查询
-- select 字段列表 from 表名 order by  字段名称  排序规则;
-- 排序规则:默认值asc :升序 
--      desc:降序
-- 多个排序条件
-- select 字段列表 from 表名 order by 字段名称1 排序规则,字段名称2 排序规则...;
​
-- 需求:按照学生的数学成绩升序排序
SELECT 
  * 
FROM
  student3 
ORDER BY math ASC ;-- 默认不写,asc
​
​
-- 需求:查询学生的所有信息,同时 数学成绩降序,英语成绩升序 获取学生所有信息
SELECT 
  * 
FROM
  student3 
ORDER BY math DESC,
  english ASC ;
  
  
-- 需求:查询数学成绩大于70分的学生的所有信息并且进行升序排序
-- where 在 order by的前面 
SELECT 
*
FROM 
student3
WHERE math > 70
ORDER BY math ASC ;
​
​
-- DQL语句之分组查询:group by
/**
 group by 后面跟分组字段,在select的时候-查询分组字段
    聚合函数在group by的后面不能使用
*/
​
-- select 字段列表 from 表名 group by 字段名称;    -- 分组基本查询
-- 一般情况:group by 和where 搭配使用
​
​
-- 需求:按照性别分组,查询数据成绩大于70分的信息;
-- 数学成绩的大于70分的人参与分组,查询出每一组的数学平均分
/*
select 
 sex '性别'
from 
student3 
group by sex 
where 
   math > 70 ;
*/
-- 先满足条件:当前where 和group by一块使用,先执行where ,然后在执行group by 分组字段;
SELECT 
  sex '性别',
  AVG(math) 
FROM
  student3 
WHERE math > 70 
GROUP BY sex ;
​
-- 筛选having 
/*
    一个sql语句,where条件,有分组group by ,有having(它的后面可以跟聚合函数)
    依次先后顺序,先满足where,在分组,分组基础上进行筛选
*/
-- 需求:查询(分组信息/数学平均分/人数大于2的) 学生的数学成绩大于70分的参与分组(按照性别分组)
-- 同时,筛选出某组人数大于2的一组!
SELECT 
  sex '性别', -- 查询分组字段
  AVG(math) '数学平均分',
  COUNT(id) '总人数'  -- 查询满足筛选条件的信息
FROM
  student3 
  
WHERE math > 70 
GROUP BY sex 
HAVING 
COUNT(id)> 2 ;
​
​
-- DQL语句分页查询
-- limit关键字
-- 语法:select 字段列表 from  表名 limit 起始行数,每页显示的条数;
-- 起始行数:从0开始 --- = (当前页码数-1)*每页显示的条数;
​
-- 实际开发中:页码数currentPage/每页显示的条数pageSize (必须已知数据:前端传来的)
​
-- student3:9条数据,已知:每页显示2条,
-- student3的第一页的数据;
SELECT * FROM student3  LIMIT 0,2 ;
-- 第二页数据
SELECT * FROM student3 LIMIT 2,2 ;
-- 第三页数据
SELECT * FROM student3 LIMIT 4,2;
-- 第四页数据
SELECT * FROM student3 LIMIT 6,2 ;
-- 第五也数据
SELECT * FROM student3 LIMIT 8,2;
​
-- 查询 这个表的时候限制指定的条数
-- select * from 表名 limit 值;
SELECT * FROM student3 LIMIT 4;
​
​
-- 数据库的备份和还原
/*
 DBA(数据库管理员) 设计完数据库,对库中的所有的数据以及结构进行备份;
 防止数据库的信息丢失等等
 数据库还原:就是将备份库 加载已知存在的库中(使用备份好.sql脚本文件,执行这个sql脚本)
    备份和还原:
        1)命令行方式的备份(dos管理员的运行)
            mysqldump -uroot -p输入密码 库名称 > 指定磁盘路径 "d:\\mysql_dump\\xx.sql文件"
        1)命令行方式的还原:
            1.1)dos登录mysql,将之前的库删除
            1.2)新建一个新的库,使用库
            1.3)source  执行本地或者远程路径上的.sql文件 (加载指定的sql脚本文件)
            
       
        2)使用图形界面化工具去备份和还原
        
        任何的图形界面化工具都是一样的
        备份:
            在已知的库上右键---backup--->backup SQL 备份到本地磁盘上的sql脚本
         还原:删除已知库,新建库,使用库,  存在库上右键--->import--->选择执行 execute SQL script 本地sql文件
         
​
*/
CREATE DATABASE myee_2302;
​
​
​
​
​
​
​
  
​
  
-- 修改id为5的学生的英语成绩
UPDATE student3 SET english = 91 WHERE id = 5;  
-- 添加学生
INSERT INTO student3 VALUES(9,'高圆圆',44,'女','西安',86,100) ;
SELECT * FROM student3;
​
​
​
​
--  2.数据库的约束
-- 约束:限制用户操作数据库的行为
-- 举例:插入数据的时候,直接插入null值(这个字段是业务字段,是null,,没有意义)
-- 通过约束将上面的用户插入非法数据的行为进行限制!
​
-- 2.1默认约束:default
CREATE  TABLE test(
    id INT, -- 编号
    NAME VARCHAR(10), -- 姓名
    gender VARCHAR(3) DEFAULT '女' -- 性别  使用默认约束default关键字
) ;
​
INSERT INTO test VALUES(1,'高圆圆','女'),(2,'文章','男') ;
-- 插入部分字段
-- insert into test(id,name) values(3,'张佳宁') ; -- 没有插入的数据null值(没有意义)
-- 添加默认约束后,没有插入的字段:默认约束default起作用!
INSERT INTO test(id,NAME) VALUES(3,'张佳宁') ; 
INSERT INTO test(id,NAME,gender) VALUES(4,'刘亦菲',NULL) ; -- 直接插入null值,default无法约束
​
​
DROP TABLE test;
​
​
-- 2.2 非空约束not null
CREATE TABLE test(
    id INT ,       -- 编号
    NAME VARCHAR(10) NOT NULL , -- 姓名 不能为空
    address VARCHAR(50) NOT NULL -- 地址 不能为空
);
​
INSERT INTO test VALUES(1,'张三丰','武当山'),(2,'令狐冲','泰山') ;
-- 用户直接插入null值(非法数据),加入约束之后:Column 'name' cannot be null
INSERT INTO test VALUES(3,'王五','西安') ;
-- insert into test(id,name) values(4,'李国栋') ;-- 非空约束,不给字段数据,会出现错误
​
-- sql更改表中默认约束(去掉默认约束)
-- 删除name字段非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10) ;
​
-- sql 添加字段的not null非空约束
ALTER TABLE test MODIFY NAME VARCHAR(10)  NOT NULL ;
-- insert into test values(4,null,'咸阳') ;
​
​
DROP TABLE test;
​
-- 2.3 唯一约束unique不能重复
CREATE TABLE test(
    id INT,     -- 编号
    NAME VARCHAR(10), -- 姓名
    telephone VARCHAR(11) UNIQUE -- 手机号 创建表,给手机号添加唯一
) ;
​
INSERT INTO test VALUES
(1,'高圆圆','13366668888'),
(2,'文章','18788886666') ;
​
-- 插入一个数据 
-- (非法数据了手机号或者邮箱/能够去代表身份信息必须唯一的!)
-- 如果使用手机号获取用户信息:获取不到了!
 INSERT INTO test VALUES(3,'李国栋','13366668888') ; -- Duplicate entry '13366668888' for key 'telephone'
​
-- 通过sql语句更改表,删除唯一删除
-- 错误语法: alter table test modify telephone varchar(11) ;
-- 正常语法:alter table 表名 drop index 唯一约束的名称 (默认和当前的字段名称一致)
ALTER TABLE test DROP INDEX telephone ;
​
-- 通过sql添加唯一约束
-- alter table 表名 add constraint(声明) 唯一约束索引的名称  unique(给哪个字段名称);
ALTER TABLE test 
  ADD CONSTRAINT unique_telephone UNIQUE (telephone) ;
​
​
-- 2.4 主键约束 primary key 
/*
    特点:非空且唯一
    不能直接插入null值,不能重复
    
primary key 作用每一张表的id(非业务字段,设置为主键)
*/
CREATE TABLE test(
    id INT PRIMARY KEY AUTO_INCREMENT,  -- 创建表的时候添加主键,同时自增长
    NAME VARCHAR(10)
);
-- insert into test values(1,'张三'),(2,'李四') ;
​
INSERT INTO test(NAME) VALUES('张三'),('李四') ;
INSERT INTO test VALUES(1,'王五') ;-- id重复 无法添加
INSERT INTO test VALUES(NULL,'赵六') ;-- 直接插入null值 .无法获取
​
-- sql语句直接主键删除
-- alter table 表名 drop primary key ; -- 将唯一删除,not null非空还存在
ALTER TABLE test DROP PRIMARY KEY  ;
​
-- sql语句添加主键约束(唯一特性加上)
-- alter table 表名 modify id int PRIMARY KEY ;
ALTER TABLE test MODIFY id INT PRIMARY KEY ;
​
-- 一般主键约束和自增长约束auto_increment,一块用
-- 插入数据insert into 之后,id值不断自增1!
​
-- id为2的值改成10
UPDATE test SET id = 10 WHERE id = 2 ;
INSERT INTO test (NAME) VALUES('高圆圆') ;
​
DROP TABLE test ;
​
SELECT * FROM test ;
​
​
-- 2.5 外键约束 foreign key 
-- 创建一个员工表employee
CREATE TABLE emplyee(
    id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
    NAME VARCHAR(10),          -- 员工姓名
    gender VARCHAR(3) ,                -- 员工性别
    salary  DOUBLE,                    -- 员工工资
    dept_name VARCHAR(10)              -- 员工所在的部门名称
) ;
​
INSERT INTO emplyee(NAME,gender,salary,dept_name)
VALUES('高圆圆','女',8000.0,'测试部'),
('文章','男',6500.0,'运维部'),
('李国栋','男',10000.0,'开发部'),
('马保国','男',6000.0,'安保部'),
('张三丰','男',9500.0,'开发部'),
('邓超','男',7000.0,'运维部'),
('张佳宁','女',9500.0,'测试部');
​
​
SELECT * FROM emplyee ;
-- 查询员工的姓名以及它部门名称信息
SELECT 
 NAME '员工姓名',
 dept_name '部门名称'
FROM emplyee ;
​
-- 问题:查询员工信息,部门名称查询"字段冗余",大量重复数据不友好!
-- 如何优化呢, 创建两张表,分别描述两件事情:一个部门表:描述部门名称 
                     -- 一个员工表:描述员工信息
DROP TABLE emplyee ;
​
-- 创建一张部门表:id:部门编号   dept_name:部门的名称
CREATE TABLE dept(
    id INT PRIMARY KEY AUTO_INCREMENT, -- 部门编号
    dept_name VARCHAR(10)              -- 部门名称
)   ;                
-- 插入部门
INSERT INTO dept(dept_name) VALUES ('测试部'),('运维部'),('开发部'),('安保部') ;
​
-- 创建员工表:id 员工编号,name 员工姓名,gender 性别,salary工资,员工所在的部门编号dept_id
CREATE TABLE employee(
    id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
    NAME VARCHAR(10),                  -- 员工姓名
    gender VARCHAR(3),                 -- 员工性别
    salary DOUBLE,                     -- 工资
    dept_id INT                        -- 所在的部门编号
);
INSERT INTO employee
(NAME,gender,salary,dept_id)
VALUES('高圆圆','女',8000.0,1),
('文章','男',6500.0,2),
('李国栋','男',10000.0,3),
('马保国','男',6000.0,4),
('张三丰','男',9500.0,2),
('邓超','男',7000.0,3),
('张佳宁','女',9500.0,2);
​
-- 新入职一个员工
INSERT INTO employee (NAME,gender,salary,dept_id)
VALUES('王宝强','男',12000.0,5) ; 
​
-- 删除员工表
DROP TABLE employee ;
​
--  不存在5号部门,需要建立两张表的关系!
-- 员工表的 dept_id关联dept部门表id字段---外键约束
/*
    外键所在的表---从表的某个字段依赖于主表的主键字段
    
    部门表:主表
    员工表:从表
    
*/
​
​
​
​
CREATE TABLE employee (
  id INT PRIMARY KEY AUTO_INCREMENT,
  -- 员工编号
  NAME VARCHAR (10),
  -- 员工姓名
  gender VARCHAR (3),
  -- 员工性别
  salary DOUBLE,
  -- 工资
  dept_id INT,
  -- 所在的部门编号
  -- 声明 
  CONSTRAINT -- 外键名称:主表名_从表名_fk
  dept_emp_fk -- 外键作用在哪个字段上
  FOREIGN KEY (dept_id) -- 关联
  REFERENCES -- 主表的主键字段(就是id)
  dept(id)
) ;
/*
  有了外键约束,直接操作主表(删除/修改),直接报错!
  因为从表的数据和主表有关联!
    
*/
​
-- 删除id为4号部门
-- delete from dept where id = 4;  -- 4号部门有员工--Cannot delete or update a parent row:
​
-- 将4号部门的员工先删除,(没有关联了),在删除主表数据
DELETE FROM employee WHERE dept_id = 4 ;
DELETE FROM dept WHERE id = 4 ;
​
-- 将1号部门修改为5号部门
-- update dept set id = 5 where dept_name = '运维部' ; -- 也不能直接修改
-- 将2号部门的员工修改为 "其他部门"
UPDATE employee SET dept_id = 2 WHERE  NAME = '高圆圆' ;
-- 修改主表将1号--5号
UPDATE dept SET id = 5 WHERE dept_name = '测试部' ;
UPDATE employee SET dept_id = 5 WHERE NAME = '高圆圆' ;
​
SELECT * FROM dept ;
SELECT * FROM employee ;
​

day34

晨写

# 晨写
​
## 1.分页查询的语法
​
```sql
select 指定的字段列表 from  表名  limit 起始索引,每页显示的条数;
-- 起始索引 = (当前页码数-1)*每页显示的条数;
-- 当前页码数以及 每页显示的条数----前端传过来的数据!
​
-- 后端 pageBean:自定义分页组件
class PageBean<T>{
    private int currentPage;  当前页码
    private int pageSize ; 每页显示的条件
    private int totalPage; 总页数 ---  
                    -- (totalCount % pageSize == 0)?totalCount/pageSize:向上取整;
    private int totalCount ;  总记录数
    private List<T> list ;  分页的列表数据
}
​
```
​
​
​
## 2.通过sql添加/删除为唯一约束的语法
​
```sql
-- 通过sql添加唯一约束
-- 如果在创建表的时候,没有设置唯一约束名称,默认和字段名称一致;
alter table 表名 add constraint <唯一约束名称> unique(字段名称) ;
-- 通过sql删除唯一约束
alter table 表名 drop index 唯一约束名称;
```
​
​
​
## 3.通过sql添加外键约束和删除外键约束
​
```sql
-- 添加外键约束
alter table 表名  
            add
            constraint 外键名称(主表名缩写_从表名的缩写_fk)
            foreign key(外键作用字段名称)
            references 主表名(主键id字段) ;
            
-- 删除外键约束
alter table 表名 drop foreign key 外键名称;
```
​
​
​
## 4.模糊搜索的语法
​
```sql
select 指定的字段列表 from 表名 where 字段名称 like '%关键字%' ; -- '关键字%'
```
​
​
​
## 5.反射获取一个类的字节码文件后如何调用成员方法?
​
```java
//获取当前正在运行的这个类Class,字节码文件对象
Class  c = Class.forName("包名.类名") ;
//如果当前类的无参构造方法公共的,直接创建当前类实例
Object obj = c.newInstance();
//通过字节码文件对象获取成员方法所在的Method类对象
Method m = c.getDeclareedMethod("方法名",形式参数类型的.class属性...) ;
//取消Java语言访问检查
c.setAccessiable(true) ;
//调用方法
m.invoke(obj,实际参数和形式参数类型匹配) ;
//有返回值直接返回Object,或者没有返回值,单独调用或者return null;
```
​
​
​
​
​
----
​
----
​
# 今日内容
​
## 1.外键约束---通过sql添加/删除
​
## 2.级联操作CASCADE 
​
```
ON update CASCADE /ON delete CASCADE:级联修改和级联删除
相对在多表中:有外键关系的时候,直接操作主表数据,跟主表相关的从表数据会随之改变
```
​
## 3.多表关系(设计数据库的三大范式:了解设计数据库注意事项)
​
```
一对多:
多对多:
一对一:一种特例:
1NF
2NF
3NF
```
​
## 4.多表查询
​
```
笛卡尔乘积查询: 
            A表 3条记录
            B表 5条件记录
            不设置多张表的连接条件---->15条数据
内连接
    隐式内连接---where 条件1 and 添加2  and 添加3....
    显示内连接 表名1  (inner) join   表名2  on 连接条件
外连接
    左外: left (outer) join
         right (outer) join
子查询 
        select 嵌套 select
        利用聚合函数--查询出来的单行单列的数据和比较运算符 (完成嵌套)
        
        条件字段名称  in(嵌套selct...)
        
        (select 指定字段列表 from 表名)----> 虚表 和另一种张进行连接条件
        
```
​
## 5.数据库的事务

mysql_3

-- 通过sql删除外键约束
​
-- alter table 表名 drop foreign key 外键名称 ;
ALTER TABLE employee DROP FOREIGN KEY dept_emp_fk;
​
-- 测试是否删除了外键
INSERT INTO employee(NAME,gender,salary,dept_id)
VALUES('张艺兴','男',5000.0,4) ;
DELETE FROM employee WHERE id = 9 ;
​
-- 通过sql 添加外键约束
/*
    alter table 表名 add
        constraint 外键名称
         foreign key  (外键作用从表的字段名称)
         references 主表名(主键字段) ;
*/
​
ALTER TABLE employee 
  ADD CONSTRAINT de_em_fk FOREIGN KEY (dept_id) REFERENCES dept(id) ;
  
 
-- 级联操作:CASCADE(修改以及删除主表数据,从表数据随之改变)
-- 级联删除和级联修改 
-- 情况1:创建表的时候添加外键的同时后面添加级联删除以及级联修改
/*
CREATE TABLE employee (
  字段名称1 字段类型1,
  字段名称2 字段类型2,
  ....,
  
  dept_id INT,  -- 外键要作用的字段名称
  -- 所在的部门编号
  -- 声明 
  CONSTRAINT 
  外键名称  -- 外键名称:主表名_从表名_fk
  FOREIGN KEY (外键作用的从表的字段名称)  -- 外键作用在哪个字段上
  
  REFERENCES -- 关联
  主表名(主键字段)-- 主表的主键字段(就是id)
  on update cascade 
  on delete cascade 
) ;
*/
​
CREATE TABLE employee (
  id INT PRIMARY KEY AUTO_INCREMENT,
  -- 员工编号
  NAME VARCHAR (10),
  -- 员工姓名
  gender VARCHAR (3),
  -- 员工性别
  salary DOUBLE,
  -- 工资
  dept_id INT,
  -- 所在的部门编号
  -- 声明 
  CONSTRAINT -- 外键名称:主表名_从表名_fk
  dept_emp_fk -- 外键作用在哪个字段上
  FOREIGN KEY (dept_id) -- 关联
  REFERENCES -- 主表的主键字段(就是id)
  dept(id)
  
  ON UPDATE CASCADE     -- 级联修改
  ON DELETE CASCADE     -- 级联删除
) ;
​
DROP TABLE employee ;
​
-- 删除5号部门
DELETE FROM dept WHERE id =  5;
-- 将部门表id为2的部门修改为 id=4的部门
UPDATE dept SET id = 4 WHERE id = 2 ;
 
 
-- 通过sql添加外键的同时,设置级联操作(级联修改和级联删除)
/*
    alter table 表名 add
        constraint 外键名称
         foreign key  (外键作用从表的字段名称)
         references 主表名(主键字段)
         on update cascade
         on delete cascade ;
*/ 
  
​
SELECT * FROM dept ;
SELECT * FROM employee ;
​
​
-- 表和表的关系问题
/*
    一般情况:两张表一个外键
    两张表以上以上,可以设置多个外键
    
    一对多
            部门和员工的关系
            从部门维度--->一个部门中包含多个员工
            从员工维度---> 一个员工从属于某个部门
            
            用户和订单
                一个用户(用户维度):一个用户可以下多个订单
                订单(订单维度):一个订单在某个时刻属于某个用户的
                        一个订单可以可以从属于多个用户的
                
    多对多
            学生表和选课表
            一个学生可以选择多个课程
            一个课程被多个学生选择
            
            用户表和角色表   (用户表和角色表中间表)
            
                从用户维度--看角色:一个用户有多个角色
                从角色维度--看用户:一个角色赋予多个用户
            角色表和权限表  (角色表和权限表中间表)
                从角色表维度--看权限:一个角色可以多个权限
                                CEO:crud(添加,查询,修改和删除)
                从权限维度---看角色:一个权限可以被多个角色赋予
                                查询权限:
                                        CEO
                                        hr
                                        root管理员
                                        普通管理员
                                            
    
*/
​
-- 数据库的三大范式:(理论)
-- 1NF:保证数据库表中的每一列是不能在拆分的原子数据项(单独某一列)
​
-- 2NF:在1NF的基础上,数据库表中每一个非主键字段必须完全依赖主键字段
    -- 1)一张表示描述一件事情
    -- 2) 非主键字段必须完全依赖主键字段
    
    
-- 3NF:在2NF基础上,数据库表中每一个非主键字段不能产生传递依赖(必须在2NF上满足非主键字段必须完全依赖主键字段)
-- 表中A字段依赖于B字段,B字段依赖于C字段, ---->A字段依赖于C字段(字段冗余非常大了)
​
​
-- 多表查询
/*
    
    笛卡尔乘积查询: 
            A表 3条记录
            B表 5条件记录
            不设置多张表的连接条件---->15条数据
内连接
    隐式内连接---where 条件1 and 添加2  and 添加3....
    显示内连接 表名1  (inner) join   表名2  on 连接条件
外连接
    左外: left (outer) join
         right (outer) join
子查询 
        select 嵌套 select
        利用聚合函数--查询出来的单行单列的数据和比较运算符 (完成嵌套)
        
        条件字段名称  in(嵌套selct...)
        
        (select 指定字段列表 from 表名)----> 虚表 和另一种张进行连接条件
*/
​
CREATE DATABASE myee2302_db_2;
​
# 创建部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT, -- 部门编号
NAME VARCHAR(20) -- 部门名称
);
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
​
​
# 创建员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT, -- 员工编号
NAME VARCHAR(10),         -- 员工名称
gender CHAR(1),           -- 性别
salary DOUBLE,          -- 工资
join_date DATE,         -- 入职日期
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键) (省略constraint 外键名称)
) ;
​
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙悟空','男
',7200,'2021-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('猪八戒','男
',3600,'2022-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES
('唐僧','男',9000,'2020-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女
',5000,'2021-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女
',4500,'2021-11-14',1);
​
/*
    多表查询:
        最基本的语法:
        select 指定字段名称 from 表名1 ,表名2;
*/
-- 查询员工表中的id,姓名,性别,工资,入职日志以及部门表的部门名称
SELECT
   emp.`id` '员工编号',
   emp.`name`   '员工姓名',
   emp.`gender` '员工性别',
   emp.`salary` '员工工资',
   emp.`join_date` '入职日期',
   dept.`name`  '部门名称'   
FROM
   emp,
   dept;
-- 问题: 员工表就5个人,查询出来15条数据---错误写法
-- 原因: 没有查询的时候,指定两张表的关联关系(存在外键),造成数据紊乱;
-- 迪卡尔乘积:两张表没有建立连接关系,A表的记录数 * B表的记录数----等于总记录数
​
-- .关系数据库中提供了多表查询之内连接---解决笛卡尔乘积问题
/*
​
    多表查询的分析思路:
            1)要查询哪张表
            2)要查询指定表中的哪些字段名称
            3)表和表关系问题 (需要建立连接条件)
*/
-- 内连接的隐式内连接:就是利用where语句完成条件 的拼接(&&,或者and关键字)
-- select 字段列表 from 表名1 ,表名2 where 连接条件1 and....连接条件2....
​
-- 查询员工表中的id,姓名,性别,工资,入职日志以及部门表的部门名称
SELECT 
  e.`id` '员工编号',
  e.`name` '员工姓名',
  e.`gender` '性别',
  e.`salary` '工资',
  e.`join_date` '入职日期',
  d.`name` '部门名称' 
FROM
​
  emp e,
  -- 给表起一个别名
  dept d -- d是部门表的别名
WHERE e.`dept_id` = d.`id` ;
​
​
-- 显示内连接 --inner join
-- select 字段列表 from 表名1 (inner) join 表名2  on  连接条件1 and 连接条件2.....
​
-- 需求:查询员工表名的姓名,工资,入职日期以及部门表的部门名称
SELECT 
  t1.`name` '员工姓名',
  t1.`salary` '工资',
  t1.`join_date` '入职日期',
  t2.`name` '部门名称' 
FROM
  emp t1 
   INNER JOIN dept t2 
    ON t1.`dept_id` = t2.`id` ;
    
-- 插入一条数据
INSERT INTO emp(NAME,gender,salary,join_date)
VALUES('高圆圆','女',8000,'2018-10-30') ;    
​
​
-- 多表查询之外连接
-- 左外连接/右外连接
-- 一般比较常用的左外连接: 将左边的数据全部查询以及两张表之间的交集数据(连接条件的数据)全部查询!
/*
    select
       指定字段列表
       
    from 表名1 
    left outer join 表名2     / right outer join  右外连接
    on 连接条件
*/
​
-- 需求:查询员工表的所有数据以及部门的部门名称数据,没有部门的员工信息也得查询
SELECT
   t1.*,  -- 查询员工的所有数据
   t2.`id` '部门编号',
   t2.`name` '部门名称' -- 部门名称
FROM
   emp t1
LEFT OUTER JOIN 
   dept t2
ON 
   t1.`dept_id` = t2.`id` ;
    
​
​
-- 多表查询里面的子查询 (就是select嵌套select语句)
-- 情况1:利用聚合函数查询出来的单列的数据和select语句进行嵌套
​
-- 需求:查询最高工资的员工信息以及员工所在的部门信息
-- 1)查询出最高工资是多少
-- select max(salary) from emp ; -- 9000
-- 2)查询员工工资是9000的员工信息以及部门信息
/*
select 
    t1.* , -- 员工所有信息
    t2.*   -- 部门所有信息
from 
   emp t1,
   dept t2
where 
     t1.`salary` = 9000  and t1.`dept_id` = t2.`id`;
     */
     
-- 一步走:
SELECT 
  t1.*,
  -- 员工所有信息
  t2.* -- 部门所有信息
FROM
  emp t1,
  dept t2 
WHERE t1.`dept_id` = t2.`id` 
  AND t1.`salary` = 
  (SELECT 
    MAX(salary) 
  FROM
    emp) ;
    
 -- 需求:查询出来员工工资大于等于平均工资的员工信息(员工姓名,性别,工资,入职日期)同时所在的部门名称信息;
 -- 1)查询出来平均工资是多少
 SELECT AVG(salary) FROM emp ;   -- 6216.67
 -- 2)查询出来员工工资大于等于6216员工的部分信息以及部门名称信息,没有部门的员工信息查询出来
SELECT 
  e.`name` '员工姓名',
  e.`gender` '员工性别',
  e.`salary` '员工工资',
  e.`join_date` '入职日期',
  d.`name` '部门名称' 
FROM
  emp e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`salary` >= 6216 ;  
​
     
-- 一步走
SELECT 
  e.`name` '员工姓名',
  e.`gender` '员工性别',
  e.`salary` '员工工资',
  e.`join_date` '入职日期',
  d.`name` '部门名称' 
FROM
  emp e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`salary` >= 
  (SELECT AVG(salary) FROM emp) ;
​
INSERT INTO emp(NAME,gender,salary,join_date) VALUES('文章','男',7000.0,'2020-05-01') ; 
  -- 如果提示:仅仅没有部门的员工的也需要查询出来,使用左外连接
SELECT 
  e.`name` '员工姓名',
  e.`gender` '员工性别',
  e.`salary` '员工工资',
  e.`join_date` '入职日期',
  d.`name` '部门名称' 
FROM
  emp e 
  LEFT JOIN dept d 
    ON e.`dept_id` = d.`id` -- 作为两张表的连接条件
WHERE e.`salary` >= -- 附件条件
  (SELECT 
    AVG(salary) 
    
  FROM
    emp) ;
​
​
-- 查询出在财务或者市场部的员工的信息以及部门名称信息
-- 1)查询财务部和市场部id 是多少
SELECT 
  id 
FROM
  dept 
WHERE NAME = '市场部' 
  OR NAME = '财务部' ;
  
-- 2)利用子查询 in(值1,值2,值3集合数据) ;
-- 查询在2或者3号部门的员工信息以及部门名称信息
SELECT 
  e.*,
  d.`id`   '部门编号',
  d.`name` '部门名称' 
FROM
  emp e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`dept_id` IN (2, 3) ;
  
-- 一步走
SELECT 
  e.*,
  d.`id` '部门编号',
  d.`name` '部门名称' 
FROM
  emp e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`dept_id` IN 
  (SELECT 
    id 
  FROM
    dept 
  WHERE NAME IN('市场部','财务部') ) ;
  
-- 多表查询子查询的情况3:
-- 将某张表select的结果集---当做一张虚表和其他表建立连接查询
​
-- 需求:要查询出员工入职日期大于2021-10-07的员工的所有信息以及它的部门信息;
-- 查询员工入职日期大于  2021-10-07的员工所有信息 (查询出来的结果集当作 "虚表")
​
SELECT 
  t1.*,
  -- 所有的部门信息
  t2.* -- 所有员工信息
FROM
  dept t1 
  INNER JOIN 
    (SELECT 
      * 
    FROM
      emp 
    WHERE emp.`join_date` > '2021-10-07') t2 
    ON t1.`id` = t2.`dept_id` ;
    
    
 -- 优化隐式内连接
SELECT 
  e.*,
  d.* 
FROM
  emp e,
  dept d 
WHERE e.`dept_id` = d.`id` 
  AND e.`join_date` > '2021-10-07' ;
SELECT * FROM dept ;
SELECT * FROM emp;
​
​
​
​
-- 数据库的事务
/*
    什么是数据库的事务?
事务就是DBA(数据库管理员)操作多个sql的时候,可能有一条执行语句可能异常了,其他sql不执行了,就会导致出现紊乱,
将整个sql(多个sql)的执行看成一个"整体",要么同时执行成功,要么同时执行失败!
始终保证的数据的一致性(高并发中,读/写)
​
*/
-- 创建一个账户表account
CREATE TABLE account(
    id INT PRIMARY KEY AUTO_INCREMENT, -- 账户id
    NAME VARCHAR(10)         , -- 账户名称
    balance INT                        -- 账户余额
);
​
​
-- 插入两个账户信息
INSERT INTO account(NAME,balance) VALUES('zhangsan',1000),('lisi',1000) ;
​
​
-- zhangsan 给 lisi转账500
UPDATE account SET balance = balance - 500 WHERE id = 1 ;
-- 出问题了,这块不执行了
UPDATE account SET balance = balance + 500 WHERE id = 2 ;
​
​
UPDATE account SET balance = 1000 ;
​
-- 将 "转账业务"看成一个整体,
-- 开启事务
START TRANSACTION ; -- 将自动提交切换为手动提交
UPDATE account SET balance = balance - 500 WHERE id = 1 ;
 -- 出问题了,这块不执行了
UPDATE account SET balance = balance + 500 WHERE id = 2 ;
​
-- 有问题回滚;事务回滚:撤销之前的所有操作,默认回滚到执行更新之前的数据
ROLLBACK ;
​
-- 没有问题,正常提交事务
​
COMMIT ; -- 不提交,不会永久性的更改数据---
​
​
​
-- 传统事务特点(重点)ACID
-- 原子性:执行的某业务操作,同时操作多个sql(增删改),要么同时执行成功,要么同时执行失败!
-- 一致性:在实际开发中,多个线程同时去写和读的时候,数据必须一致性 
-- 隔离性:事务和事务之间(业务和业务之间)相互独立的, 互不影响! 
     
-- 持续性:就是对增删改这些sql语句,一旦事务提交了,对数据库中表的操作是永久性,即使关机了,数据永久保存!
​
​
​
​
​
-- 传统事务的隔离级别:
-- 查询数据库的隔离基本
SELECT @@tx_isolation;  -- mysql8.0服务器版---SELECT @@transaction_isolation
-- 设置隔离级别
-- set global transaction  isolation level  (级别的名称) ;
​
    -- 执行效率从大到小,安全性:从低到高
-- 读未提交:read uncommited; 
    /*
         一个事务读取到另一个没有没有提交的事务(最不安全),出现"脏读" (最严重的问题!)
    */
    
-- 读已提交:read committed; 
    /*
    有效防止脏读! 会出现另一种问题"不可重复读",
    
    读取到自己本身没有提交的事务的数据前后两次不一致,本身这个事务没有提交,多次读取到的数据必须一致!
    */
            
​
-- 可重复读  :mysql的默认隔离级别 (repetable-read)
        /*
            有效防止脏读,不可重复读,可能出现"幻读"
        */
-- 串行话:serializable
        
​
​
​
​
​
SELECT * FROM account ;
​
​
​

day35

晨写

​
​
​
​
# 晨写
​
## 1.什么是事务?
​
```markdown
    关系型数据库中--支持"多事务",都会在事务机制,当某个业务同时操作多个sql语句或者是多张表的sql插入/删除/修改),这多个sql要么同时执行成功,要么同时执行失败,保证数据的完整性!
```
​
## 2.事务的特点和事务的隔离级别
​
```markdown
事务的特点
    原子性:多个sql要么同时执行成功,要么同时执行失败,保证数据的完整性!
    一致性:事务同时去操作多个sql的时候,需要保证数据的一致性!
    隔离性:多个事务(业务和业务之间)之间互相独立的,互不影响
    持久性:当事务一旦提交,对数据的更改是永久性的,即使关机也存在!
事务的隔离级别:
    -- 下面依次从小到大,安全性低大高,效率:从高到低;
    read uncommitted ; 读未提交
    read committed ;  读已提交
    repetable read ; 可重复读       mysql的默认级别:有效防止脏读以及不可重复读
    serializable ;  串行话
```
​
## 3.mysql多表查询内连接和左外连接的语法
​
```sql
-- 隐式内连接
select 指定的字段名称  from  表名1,表名2 where 条件1 and 条件2.... ;
-- 显示内连接
select 指定的字段名称  from  表名1 inner join 表名2  on  连接条件;
-- 左外连接语法:将左表数据全部查询以及它们的交集部分的数据
select 指定的字段名称  from   表名1 left outer join 表名2  on 连接条件  where 附件条件..
​
```
​
​
​
## 4.数据库的三大范式描述
​
```markdown
1NF:
    数据库表中的每一列是独立,不能在拆分的原子数据项
2NF:
    在1NF基础上
    1)数据库指定表中,描述一件事情(一张表描述一件事情)
    2)数据库表中的非主键字段必须完全依赖主键字段
3NF:
    在2NF基础上         
    数据库表中非主键字段之间不能产生传递依赖!
    非主键字段A---字段B---->字段C :产生传递依赖        
    -- 解决冗余:比如多对多---拆分中间表:设置外键连接
    
```
​
## 5.通过mysql指令如何控制事务
​
```sql
-- 开启事务:将mysql自动提交,切换手动提交事务
start transaction ;
-- 设置回滚命令
rollback;
-- 永久更新数据(保证数据的持久性)
commit ;
​
-- 设置隔离级别
set global transaction isolation level 级别名称;
-- 查看隔离级别
select @@tx_isolation ;
```
​
-----
​
-------
​
# 今日内容
​
## 1.JDBC入门
​
```
什么是jdbc?
jdbc的本质是什么?
​
```
​
## 2.jdbc的操作步骤 (DDL,DML :插入/update/delete)
​
```markdown
1)导入驱动包
2)注册驱动
3)准备好sql语句
4)获取数据库的连接对象Connnection
5)通过连接对象获取执行对象:Statement
6)执行静态sql
7)释放资源---Connection Statement都必须释放
```
​
### 2.1 单元测试---junit完成单元测试
​
```
自己导入junit的jar包完成单元测试
测试:
    白盒  :技术含量---测试人员懂 java基础,python基础...需要写测试用例
                功能性测试:
    黑盒  :没有技术含量的 
```
​
​
​
## 3.jdbc操作(Statement)查询sql语句 
​
```
查询select语句----将select语句的结果集的数据表---存储在jdk提供ResultSet
遍历数据,获取数据----自己封装数据!
```
​
​
​
## 4.mysql视图 (view) : (掌握基础指令)
​
```
通过查询的select结果集----存储在虚拟视图中,提高数据的安全性!
虚拟表(视图) --- 基础表(真实存在的表)
create view 视图名称 as <select语句>
```
​
​

jdbc入门

package com.qf.jdbc_01;
​
import java.sql.Connection; // 全部是接口下的java.sql.xx
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
/**
 * @author 高圆圆
 * @date 2023/4/4 10:03
 *
 * jdbc入门
 */
public class JdbcDemo {
    public static void main(String[] args) throws ClassNotFoundException,
            SQLException {
        //1)导入驱动包
        //2)注册驱动
        Class.forName("com.mysql.jdbc.Driver") ;//mysql-5.1xxxjar包
        //DriverManager.registerDriver( new com.mysql.jdbc.Driver());
        //3)准备sql语句
        String sql = "insert into account(name,balance) values('文章',1000);" ;
        //4)获取数据库的连接对象
        //jdk提供了类DriverManager:管理jdbc服务的
        /**
         * public static Connection getConnection(String url, 统一资源定位符:连接的具体库
         *                                        String user,  用户名
         *                                        String password)登录mysql的密码
         *                                 throws SQLException
         */
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/myee2302_db_2",
                //jdbc协议:数据库协议://域名:端口号/库名
                //如果使用mysql8.0的jar包(mysql-server:安装的是8.0)此时后面带上一些参数:时区以及编码格式
                //jdbc:mysql://localhost:3306/myee2302_db_2?characterEncoding=utf-8&timezone=utc
                "root",
                "123456");
​
​
        //5)通过数据库的连接对象获取执行对象
        //java.sql.Connnection接口---->Statement createStatement()
        Statement stmt = conn.createStatement();
        //6)执行对象执行sql
        //java.sql.Statemnt--->通用方法:更新操作(插入/修改/删除)
        //int executeUpdate(String sql)throws SQLException
        int count = stmt.executeUpdate(sql);
        System.out.println("影响了"+count+"行");
        //7)释放资源
        stmt.close() ;
        conn.close();
    }
}
package com.qf.jdbc_01;
​
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
​
/**
 * @author 高圆圆
 * @date 2023/4/4 11:31
 * jdbc操作DDL语句,创建一张表 student
 *                              id int ,name varchar(10),age int,gender varchar(3),address varchar(50),
 *
 */
public class JdbcDemo2 {
    public static void main(String[] args) {
        //捕获异常
        //1)导包
        //2)注册驱动
        Connection conn = null ;
        Statement stmt = null ;
        try {
            Class.forName("com.mysql.jdbc.Driver") ;
            //3)获取数据库连接对象
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/myee2302_db_2",
                    "root",
                    "123456");
            //4)准备sql
            String sql = "create table student(" +
                    "id int primary key auto_increment," +
                    "name varchar(10)," +
                    "age int," +
                    "gender varchar(3)," +
                    "address varchar(50));";
            //5)通过连接对象获取执行对象
            stmt  = conn.createStatement();
            //6)执行更新操作 DDL语句 executeUpdate(String sql)
            int count = stmt.executeUpdate(sql);
            System.out.println(count);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            if(stmt!=null){
                try {
                    stmt.close() ;
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
            if(conn!=null){
                try {
                    conn.close() ;
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
            }
​
        }
​
    }
}
​

jdbc操作过程中的api

​
JDBC七大步骤
1.导包
    mysql5.1的jar包---com.mysql.jdbc.Driver 驱动类
    mysql8.0的jar包---com.mysql.cj.jdbc.Driver 驱动类
​
2.注册驱动
    本身注册驱动的写法:
    jdk提供的DriverManager驱动管理类:管理jdbc服务的
    public static void registerDriver(Driver driver)throws SQLException 注册驱动
                参数:java.sql.Driver接口
     书写代码中不需要上面的这个步骤
​
     因为
        com.mysql.jdbc.Driver 这个类里面已经注册驱动了
                里面有静态代码块
                static {
                        try {
                            //注册驱动
                            java.sql.DriverManager.registerDriver(new Driver());
                        } catch (SQLException E) {
                            throw new RuntimeException("Can't register driver!");
                        }
                    }
​
​
​
     Class.forName("com.mysql.jdbc.Driver") ;  获取正在运行的这个类的字节码文件对象:
        1)加载这个类会执行com.mysql.jdbc.Driver这个类的staitc静态代码块,立即注册驱动!
        2)为了向下兼容!
​
​
  3.准备sql语句---定义String类型,里面书写插入/修改/删除
  静态sql语句,里面的参数要么键盘录入,要么直接给值,存在字符串拼接!
  String sql = "insert into account(name,balance) values('文章',1000);" ;
​
  4.获取数据库的连接对象 java.sql.Connnection
  java.sql.DriverManager类:
       提供静态方法:
       public static Connection getConnection(String url,
                                              String user,
                                              String password)
                                       throws SQLException
        url:统一资源定位符
            jdbc:mysql://本地默认localhost或者127.0.0.1:端口号/库名    (mysql驱动包5.1jar包这个地址不需要带参数)
                                                                    mysql驱动包8.0jar包后面带参数
            jdbc:mysql://本地默认localhost或者127.0.0.1:端口号/库名?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
                                                                       编码格式/是否启用证书(不启用,都是默认密码登录)/时区/是否允许数据库公钥验证(默认true):验证登录的密码
            端口号:3306 (mysql)
        user:用户名:
        password:登录mysql的密码
​
  java.sql.Connection:接口:代表的与特定数据库的连接会话
​
  获取执行对象执行静态sql语句
        Statement createStatement()
​
  java.sql.Statement:在数据库中执行sql语句的接口
​
            针对DML语句(insert into/delete/update) ,直接影响了的行数,返回值int
            针对ddl语句(创建表/修改表/删除表):返回值是0
            int executeUpdate(String sql)throws SQLException
​
            执行DQL语句,数据库查询语句 select语句
​
            ResultSet executeQuery(String sql)throws SQLException
​
  java.sql.ResultSet:获取数据表的结果集  (接口)
        获取查询的多条件记录或者单条记录或者查询单行单列数据....
​
​

jdbc工具类写法

package com.qf.utils;
​
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
​
/**
 * 将jdbc步骤优化
 *       自定义工具类,将获取连接对象,释放资源都放在静态方法中,方便去使用!
 */
public class JdbcUtils {
    //统一资源定位符
    private static String url = null ;
    //用户名
    private static String user = null ;
    //密码
    private static String password = null ;
    //驱动类
    private static String driverClassName = null ;
​
    //定义静态代码块
    static{
        try {
            //1)读取src下面的jdbc.properties文件
            //创建一个属性集合列表
            Properties prop = new Properties() ;
            //System.out.println(prop) ;
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //将字节输入流加载到属性集合列表中
            prop.load(inputStream) ;
            //System.out.println(prop) ;
            //2)通过key获取value
            driverClassName = prop.getProperty("driverClassName");
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");
​
            //3)注册驱动
            Class.forName(driverClassName) ;
​
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
​
    //对外私有,不让外界new
    private JdbcUtils(){}
​
​
    //定义公共的静态方法,返回值就是Connection
    //public static Connection getConnection(String url,String user,String password){ //一会还得需要传入参数,
    public static Connection getConnection(){ //一会还得需要传入参数,
        Connection conn = null ;
        try {
           conn = DriverManager.getConnection(url,user,password) ;//url,user,password
            return  conn;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;
    }
​
​
    //释放资源
​
    public static void  close(ResultSet rs,Statement stmt,Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
​
    //主要针对DDL/DML语句操作释放资源
    public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }
​
    public static void main(String[] args) {
​
        Connection conn = JdbcUtils.getConnection();
        System.out.println(conn);
    }
}
package com.qf.jdbc_02;
​
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
​
/**
 * 测试自定义的工具类给myee2303_db_2库中student添加一条数据
 */
public class JdbUtilsTest {
    public static void main(String[] args) throws SQLException {
​
        //1)导包/注册驱动/获取直接对象
        Connection conn = JdbcUtils.getConnection();
        //2)sql
        String sql = "insert into student(name,age,gender,address)" +
                "values ('张三丰',25,'男','西安市'),('高圆圆',25,'女','咸阳市');";
​
​
        //3)获取执行对象
        Statement stmt = conn.createStatement();
        //4)执行
        int count = stmt.executeUpdate(sql);
        System.out.println("影响了"+count+"行") ;
        //5)释放资源
        JdbcUtils.close(stmt,conn);
​
    }
}
​
jdbc.properties的内容
    
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/myee2302_db_2
user=root
password=123456

Statement执行对象操作DML语句之修改操作

package com.qf.jdbc_02;
​
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
​
/**
 * Statement执行对象操作DML语句之修改操作
 */
public class Statement_Operator_DML {
    public static void main(String[] args) {
        Connection conn = null ;
        Statement stmt = null ;
        try {
            //获取数据库连接对象
             conn = JdbcUtils.getConnection();
            //准备sql
            String sql = "update student set name = '赵又廷',age = 35,address='西安市南窑国际' where id = 1;" ;
            //获取执行器对象Statement
             stmt = conn.createStatement();
             //执行sql
            int count = stmt.executeUpdate(sql);
            System.out.println("影响了"+count+"行");
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.close(stmt,conn);
        }
    }
}
​

使用Statment执行对象来操作DQL语句,并去将所有的结果集数据表打印在控制台上

package com.qf.jdbc_03;
​
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
​
/**
 * 使用Statment执行对象来操作DQL语句,并去将所有的结果集数据表打印在控制台上
 */
public class Statement_DQL {
    public static void main(String[] args) {
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;
        try {
            //注册驱动并获取连接对象
             conn = JdbcUtils.getConnection() ;
            //准备sql语句
            String sql = "select * from student;" ;
​
            //通过连接对象获取执行对象,准备发送sql到数据库
            stmt = conn.createStatement() ;
            //执行通用的查询操作
            rs = stmt.executeQuery(sql) ;
            //第一次获取
            System.out.println("编号\t姓名\t\t\t年龄\t性别\t地址") ;
            //有下一行数据获取
            //boolean next() ;
       /*     if(rs.next()){
                //列的索引值获取
                int id = rs.getInt(1) ;
                String name = rs.getString(2) ;
                int age = rs.getInt(3) ;
                String gender = rs.getString(4);
                String address = rs.getString(5);
                System.out.println(id+"\t"+name+"\t\t"+age+"\t"+gender+"\t"+address);
            }
​
            //第二次获取
            //通过列的名称获取
            if(rs.next()){
                int id = rs.getInt("id") ; //id名称
                String name = rs.getString("name") ; //name名称
                int age = rs.getInt("age") ; //age名称
                String gender = rs.getString("gender") ; //gender
                String address = rs.getString("address") ; //address
                System.out.println(id+"\t"+name+"\t\t"+age+"\t"+gender+"\t"+address);
            }
​
            //第三次获取
            //通过列的名称获取
            if(rs.next()){
                int id = rs.getInt("id") ; //id名称
                String name = rs.getString("name") ; //name名称
                int age = rs.getInt("age") ; //age名称
                String gender = rs.getString("gender") ; //gender
                String address = rs.getString("address") ; //address
                System.out.println(id+"\t"+name+"\t\t\t"+age+"\t"+gender+"\t"+address);
            }*/
​
            //当不明确多少个结果,while循环
            while(rs.next()){
                //有数据,获取
                int id = rs.getInt("id") ; //id名称
                String name = rs.getString("name") ; //name名称
                int age = rs.getInt("age") ; //age名称
                String gender = rs.getString("gender") ; //gender
                String address = rs.getString("address") ; //address
                System.out.println(id+"\t"+name+"\t\t\t"+age+"\t"+gender+"\t"+address);
            }
​
​
​
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            JdbcUtils.close(rs,stmt,conn);
        }
    }
}
加上面的工具类
    

单元测试类写法

package com.qf.test_04;
​
import com.qf.pojo.Student;
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
​
/**
 * 需求:
 *      将student表中的所有数据查询出来,表中每一条数据封装到Student类中,将这个多条记录
 * 添加到集合中,最终遍历集合,展示ArrayList<Student>里面的数据!
 *
 */
public class DqlTest {
​
    public static void main(String[] args) {
        List<Student> list = getStudents();
        for (Student s : list) {
            System.out.println(s) ;
        }
    }
​
    //获取数据表中的所有数据,添加集合中;
    public static List<Student> getStudents(){
        //创建一个集合
        List<Student> list = null ;
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;
        try {
             list = new ArrayList<>() ;
​
            //注册驱动,同时获取数据库的连接对象
             conn = JdbcUtils.getConnection();
            //sql
            String sql = "select * from student;" ;
            //获取执行对象
            stmt = conn.createStatement() ;
            //执行查询操作
            rs = stmt.executeQuery(sql) ;
            //声明一个学生变量s
            Student s = null ;
            //遍历结果集
            while(rs.next()){
                //有数据行,获取数据
                //封装学生对象
                s = new Student() ;
                s.setId(rs.getInt("id")) ;
                s.setName(rs.getString("name")) ;
                s.setAge(rs.getInt("age")) ;
                s.setGender(rs.getString("gender")) ;
                s.setAddress(rs.getString("address")) ;
​
                //将学生对象添加list集合中
                list.add(s) ;
             }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
​
        return list;
    }
​
}
package com.qf.pojo;
​
/**
 * @author 高圆圆
 * @date 2023/4/4 15:49
 *
 * 学生实体中,属性名称和数据表中的字段对应!
 */
public class Student {
    /**
     * id   int(11) NOT NULL
     * name varchar(10) NULL
     * age  int(11) NULL
     * gender   varchar(3) NULL
     * address  varchar(50) NULL
     */
    //属性字母都是小写,可以有_下划线
            //如果属性 private String NAME ;  大写,后期通过一些"高级jdbc"技术,没有办法封装数据!
    private int id ; //学生编号
    private String name; //姓名
    private int age ; //年龄
    private String gender ; //性别
    private String address ;//地址
​
​
    public Student() {
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public String getGender() {
        return gender;
    }
​
    public void setGender(String gender) {
        this.gender = gender;
    }
​
    public String getAddress() {
        return address;
    }
​
    public void setAddress(String address) {
        this.address = address;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.qf.dao;
​
import com.qf.pojo.Student;
​
import java.util.List;
​
/**
 * 针对学生的数据访问接口
 */
public interface StudentDao {
​
    /*
     * 查询所有学生信息
     * @return 返回学生列表
     */
    List<Student> findAll() ;
​
    /**
     * 添加学生信息
     * @param s 学生实体
     *
     */
    void add(Student s) throws Exception;
​
   // void add(Student s) ;
}
package com.qf.dao.impl;
​
import com.qf.dao.StudentDao;
import com.qf.pojo.Student;
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
​
/**
 * 针对学生的数据访问接口实现
 *
 * dao层: data access Object :数据访问对象! :操作数据库,这一层代码需要抛出throws
 */
public class StudentDaoImpl  implements StudentDao {
    /*
     * 查询所有学生信息
     * @return 返回学生列表
     */
    @Override
    public List<Student> findAll() {
​
        //创建一个集合
        List<Student> list = null ;
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;
        try {
            list = new ArrayList<>() ;
​
            //注册驱动,同时获取数据库的连接对象
            conn = JdbcUtils.getConnection();
            //sql
            String sql = "select * from student;" ;
            //获取执行对象
            stmt = conn.createStatement() ;
            //执行查询操作
            rs = stmt.executeQuery(sql) ;
            //声明一个学生变量s
            Student s = null ;
            //遍历结果集
            while(rs.next()){
                //有数据行,获取数据
                //封装学生对象
                s = new Student() ;
                s.setId(rs.getInt("id")) ;
                s.setName(rs.getString("name")) ;
                s.setAge(rs.getInt("age")) ;
                s.setGender(rs.getString("gender")) ;
                s.setAddress(rs.getString("address")) ;
​
                //将学生对象添加list集合中
                list.add(s) ;
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
​
        return list;
    }
​
    /**
     * 添加学生信息
     * @param s 学生实体
     */
    @Override
    public void add(Student s) throws Exception{ //测试的时候传入学生对象
​
        //注册驱动,同时获取数据库的连接对象
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "insert into student(name,age,gender,address) values('"+s.getName()+"','"+s.getAge()+"','"+s.getGender()+"','"+s.getAddress()+"') ;" ;
        //获取执行对象
        Statement stmt = conn.createStatement() ;
        int count = stmt.executeUpdate(sql);
        System.out.println(count) ;
        JdbcUtils.close(stmt,conn);
    }
}
package com.qf.junit_05;
​
import com.qf.dao.StudentDao;
import com.qf.dao.impl.StudentDaoImpl;
import com.qf.pojo.Student;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
​
import java.util.List;
​
/**
 * 测试学生接口
 *
 * @Test:标记这个方法是单元测试方法
 * @Before:标记的方法:是在执行单元测试之前执行
 * @After:标记的方法:是在执行单元测试之后执行
 */
public class StudentTest {
    private StudentDao sd ; //声明学生接口StudentDAo
    @Before
    public void init(){
        System.out.println("执行单元测试方法之前执行了...");
        sd = new StudentDaoImpl() ;
        System.out.println(sd) ;
    }
​
    @Test
    //测试查询所有的功能 (测试功能是否完整)
    public void testFindAll(){
        System.out.println("进入单元测试方法了");
        //调用功能
        List<Student> list = sd.findAll();
        for(Student s:list){
            System.out.println(s) ;
        }
    }
​
    @Test
    //测试添加学生
    public void testaddStudent() throws Exception {
        //System.out.println("进入单元测试方法了");
        //调用功能
        Student s = new Student() ;
        s.setName("梁飞虎") ;
        s.setAge(23) ;
        s.setGender("男") ;
        s.setAddress("西安市");
        sd.add(s);
    }
​
    @After
    public void close(){
        System.out.println("执行单元测试方法之后执行了...");
    }
}
​

day36

晨写

# 晨写
​
## 1.jdbc的本质是什么?
​
```markdown
Jdbc是一个普通的Java类,是数据库厂商提供的驱动jar包,可以实现sun提供一套接口规范!
    java.sql.Driver:驱动接口---->驱动jar包--->实现了这个接口
    java.sql.Connection:数据库的连接会话--->驱动jar包--->ConnectionImpl实现了这个接口
    ...
```
​
​
​
## 2.jdbc的7大操作步骤,代码体现
​
```java
// 7大步骤 后期--->开源框架:就是对原生Jdbc代码的封装+一些配置文件
//1)导入驱动jar包 --mysql-connnecto-java驱动jar包  
//2)注册驱动
Class.forName("com.mysql.jdbc.Driver") ; 
//3)获取数据库的连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/库名",
"root",
"123456") ;
//4)准备sql语句:DDL语句或者DML语句
String sql = "insert into employee(name,age,gender,birthday,address) values(xxx,xx,xx,xx,xx,xx)" ;
//5)通过连接对象获取执行对象Statement 
Statement stmt  = conn.createStatement() ;
//6)执行sql,通用的更新
int count = stme.executeUpdate(sql) ;
//7)释放资源
stmt.close() ;
conn.close() ;
```
​
​
​
## 3.jdbc针对DQL语句,遍历结果集
​
```java
// 7大步骤 后期--->开源框架:就是对原生Jdbc代码的封装+一些配置文件
//1)导入驱动jar包 --mysql-connnecto-java驱动jar包  
//2)注册驱动
Class.forName("com.mysql.jdbc.Driver") ; 
//3)获取数据库的连接对象
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/库名",
"root",
"123456") ;
//4)准备sql语句:DDL语句或者DML语句
String sql = "select 指定的字段列表  from 表名" ;
//5)通过连接对象获取执行对象Statement 
Statement stmt  = conn.createStatement() ;
//6)执行sql,通用的查询操作
ResultSet rs = stmt.executeQuery(sql) ;
​
//遍历结果集
while(rs.next()){
    //获取数据
    //通用的写,列的名称获取/列的索引值获取
    XXX 变量= rs.getXXX("字段名称") ;
    //自己封装数据...
}
​
//7)释放资源
stmt.close() ;
conn.close() ;
```
​
​
​
## 4.自定义工具类JdbcUtils的步骤
​
```properties
driverClass=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/库名
user=root
password=123456
​
```
​
​
​
```java
class JdbcUtils{
    private static String user = null ;
    private static String password = null ;
    private static String driverClass = null ;
    private static String url = null ;
    
    //定义static代码块
    static{
        //读取配置文件
        Properties prop = new Properties() ;
        //获取key对应的value,赋值给上面四个成员变量
        InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties") ;
        user = prop.getProperty("user") ;
        password = prop.getProperty("password") ;
        url = prop.getPrpperty("url") ;
        driverClass = prop.getProperty("driverClass") ;
        //注册驱动
        Class.forName(driverClass) ;
    }
    
    
 
    private JdbcUtils(){}
    public static Connnection getConnection(){
            Connection conn = DriverManager.getConnection(url,user,password) ;
        return conn ;
    }
    //释放资源
    //带三个参数:ResultSet ,Statment,Connection---针对DQL语句操作
    //带两个参数:Satement,Connection--->针对DML语句
}
```
​
​
​
## 5.junit单元测试的使用步骤
​
```markdown
    1)导入junit的核心包: 4.13.1以及依赖包
    2)建立测试类---XXXTest
    3)定义单元测试方法,在方法上加入@Test 
    4)方法中要么Assert断言,要么直接测试指定功能(XXXDao--->添加,删除,修改,查询的功能)
```
​
​
​
---
​
---
​
# 今日内容
​
## 1.作业:使用Statement完成对一张表的内容增删查改
​
```
员工类
    编号
    姓名
    年龄
    性别
    工资
    ....
EmployeeDao--->针对员工的数据访问接口
        添加员工
        修改员工
        删除员工
        查询所有员工
        通过指定员工编号查询员工...  
        
EmployeeDaoIml---实现
​
定义EmployeeTest--->提供单元测试方法:针对上面所有功能单独测试.... 
```
​
## 2.视图 View(了解)
​
```
虚拟表 (通过建立视图和基础表的内容一模一样)  和基础表(真实存在的数据)
```
​
## 3.使用Statement的弊端
​
```java
使用Statement完成用户登录---------->有一张user表  
                                        id   username   password
    键盘录入用户名和密码,
    User类:private int id;
          private String username;
          private String password;
    定义一个UserDao接口---->boolean isLogin(String username,String password) ;
    userDaoImpl接口实现类----->实现这个业务
                        select * from user where username = 'xxx' and passwod='xxxx'  ; 
纯sql拼接会出现安全漏洞!                      
select * from user where username = 'xxx' and passwod='xxxx' or '1'='1' ;
                        如果查询到了数据---->结果集对象.next()--->返回true
    --- 效率低
    --- 造成sql注入(用户名和随便输入,依然登录成功)
                            
开发中使用:PreparedStatement---执行预编译sql语句    
select * from user where username = ? and passwod=?  ; //? 占位符符号
```
​
## 4.PreparedStatement预编译对象的使用:执行预编译sql语句(重点)
​
```
一条sql:insert into/update/delete /select--->有参数--->全部都是? 占位符号
```
​
## 5.数据库连接池(重点)
​
```
c3p0
dbcp
druid:德鲁伊---->阿里巴巴提供的 (开源的)
        druid.jar包
只是提供数据库连接池---不能连接数据库(要连接数据库---提供mysql驱动jar包)
JdbcUtils就需要优化了
        模拟线程 ThreadLocal<T> :  每一个线程都有自己的Connection
                set(T t):绑定内容
                remove():解绑
                T get() :获取指定的内容
```
​
​
​
​
​
​
​
​
​
​
​
​
​
-----
​
----
​
## Statement和PreparedStatement的区别?
​
```markdown
1)共同点:
    都是可以发送sql到数据库的,都是执行对象,后者继承前者(java.sql.包下的接口)
2)不同点:
2.1)是否会造成sql注入
    Statement永远执行的是静态sql语句:语句中存在"硬编码",存在SQL的字符串拼接,就造成sql注入,不安全!
    PreparedStatement:永远执行的是参数化的sql语句,全部参数都是"?",占位符号,有效防止sql的拼接,预防sql注入,提高执行sql的安全性!
2.2)是否会提高sql执行效率
    Statement:不会提高sql执行效率,
    获取执行对象,然后将sql语句发送数据库(没写一个sql,发一次!),频繁的操作访问数据库
    PreparedStatement:大大提高SQL执行效率
    参数化sql是在获取PreparedStatement,就已经发送给数据库了,然后在PreparedStatement赋值不同的值;
```
​
## 德鲁伊Druid配置文件的参数说明
​
```properties
#这些名称都是DruidDataSoure提供的参数
#连接数据库的驱动类
driverClassName=com.mysql.jdbc.Driver   
#连接数据库的url地址:统一资源定位符
url=jdbc:mysql://localhost:3306/myee2302_db_2
#用户名
username=root
#密码
password=123456
#连接池一旦创建,初始化5个连接数量
initialSize=5
#最大连接数量值:默认值8个,自己设定值,和maxIdel:最大空闲数量相等
maxActive=10
#最大等待时间:为毫秒值,一旦连接池中创建连接对象超过了最大连接数量,等待3秒中,如果还连接不上,连接池会产生错误日志,提示"连接超时"
maxWait=3000
```
​
​

Statement作业讲解+预编译方法

/*
package com.qf.dao.impl;
​
import com.qf.dao.EmployeeDao;
import com.qf.pojo.Employee;
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
​
*/
/**
 * 针对员工的数据接口实现(持久层的实现类---有异常---全部throws)
 *
 * service:业务层:调用dao层代码获取数据---->必须try...catch...捕获
 *
 * dao层: 数据访问----throws抛出
 *//*
​
public class EmployeeDaoImpl  implements EmployeeDao {
​
    */
/**
     * 查询所有员工
     * @return 返回员工列表
     *//*
​
    @Override
    public List<Employee> findAll() throws SQLException {
​
        //创建一个集合
        List<Employee> list = new ArrayList<>() ;
​
        //获取连接对象
        Connection conn = JdbcUtils.getConnection();
        //准备sql语句
        String sql = "select * from employee" ;
​
        //获取执行对象
        Statement stmt = conn.createStatement() ;
        //执行查询
        ResultSet rs = stmt.executeQuery(sql);
        Employee emp = null ;
        //遍历结果集
        while(rs.next()){
            //获取数据,将数据封装员工对象中
            emp = new Employee() ;
            emp.setId(rs.getInt("id")) ;
            emp.setName(rs.getString("name"));
            emp.setGender(rs.getString("gender")) ;
            emp.setAge(rs.getInt("age"));
            emp.setSalary(rs.getDouble("salary")) ;
            emp.setAddress(rs.getString("address"));
            emp.setBirthday(rs.getDate("birthday")) ;
​
            //将所有员工添加到集合中
            list.add(emp) ;
​
​
​
        }
        JdbcUtils.close(rs,stmt,conn);
​
        return list;
    }
​
    */
/**
     * 添加员工
     * @param employee 员工实体
     *//*
​
    @Override
    public void add(Employee employee) throws SQLException {
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "insert into employee(name,gender,age,salary,address,birthday) " +
                "values('"+employee.getName()+"','"+employee.getGender()+"','"+employee.getAge()+"','"+employee.getSalary()+"','"+employee.getAddress()+"','"+employee.getBirthday()+"')" ;
        System.out.println(sql);
        Statement stmt = conn.createStatement();
        int count = stmt.executeUpdate(sql);
        System.out.println(count);
    }
​
    */
/**
     * 通过员工编号删除员工
     * @param id 要传进来的员工id
     *//*
​
    @Override
    public void deleteEmployeeById(int id) throws SQLException {
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "delete from employee where id ='"+id+"' " ;
        System.out.println(sql);
        Statement stmt = conn.createStatement();
        int count = stmt.executeUpdate(sql);
        System.out.println(count);
    }
​
    */
/**
     * 修改员工
     * @param employee 员工实体
     *//*
​
    @Override
    public void updateEmployee(Employee employee) throws SQLException {
​
        Connection conn = JdbcUtils.getConnection();
        //sql
        String sql = "update employee set name = '"+employee.getName()+"',age ='"+employee.getAge()+"',gender='"+employee.getGender()+"',address='"+employee.getAddress()+"' where id = '"+employee.getId()+"' " ;
        System.out.println(sql);
        Statement stmt = conn.createStatement();
        int count = stmt.executeUpdate(sql);
        System.out.println(count);
    }
​
    */
/**
     * 根据员工编号查询员工
     * @param id 员工编号
     * @return 返回员工实体
     *//*
​
    @Override
    public Employee findEmpById(int id) throws SQLException {
​
        //获取连接对象
        Connection conn = JdbcUtils.getConnection();
        //准备sql语句
        String sql = "select * from employee where id = '"+id+"'" ; //id字段主键,自增长
​
        //获取执行对象
        Statement stmt = conn.createStatement() ;
        //执行查询
        ResultSet rs = stmt.executeQuery(sql);
        Employee emp = null ;
        //遍历结果集
        while(rs.next()){
            //获取数据,将数据封装员工对象中
            emp = new Employee() ;
            emp.setId(rs.getInt("id")) ;
            emp.setName(rs.getString("name"));
            emp.setGender(rs.getString("gender")) ;
            emp.setAge(rs.getInt("age"));
            emp.setSalary(rs.getDouble("salary")) ;
            emp.setAddress(rs.getString("address"));
            emp.setBirthday(rs.getDate("birthday")) ;
        }
​
        return emp;
    }
}
package com.qf.dao.impl;
​
import com.qf.dao.EmployeeDao;
import com.qf.pojo.Employee;
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
​
/**
 * @author 高圆圆
 * @date 2023/4/6 14:25
 * 使用PreparedStatement来操作数据库
 */
public class EmployeeDaoImpl2  implements EmployeeDao {
    /**
     * 修改员工
     * @param employee 员工实体
     */
    @Override
    public void updateEmployee(Employee employee) throws SQLException {
       //获取连接对象
        Connection connection = JdbcUtils.getConnection();
        //sql--参数化的sql
        String sql = "update employee set name = ?,gender=?,age=?,salary=?,address=?,birthday=? where id =?" ;
        System.out.println(sql) ;
​
        //获取预编译对象
        PreparedStatement ps = connection.prepareStatement(sql) ;
        //参数赋值
        ps.setString(1,employee.getName()) ;
        ps.setString(2,employee.getGender()) ;
        ps.setInt(3,employee.getAge()) ;
        ps.setDouble(4,employee.getSalary()) ;
        ps.setString(5,employee.getAddress()) ;
​
        ps.setDate(6,new java.sql.Date(employee.getBirthday().getTime())) ;
        ps.setInt(7,employee.getId()) ;
​
        //执行
        int count = ps.executeUpdate();
        System.out.println(count) ;
​
​
    }
}
​
*/
package com.qf.dao;
​
import com.qf.pojo.Employee;
​
import java.sql.SQLException;
import java.util.List;
​
/**
 *针对员工持久层(操作数据库:数据访问接口)
 */
public interface EmployeeDao {
​
    /**
     * 查询所有员工
     * @return 返回员工列表
     */
   // List<Employee> findAll() throws SQLException ;
​
    /**
     * 添加员工
     * @param employee 员工实体
     */
    //void add(Employee employee) throws SQLException;
​
​
​
    /**
     * 通过员工编号删除员工
     * @param id 要传进来的员工id
     */
    //void deleteEmployeeById(int id) throws SQLException;
​
    /**
     * 修改员工
     * @param employee 员工实体
     */
    void updateEmployee(Employee employee) throws SQLException;
​
    /**
     * 根据员工编号查询员工
     * @param id 员工编号
     * @return 返回员工实体
     */
  //  Employee findEmpById(int id) throws SQLException;
}
package com.qf.pojo;
​
import java.util.Date;
​
/**
 * @author 高圆圆
 * @date 2023/4/6 9:47
 * 员工实体
 */
public class Employee {
    /**
     * CREATE TABLE employee(
     *     id INT PRIMARY KEY AUTO_INCREMENT,
     *     NAME VARCHAR(10) ,
     *     gender VARCHAR(3) ,
     *     age INT ,
     *     salary DOUBLE,
     *     address VARCHAR(20),
     *     birthday DATE
     * );
     */
    private int id ;
    private  String name ;
    private String gender ;
    private int age;
    private double salary ;
    private String address ;
    private Date birthday ;
​
    public Employee() {
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public String getGender() {
        return gender;
    }
​
    public void setGender(String gender) {
        this.gender = gender;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public double getSalary() {
        return salary;
    }
​
    public void setSalary(double salary) {
        this.salary = salary;
    }
​
    public String getAddress() {
        return address;
    }
​
    public void setAddress(String address) {
        this.address = address;
    }
​
    public Date getBirthday() {
        return birthday;
    }
​
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
​
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", gender='" + gender + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", address='" + address + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}
package com.qf.utils;
​
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
​
/**
 * 将jdbc步骤优化
 *       自定义工具类,将获取连接对象,释放资源都放在静态方法中,方便去使用!
 */
public class JdbcUtils {
    //统一资源定位符
    private static String url = null ;
    //用户名
    private static String user = null ;
    //密码
    private static String password = null ;
    //驱动类
    private static String driverClassName = null ;
​
    //定义静态代码块
    static{
        try {
            //1)读取src下面的jdbc.properties文件
            //创建一个属性集合列表
            Properties prop = new Properties() ;
            //System.out.println(prop) ;
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //将字节输入流加载到属性集合列表中
            prop.load(inputStream) ;
            //System.out.println(prop) ;
            //2)通过key获取value
            driverClassName = prop.getProperty("driverClassName");
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password") ;
​
            //3)注册驱动
            Class.forName(driverClassName) ;
​
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
​
    //对外私有,不让外界new
    private JdbcUtils(){}
​
​
    //定义公共的静态方法,返回值就是Connection
    //public static Connection getConnection(String url,String user,String password){ //一会还得需要传入参数,
    public static Connection getConnection(){ //一会还得需要传入参数,
        Connection conn = null ;
        try {
           conn = DriverManager.getConnection(url,user,password) ;//url,user,password
            return  conn;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;
    }
​
​
    //释放资源
​
    public static void  close(ResultSet rs,Statement stmt,Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
​
    //主要针对DDL/DML语句操作释放资源
    public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }
​
    public static void main(String[] args) {
​
        Connection conn = JdbcUtils.getConnection();
        System.out.println(conn);
    }
}
package com.qf.test;
​
import com.qf.dao.EmployeeDao;
//import com.qf.dao.impl.EmployeeDaoImpl;
import com.qf.dao.impl.EmployeeDaoImpl2;
import com.qf.pojo.Employee;
import org.junit.Before;
import org.junit.Test;
​
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
​
/**
 * @author 高圆圆
 * @date 2023/4/6 10:03
 */
public class EmployeeTest {
​
    private EmployeeDao employeeDao ;
    @Before
    public void init(){
//        employeeDao = new EmployeeDaoImpl() ;
        employeeDao = new EmployeeDaoImpl2() ;
    }
​
​
    //测试查询所有员工
    /*@Test
    public void testFindAll() throws SQLException {
        List<Employee> list = employeeDao.findAll();
        if(list!=null){
            for(Employee emp: list){
                System.out.println(emp) ;
            }
        }
    }*/
​
    //测试添加员工
    /*@Test
    public void testAddEmp() throws SQLException, ParseException {
        Employee emp = new Employee() ;
        emp.setName("张蒋杰") ;
        emp.setGender("男") ;
        emp.setAge(24) ;
        emp.setSalary(8000.00) ;
        emp.setAddress("南窑国际");
        //日期文本
        String dateStr = "1990-02-27" ;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd") ;
        Date date = sdf.parse(dateStr);//java.util.Date--->java.sql.date;
        //获取Date指定的日期的时间毫秒值
        long time = date.getTime();
        //创建java.sql.Date对象   --->Date(long date)
        java.sql.Date  myDate = new java.sql.Date(time) ;
​
        emp.setBirthday(myDate);
        employeeDao.add(emp) ;
    }*/
​
​
    //测试删除员工
   /* @Test
    public void delete() throws SQLException {
        employeeDao.deleteEmployeeById(3) ;
    }*/
    //测试修改员工
    @Test
    public void updateEmp() throws SQLException, ParseException {
        Employee emp = new Employee() ;
        emp.setId(5) ;
        emp.setName("文章") ;
        emp.setAge(35) ;
        emp.setGender("男") ;
        emp.setSalary(10000.0) ;
        String dateStr = "1985-10-30" ;
        Date date = new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
        emp.setBirthday(date);
        emp.setAddress("西安市") ;
​
        employeeDao.updateEmployee(emp);
    }
​
    //根据员工编号查询指定员工信息
   /* @Test
    public void testFindEmpById() throws SQLException {
​
​
        Employee emp = employeeDao.findEmpById(1);
        System.out.println(emp);
    }*/
}
​

连接池+预编译

package com.qf.dao;
​
import com.qf.pojo.User;
​
import java.sql.SQLException;
​
/**
 * @author Kuke
 * @date 2023/4/6 11:18
 *
 * 持久层
 * 针对用户实体的数据访问接口
 */
public interface UserDao {
​
    /**
     * 判断用户是否登录
     * @param user 用户实体
     * @return 返回true,表示登录成功,否则,登录失败!
     */
    boolean isLogin(User user) throws SQLException;
}
package com.qf.dao.impl;
​
import com.qf.dao.UserDao;
import com.qf.pojo.User;
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
​
/**
 * @author 高圆圆
 * @date 2023/4/6 11:19
 * 持久层的实现类(针对用户的)
 */
public class UserDaoImpl  implements UserDao {
    /**
     * 判断用户是否登录
     * @param user 用户实体
     * @return 返回true,表示登录成功,否则,登录失败!
     */
    @Override
    public boolean isLogin(User user) throws SQLException {
​
        //获取数据库连接对象
        Connection conn = JdbcUtils.getConnection() ;
        //sql :直击通过用户名和密码一块查询
        String sql = "select * from user where username = '"+user.getUsername()+"' and password ='"+user.getPassword()+"'" ;
        System.out.println(sql);
        //获取执行对象
        Statement stmt = conn.createStatement();
        //执行查询
        ResultSet rs = stmt.executeQuery(sql);
​
        boolean flag = rs.next() ;
        //JdbcUtils.close(rs,stmt,conn);
        return flag;
​
    }
}
package com.qf.dao.impl;
​
import com.qf.dao.UserDao;
import com.qf.pojo.User;
import com.qf.utils.JdbcUtils;
​
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
​
/**
 *针对用户数据访问接口的 实现
 */
public class UserDaoImpl2  implements UserDao {
    /**
     * 判断用户是否登录
     * @param user 用户实体
     * @return 返回true,表示登录成功,否则,登录失败!
     */
    @Override
    public boolean isLogin(User user) throws SQLException {
​
        //获取数据库连接对象
        Connection conn = JdbcUtils.getConnection();
        //准备sql---参数化的sql(预编译sql语句)
        //select * from user where username = 'xxx' and password= 'xxx';
        String sql = "select * from user where username = ? and password = ?" ; //英文符号
​
        System.out.println(sql) ;
        //1)通过数据库的连接对象获取预编译对象:将参数化的sql发送数据库,将具体的参数类型以及第几个占位符都存在了PreparedStatement中
        /**
         * PreparedStatement prepareStatement(String sql)
         *       throws SQLException创建一个PreparedStatement对象,用于将参数化的SQL语句发送到数据库
         */
        PreparedStatement stmt = conn.prepareStatement(sql) ;
        //2)使用预编译对象给参数进行赋值
                                        //1:表示第一个,2:表示第二个占位符号
        //通用的方法public void setXXX(占位符号的索引值,赋值的实际参数) ;
        //举例:预编译对象.setString(1,"高圆圆) ;
        stmt.setString(1,user.getUsername()) ;
​
        stmt.setString(2,user.getPassword()) ;
​
        //3)通过预编译对象执行这些参数(在预编译对象中执行参数化的sql)
        //int executeUpdate();
        //ResultSet executeQuery() ;
        ResultSet resultSet = stmt.executeQuery();
​
        boolean flag = resultSet.next();
        JdbcUtils.close(resultSet,stmt,conn);
        return  flag ;
​
​
    }
}
package com.qf.pojo;
​
/**
 * @author 高圆圆
 * @date 2023/4/6 11:17
 * 用户实体
 */
public class User {
    /**
     *  CREATE TABLE USER(
     *  id INT PRIMARY KEY AUTO_INCREMENT ,
     *  username VARCHAR(10),
     *  PASSWORD VARCHAR(10)
     *  ) ;
     */
    private int id ; //用户编号
    private String username ; //用户名
    private String password ; //密码
​
    public User() {
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public String getUsername() {
        return username;
    }
​
    public void setUsername(String username) {
        this.username = username;
    }
​
    public String getPassword() {
        return password;
    }
​
    public void setPassword(String password) {
        this.password = password;
    }
}
package com.qf.preparedStatement_login_02;
​
import com.qf.dao.UserDao;
import com.qf.dao.impl.UserDaoImpl2;
import com.qf.pojo.User;
​
import java.sql.SQLException;
import java.util.Scanner;
​
/**
 *  需求:
 *        使用PreparedStatementStatement完成模拟用户登录操作
 *                1)键盘录入用户名和密码
 *                2)判断如果键盘录入的信息和已知库存在的信息已知
 *                    2.1)提示"登录成功"
 *                    2.3)否则"登录失败"
 */
public class PrepearedStatementTest {
    public static void main(String[] args) throws SQLException {
​
​
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in) ;
​
        //提示并录入数据
        System.out.println("请输入用户名:" ) ;
        String username = sc.nextLine() ;
        System.out.println("请输入密码:" ) ;
        String password = sc.nextLine() ;
​
        //调用UserDao里面的登录方法
        UserDao ud = new UserDaoImpl2() ;
        User user = new User() ;
        user.setUsername(username) ;
        user.setPassword(password);
        boolean flag = ud.isLogin(user);
        if(flag){
            System.out.println("登录成功");
        }else{
            System.out.println("登录失败!");
        }
​
    }
}
package com.qf.statement_login_01;
​
import com.qf.dao.UserDao;
import com.qf.dao.impl.UserDaoImpl;
import com.qf.pojo.User;
​
import java.sql.SQLException;
import java.util.Scanner;
​
/**
 * 需求:
 *      使用Statement完成模拟用户登录操作
 *              1)键盘录入用户名和密码
 *              2)判断如果键盘录入的信息和已知库存在的信息已知
 *                  2.1)提示"登录成功"
 *                  2.3)否则"登录失败"
 *
 *   测试正常数据没有问题:
 *   但是用户名和密码随便输入,而进行sql拼接,就导致出现安全问题:
 *
 *    SELECT * FROM USER WHERE username = 'adsfds' AND PASSWORD ='sdfsds 'OR'1'='1';-- 恒成立
 *    1)sql注入
 *    原因:sql语句的实际参数存在字符串拼接,导致语句出现漏洞;(不安全)
 *    2)执行sql语句的非常低
 *     每一次将写的sql发送数据库,(写一个sql,发送一个次sql,频繁的操作库),
 *    高并发情况下,可能造成系统奔溃!
 *
 *   开发中不会使用Statement去操作数据库,使用PreparedStatement预编译对象
 */
public class StatementTest {
    public static void main(String[] args) throws SQLException {
​
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in) ;
​
        System.out.println("请您输入用户名:" ) ;
        String username = sc.nextLine();
​
        System.out.println("请您输入密码:" ) ;
        String password = sc.nextLine();
​
        //创建UserDao接口对象
        UserDao ud = new UserDaoImpl() ;
        //封装User实体
        User user = new User() ;
        user.setUsername(username) ;
        user.setPassword(password);
        boolean flag = ud.isLogin(user);
        if(flag){
            System.out.println("登录成功!");
        }else{
            System.out.println("对不起,用户名或者输入错误,登录失败!");
        }
​
    }
}
package com.qf.utils;
​
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
​
/**
 * 将jdbc步骤优化
 *       自定义工具类,将获取连接对象,释放资源都放在静态方法中,方便去使用!
 */
public class JdbcUtils {
    //统一资源定位符
    private static String url = null ;
    //用户名
    private static String user = null ;
    //密码
    private static String password = null ;
    //驱动类
    private static String driverClassName = null ;
​
    //定义静态代码块
    static{
        try {
            //1)读取src下面的jdbc.properties文件
            //创建一个属性集合列表
            Properties prop = new Properties() ;
            //System.out.println(prop) ;
            InputStream inputStream = JdbcUtils.class.getClassLoader().
                    getResourceAsStream("jdbc.properties");
            //将字节输入流加载到属性集合列表中
            prop.load(inputStream) ;
            //System.out.println(prop) ;
            //2)通过key获取value
            driverClassName = prop.getProperty("driverClassName");
            url = prop.getProperty("url");
            user = prop.getProperty("user");
            password = prop.getProperty("password");
​
            //3)注册驱动
            Class.forName(driverClassName) ;
​
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
​
    //对外私有,不让外界new
    private JdbcUtils(){}
​
​
    //定义公共的静态方法,返回值就是Connection
    //public static Connection getConnection(String url,String user,String password){ //一会还得需要传入参数,
    public static Connection getConnection(){ //一会还得需要传入参数,
        Connection conn = null ;
        try {
           conn = DriverManager.getConnection(url,user,password) ;//url,user,password
            return  conn;
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return  null ;
    }
​
​
    //释放资源
​
    //public static void  close(ResultSet rs,Statement stmt,Connection conn){
    public static void  close(ResultSet rs,PreparedStatement stmt,Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
​
    //主要针对DDL/DML语句操作释放资源
   /* public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }*/
    public static void close(PreparedStatement stmt,Connection conn){
        close(null,stmt,conn);
    }
​
    public static void main(String[] args) {
​
        Connection conn = JdbcUtils.getConnection();
        System.out.println(conn);
    }
}
package com.qf.utils;
​
import com.alibaba.druid.pool.DruidDataSourceFactory;
​
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
​
/**
 * Jdbc方式---加入Druid连接池,----自动的封装配置文件的所有数据
 * 封装一个静态方法--->获取Connection(从连接池获取)
 * 获取DataSource:数据源----> 连接参数(数据库的信息)以及初始化数量,最大激活数量,最大等待时间
 * 释放资源
 */
public class DruidJdbcUtils {
​
    //静态实例--->java.lang.ThreadLocal<T>  模拟线程,每一个用户都有自己的Connection
    private static ThreadLocal<Connection> tl = new ThreadLocal<>() ; //里面没有连接对象
    //声明一个DataSource接口类型 变量
    private static DataSource ds ;
​
    //构造方法私有化
    private DruidJdbcUtils(){}
​
    //静态代码块
    static{
        try {
            //1)读取德鲁伊的配置文件,让德鲁伊自己封装配置文件参数
            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            //创建属性集合列表
            Properties prop = new Properties() ;
            //加载属性集合列表
            prop.load(inputStream) ;
            //2)创建DruidDataSource(连接池)
            ds = DruidDataSourceFactory.createDataSource(prop) ;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
​
    //获取DataSource数据源信息 (连接池的所有参数)
    public static DataSource getDataSource(){
        return  ds ;
    }
​
    //从数据源(连接池) 获取连接对象
    public static Connection getConnection(){
        //1)线程本地线程中获取连接对象---ThreadLocal<T>--->T get():从当前线程中获取存储的内容
        Connection conn = tl.get() ;
        try {
​
            //2)判断
            //如果当前conn对象为null,说明当前线程中没有要操作的连接对象
            if(conn==null){
                //3)从数据源(连接池中)获取Connection
                conn = ds.getConnection();
                //4)将从数据源中获取到的conn连接对象,绑定当当前线程中
                //ThreadLocal<T>--->public void set(T t):绑定
                tl.set(conn) ;
            }
​
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn ;
    }
​
    //释放资源
    public static void  close(ResultSet rs, PreparedStatement stmt, Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null){
            try {
                conn.close();
                //从当前线程解绑
                tl.remove();  //ThreadLocal<T> :从线程中移出
            } catch (SQLException throwables) {
                throwables.printStackTrace();
​
            }
        }
    }
​
    //主要针对DDL/DML语句操作释放资源
   /* public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }*/
    public static void close(PreparedStatement stmt,Connection conn){
        close(null,stmt,conn);
    }
​
    public static void main(String[] args) {
​
​
        System.out.println(DruidJdbcUtils.getDataSource());
        System.out.println(DruidJdbcUtils.getConnection());
    }
}
package com.qf.druid_03;
​
import com.alibaba.druid.pool.DruidDataSourceFactory;
​
import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
​
/**
 * Druid连接池的使用步骤:
 *      1)导包 druid-1.1.10.jar包
 *      2)准备好连接池的配置文件
 *      3)从连接池获取连接对象
 *          提供jar包--->com.alibaba.druid.pool.DruidDataSource--->本质实现了一个接口javax.sql.DataSource
 *              --->Connection getConnection()
 *
 */
public class DruidDemo {
    public static void main(String[] args) throws Exception {
​
        //3)创建数据源DruidDataSource对象
        //德鲁伊提供的数据源工厂:DruidDataSourceFactory提供静态方法,返回值就是DataSource
        //public static DataSource createDataSource(Properties properties)
        //创建属性集合列表
        Properties prop = new Properties() ;
​
        //读取src下配置文件
        InputStream inputStream = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        //将字节输入流加载进来
        prop.load(inputStream) ;
​
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        for(int x = 1 ; x <=11 ; x++){
            //System.out.println(dataSource.getConnection());
            Connection conn = dataSource.getConnection() ;
            if(x==3){
                conn.close(); //暂时释放,归还连接池中
            }
            System.out.println(conn);
        }
​
        /**
         * 上面这个方法底层已经集成好了
         *  public static DataSource createDataSource(Map properties) throws Exception {
         *         DruidDataSource dataSource = new DruidDataSource(); //创建德鲁伊的数据源
         *         config(dataSource, properties); //封装数据:将配置文件的内容封装到dataSource数据源对象汇总
         *         return dataSource;//返回
         *     }
         */
    }
}
package com.qf.druid_03;
​
import com.qf.utils.DruidJdbcUtils;
​
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
​
/**
 * @author 高圆圆
 * @date 2023/4/6 16:30
 */
public class DruidTest {
    public static void main(String[] args) throws SQLException, ParseException {
        //获取连接对象
        Connection connection = DruidJdbcUtils.getConnection();
​
        //sql
        String sql = "insert into employee(name,gender,age,salary,address,birthday) values(?,?,?,?,?,?)" ;
        //获取预编译对象
        PreparedStatement ps = connection.prepareStatement(sql) ;
        //参数赋值
        ps.setString(1,"陈志龙") ;
        ps.setString(2,"男") ;
        ps.setInt(3,35) ;
        ps.setDouble(4,15000.0);
        ps.setString(5,"西安市") ;
        String dateStr = "1981-01-01" ;
        Date date = new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
        java.sql.Date sqlDate = new java.sql.Date(date.getTime());
        ps.setDate(6,sqlDate);
​
        //执行
        int count = ps.executeUpdate();
        System.out.println(count) ;
        //释放资源
        DruidJdbcUtils.close(ps,connection);
    }
}
​

day37

晨写

# 晨写
​
## 1.使用PreparedStatement完成jdbc操作:DQL语句操作
​
```java
//导包 (驱动jar包)
//注册驱动
Class.forName("com.mysql.jdbc.Driver") ;
//获取数据库连接对象
Connection conn = DriverManager.getConnecton(
    "jdbc:mysql://localhost:3306/库名",
    "用户名",
    "密码") ;
//sql
String sql = "select * from employee where id = ?" ;
//通过数据库连接对象获取预编译对象,同时发送参数化sql到数据库
PreparedStatement ps = conn.prepareStatement(sql) ;
​
//对参数进行赋值
ps.setInt(1,id实际值) ;
​
//通过赋值执行sql语句
Resultset rs = ps.executeQuery() ;
//遍历结果集,封装数据
while(rs.next()){
    //获取,封装数据到实体对象中
    类名  对象名 = new 类名() ;
    对象名.setXXX属性名称(rs.getXXX("column名称")) ;
}
​
//释放资源
//关闭结果集,关闭预编译对象,关闭连接对象
```
​
​
​
## 2.PreparedStatement和Statement的区别?
​
```markdown
共同点:
    1)都是可以将sql发送到数据库(执行sql语句的执行器),前者接口继承自后者
​
不同点:
    1)是否执行的是静态sql语句
        前者是参数化ql语句(里面所有参数都是占位符号?),不是静态sql语句
        后者执行的都是静态sql语句,存在一种"硬编码",存在字符串拼接sql的问题
    2)是否可以提高sql执行效率
        前者:可以提高sql执行效率,只需要给数据库发送一次,然后通过预编译对象赋值不同的参数
        后者:相对来说,它效率低;针对每一次新的sql,单独发送一次;
    3)是否能够造成sql注入
        前者:有效防止sql注入,不存sql的字符串拼接,不会出现安全漏洞
        后者:存在安全漏洞,因为存在字符串拼接sql问题;(非常严重的问题)
```
​
​
​
## 3.数据库连接池的好处?
​
​
​
```markdown
    节省资源:当前连接池(DataSource接口)创建之后,就会初始化一些连接对象,节省连接对象的创建;
    重复利用:当某个线程持有的连接对象被使用完之后,归还连接池等待下次利用;
    提高性能:连接池中:只需要配置好这些连接参数(最基本参数:数据库的相关信息)/连接池中的优化参数,DataSource里的实现类---DruidDataSource自己封装这里面的所有连接参数;(还可以不断监控连接池中连接数量的变化) 
    
    
```
​
## 4.Druid连接池的使用步骤
​
```markdown
    1)导包druid-1.1.10.jar /mysql的驱动jar包
    2)准备配置文件 
    url=jdbc:mysql://localhost:3306库名
    driverClassName=com.mysql.jdbc.Driver
    username=root
    password=123456
    
    initialSize=初始化连接数量
    maxActive=最大激活数量
    minIdel=最小空闲数量
    maxidel=最大空闲数量
    maxWait=最大等待时间毫秒值
    
    3)创建数据源javax.sql.DataSoure接口对象,
    //属性集合列表
    Properties prop = new Properties() ;
    //读取src下面的druid.propertites---->当前类的字节码文件对象获取类加载器--->资源文件的输入流对象
    prop.load(字节输入流) ;
    
    DataSource ds = DruidDataSourceFatory.createDataSource(prop) ;
    Connection conn = ds.getConnection() ;
    
```
​
​
​
## 5.加入连接池后自定义工具类的步骤,代码体现
​
```java
class JdbcUtils{
    private static ThreadLocal<Connection> tl = new ThreadLocal<>() ;//每一个线程都有自己的连接对象
    private static DataSource ds ;
    private JdbcUtils(){}
    
    static{
     //1)读取德鲁伊的配置文件,让德鲁伊自己封装配置文件参数
            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            //创建属性集合列表
            Properties prop = new Properties() ;
            //加载属性集合列表
            prop.load(inputStream) ;
            //2)创建DruidDataSource(连接池)
            ds =  DruidDataSourceFactory.createDataSource(prop);
    }
    
    public static Connection getConnection(){
        Connection conn =  tl.get() ;
        if(conn==null){
              //从数据源中(连接池)获取连接对象
            conn = ds.getConnection() ;
            //将当前连接对象绑定到自己的线程上
            t1.set(conn) ;
        }
        return conn ;
    }
}
```
​
​
​
# 今日内容
​
## 1.Jdbc控制事务---->javax.sql.Connection
​
```java
转账业务操作:
  同时操作多个账户内容(更新),这些更新语句要么同时执行成功,要么同时执行失败!
  public void setAutoCommit(boolean auto) ;参数为true,表示自动提交,如果是false,手动提交
  void rollback():事务回滚,撤销之前所有更改,必须释放连接对象,连接对象需要从线程中解绑
  void commit():提交事务,将更改数据永久保存,提交完毕,释放连接对象,需要从线程中解绑
​
       throws SQLException
```
​
## 2.Apache组织结构提供可以工具类库:commons-dbutils (知道每一个api功能作用)
​
```
对原生jdbc的7大步骤进行简易封装!
sql怎么写?以及要返回结果集里面到低给什么类型的数据?
        查询的时候,将查询的多条记录封装到集合List中
        查询的时候,将某条记录封装到实体中
        查询的时候,将查询的表的总记录数展示( 聚合函数:单行单列的内容)---->封装到Object类中
```
​
## 3.前端HTML/CSS/Js/

Dbutils

​
​
commons-dbutils的使用步骤:
    1)导包 commons-dbutils-1.6.jar
    2)创建执行器 QueryRunner---> 底层PreparedStatement
     public QueryRunner(DataSource ds) 参数就是数据源--->自定义工具获取到了数据源 (自动提交)
     public QueryRunner():创建执行器,手动提交
​
​
   3)准备好sql语句
        DML语句---添加/修改/删除
                  insert into
                  update
                  delete from...
​
        QueryRunner提供通用的更新操作:
        public int update(Connection conn, String sql, Object... params) throws SQLException  :手动提交
        public int update(String sql, Object... params):自动提交
​
​
        DQL语句--- 查询语句
​
        QueryRunner提供的通用查询操作
        public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params) throws SQLException
        第一个参数:查询的sql语句
        第二个参数:ResultSetHandler结果集的处理
                    它的子实现类:BeanHandler---->将查询的某一条记录封装到实体了中(JavaBean:是具体类,属性私有,对外提供setXXX()/getXXX)
                    public BeanHandler(Class<T> type) --->  参数针对查询的记录--封装到类名.class中
​
                    子实现类:BeanListHandler<T>    ---将查询的多条记录封装到List集合中,List集合都是当前类对象
​
                     public BeanListHandler(Class<T> type)
                    子实现类:
​
                        ScalarHandler:通过聚合函数(count(列名称),其他max(xx),avg(xxx))查询单行单的列的数据
                        的结果封装到Object类中
        第三个参数:就是赋值的实际参数params,没有参数可以不写
​
注意事项:
​
​
    使用commons-dbutils工具库:无论添加/删除/修改/查询数据,
        必须保证实体类的属性名称和表的字段名称一一对应,否则数据封装不上去的,永远是null!
        如果不对应,可以在(查询语句)--->给这字段给别名(保证别名和实体类的属性名称一致)
​
        实体类的属性名称不要出现大写字母,否则也可能是null值!
​

Dbutils对employee增删查改实例

package com.qf.utils;
​
import com.alibaba.druid.pool.DruidDataSourceFactory;
​
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
​
/**
 * Jdbc方式---加入Druid连接池,----自动的封装配置文件的所有数据
 * 封装一个静态方法--->获取Connection(从连接池获取)
 * 获取DataSource:数据源----> 连接参数(数据库的信息)以及初始化数量,最大激活数量,最大等待时间
 * 释放资源
 */
public class DruidJdbcUtils {
​
    //静态实例--->java.lang.ThreadLocal<T>  模拟线程,每一个用户都有自己的Connection
    private static ThreadLocal<Connection> tl = new ThreadLocal<>() ; //里面没有连接对象
    //声明一个DataSource接口类型 变量
    private static DataSource ds ;
​
    //构造方法私有化
    private DruidJdbcUtils(){}
​
    //静态代码块
    static{
        try {
            //1)读取德鲁伊的配置文件,让德鲁伊自己封装配置文件参数
            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            //创建属性集合列表
            Properties prop = new Properties() ;
            //加载属性集合列表
            prop.load(inputStream) ;
            //2)创建DruidDataSource(连接池)
            ds =  DruidDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
​
    //获取DataSource数据源信息 (连接池的所有参数)
    public static DataSource getDataSource(){
        return  ds ;
    }
​
    //从数据源(连接池) 获取连接对象
    public static Connection getConnection(){
        //1)线程本地线程中获取连接对象---ThreadLocal<T>--->T get():从当前线程中获取存储的内容
        Connection conn = tl.get() ;
        try {
​
            //2)判断
            //如果当前conn对象为null,说明当前线程中没有要操作的连接对象
            if(conn==null){
                //3)从数据源(连接池中)获取Connection
                conn = ds.getConnection();
                //4)将从数据源中获取到的conn连接对象,绑定当当前线程中
                //ThreadLocal<T>--->public void set(T t):绑定
                tl.set(conn) ;
            }
​
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn ;
    }
​
    //释放资源
    public static void  close(ResultSet rs, PreparedStatement stmt, Connection conn){
        if(rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(stmt!=null){
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if(conn!=null) {
            try {
                conn.close();
                //从当前线程解绑
                tl.remove();  //ThreadLocal<T> :从线程中移出
            } catch (SQLException throwables) {
                throwables.printStackTrace();
​
            }
        }
    }
​
​
    //主要针对DDL/DML语句操作释放资源
   /* public static void close(Statement stmt,Connection conn){
        close(null,stmt,conn);
    }*/
    public static void close(PreparedStatement stmt,Connection conn){
        close(null,stmt,conn);
    }
​
    /**
     * 开启事务
     *
     */
    public static void setAutoCommit() throws SQLException {
        //获取连接对象
        Connection conn = getConnection();
        //设置手动提交
        conn.setAutoCommit(false) ;
    }
​
    /**
     * 事务回滚
     */
    public static void rollbackAndClose() throws SQLException {
        //获取连接对象
        Connection conn = getConnection();
        conn.rollback() ;
        //释放连接对象,从当前线程中解绑
        conn.close() ;
        tl.remove() ;
    }
​
    /**
     * 提交事务
     */
    public static void commitAndClose() throws SQLException {
        //获取连接对象
        Connection conn = getConnection();
        conn.commit(); ;
        //释放连接对象,从当前线程中解绑
        conn.close();
        tl.remove() ;
    }
​
​
    public static void main(String[] args) {
​
​
        System.out.println(DruidJdbcUtils.getDataSource());
        System.out.println(DruidJdbcUtils.getConnection());
    }
}
package com.qf.pojo;
​
import java.util.Date;
​
/**
 * @author 高圆圆
 * @date 2023/4/7 11:10
 * 员工实体
 */
public class Employee {
    /**
     *
     id int(11) NOT NULL
     name varchar(10) NULL
     gender varchar(3) NULL
     age int(11) NULL
     salary double NULL
     address varchar(20) NULL
     birthday date NULL
     */
    private int id ;
    private String emp_name ;
    private String emp_gender ;
    private int age ;
    private double salary ;
    private String adderss ;
    private Date birthday;
​
    //private Dept dept; //员工属于哪个部门的
​
    public Employee() {
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    /*public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public String getGender() {
        return gender;
    }
​
    public void setGender(String gender) {
        this.gender = gender;
    }
*/
​
    public String getEmp_name() {
        return emp_name;
    }
​
    public void setEmp_name(String emp_name) {
        this.emp_name = emp_name;
    }
​
    public String getEmp_gender() {
        return emp_gender;
    }
​
    public void setEmp_gender(String emp_gender) {
        this.emp_gender = emp_gender;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public double getSalary() {
        return salary;
    }
​
    public void setSalary(double salary) {
        this.salary = salary;
    }
​
    public String getAdderss() {
        return adderss;
    }
​
    public void setAdderss(String adderss) {
        this.adderss = adderss;
    }
​
    public Date getBirthday() {
        return birthday;
    }
​
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
​
    @Override
    public String toString() {
        return "Employee{" +
                "id=" + id +
                ", emp_name='" + emp_name + '\'' +
                ", emp_gender='" + emp_gender + '\'' +
                ", age=" + age +
                ", salary=" + salary +
                ", adderss='" + adderss + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}
package com.qf.dao;
​
import com.qf.pojo.Employee;
​
import java.sql.SQLException;
import java.util.List;
​
/**
 * @author Kuke
 * @date 2023/4/7 11:12
 * 针对员工的数据访问接口(持久层)
 */
public interface EmployeeDao {
​
    /**
     * 查询所有员工
     * @return 返回员工列表
     */
    List<Employee> findAll() throws SQLException;
​
    /**
     * 根据员工编号查询员工
     * @param id 员工编号
     * @return 返回员工实体
     */
    Employee findEmpById(int id) throws SQLException;
​
    /**
     * 查询总记录数
     * @return 返回总条数
     */
    int getTotalCount() throws SQLException;
​
    /**
     * 添加员工
     * @param emp 员工实体
     */
    void addEmployee(Employee emp) throws SQLException;
​
    /**
     * 根据员工id修改员工信息
     * @param emp  员工实体
     * @throws SQLException
     */
    void updateEmployee(Employee emp) throws SQLException ;
​
    /**
     * 根据员工姓名模糊查询
     * @param name  关键字员工名称
     * @return 返回员工列表
     */
    List<Employee> findEmpByName(String name) throws SQLException;
}
​
package com.qf.dao.impl;
​
import com.qf.dao.EmployeeDao;
import com.qf.pojo.Employee;
import com.qf.utils.DruidJdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
​
import java.sql.SQLException;
import java.util.List;
​
/**
 * @author 高圆圆
 * @date 2023/4/7 11:13
 */
public class EmployeeDaoImpl  implements EmployeeDao {
    /**
     * 查询所有员工
     * @return 返回员工列表
     */
    @Override
    public List<Employee> findAll() throws SQLException {
​
        //使用apache提供开源工库实现
        //创建QueryRunner
        //public QueryRunner(DataSource ds)
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
​
        //sql
        String sql = "select * from employee" ;
​
​
        //将查询的多条记录封装List集合,集合List存储每一个员工对象
        //public <T> T query(String sql, ResultSetHandler<T> rsh, Object... params)
        //子实现类:BeanListHandler<T>    ---将查询的多条记录封装到List集合中,List集合都是当前类对象
        List<Employee> list = qr.query(sql, new BeanListHandler<>(Employee.class));
        return list;
    }
​
​
    /**
     * 根据员工编号查询员工
     * @param id 员工编号
     * @return 返回员工实体
     */
    @Override
    public Employee findEmpById(int id) throws SQLException {
        //创建执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "select * from employee where id = ?" ;
        //执行查询: 将某一条记录封装到实体中
        /**
         *  它的子实现类:BeanHandler---->将查询的某一条记录封装到实体了中(JavaBean:是具体类,属性私有,对外提供setXXX()/getXXX)
         *                     public BeanHandler(Class<T> type) --->  参数针对查询的记录--封装到类名.class中
         */
        Employee emp = qr.query(sql, new BeanHandler<>(Employee.class), id);
        return emp;
    }
​
    /**
     * 查询总记录数
     * @return 返回总条数
     */
    @Override
    public int getTotalCount() throws SQLException {
        //执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
       //sql
        String sql = "select count(id) from employee" ;
        //将查询的结果:当行单例的数据封装到Object中
        /**
         *  ScalarHandler:通过聚合函数(count(列名称),其他max(xx),avg(xxx))查询单行单的列的数据
         *                         的结果封装到Object类中
         *                         //public ScalarHandler()
         */
        Object object = qr.query(sql, new ScalarHandler<>());
        //5----取出来
        String s = String.valueOf(object);
        int totalCount = Integer.parseInt(s);
​
        return totalCount;
    }
​
    /**
     * 添加员工
     * @param emp 员工实体
     */
    @Override
    public void addEmployee(Employee emp) throws SQLException {
​
        //创建执行对象
        QueryRunner qr  = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "insert into employee(name,gender,age,salary,address,birthday) value(?,?,?,?,?,?)" ;
        //public int update(String sql, Object... params):自动提交
        int count = qr.update(sql,
               // emp.getName(),
                //emp.getGender(),
                emp.getAge(),
                emp.getSalary(),
                emp.getAdderss(),
                emp.getBirthday()
        );
        System.out.println("影响了"+count+"行");
    }
​
    /**
     * 根据员工id修改员工信息
     * @param emp  员工实体
     * @throws SQLException
     */
    @Override
    public void updateEmployee(Employee emp) throws SQLException {
        //创建执行对象
        QueryRunner qr  = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "update employee set name =?,gender =?,age =?,salary = ?,address=?,birthday=? where id = ?" ;
        //public int update(String sql, Object... params):自动提交
        int count = qr.update(sql,
               // emp.getName(),
                //emp.getGender(),
                emp.getAge(),
                emp.getSalary(),
                emp.getAdderss(),
                emp.getBirthday(),
                emp.getId()
        );
        System.out.println("影响了"+count+"行");
​
    }
​
    /**
     * 根据员工姓名模糊查询
     * @param name  关键字员工名称
     * @return 返回员工列表
     */
    @Override
    public List<Employee> findEmpByName(String name) throws SQLException {
        //执行对象
        QueryRunner qr = new QueryRunner(DruidJdbcUtils.getDataSource()) ;
        //sql
        String sql = "select name as emp_name,gender as emp_gender,age,salary,address as adderss ,birthday from employee where name like ?" ;
        //查询
        List<Employee> list = qr.query(sql, new BeanListHandler<>(Employee.class), name);
        return list;
    }
}
package com.qf.test;
​
import com.qf.dao.EmployeeDao;
import com.qf.dao.impl.EmployeeDaoImpl;
import com.qf.pojo.Employee;
import org.junit.Before;
import org.junit.Test;
​
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
​
/**
 * @author 高圆圆
 * @date 2023/4/7 11:13
 * 测试
 */
public class EmployeeTest {
​
    private EmployeeDao ed ;
    @Before
    public void init(){
        ed = new EmployeeDaoImpl() ;
    }
​
    //查询所有
    @Test
    public void testFindAll() throws SQLException {
        List<Employee> all = ed.findAll();
        if(all!=null){
            for(Employee emp :all){
                System.out.println(emp);
            }
        }
    }
​
​
    //查询执行员工
    @Test
    public void testFindEmpById() throws SQLException {
        Employee emp = ed.findEmpById(6);
        System.out.println(emp);
    }
​
    //查询总记录数
    @Test
    public void testTotalCount() throws SQLException {
        int count = ed.getTotalCount();
        System.out.println(count);
    }
​
​
    //测试添加员工
    @Test
    public void testAdd() throws ParseException, SQLException {
        //封装员工实体
        Employee employee = new Employee() ;
        //employee.setName("张三丰") ;
        //employee.setGender("男") ;
        employee.setAge(45) ;
        employee.setSalary(6000.0) ;
        employee.setAdderss("西安市") ;
        String birthdayDate = "1985-10-20" ;
        Date date = new SimpleDateFormat("yyyy-MM-dd").parse(birthdayDate);
        employee.setBirthday(new java.sql.Date(date.getTime()));
        ed.addEmployee(employee) ;
    }
​
    //测试修改
    @Test
    public void testUpdate() throws ParseException, SQLException {
        //封装员工实体
        Employee employee = new Employee() ;
        employee.setId(7);
        //employee.setName("张无忌") ;
        //employee.setGender("男") ;
        employee.setAge(20) ;
        employee.setSalary(8000.0) ;
        employee.setAdderss("神木市") ;
        String birthdayDate = "1990-05-01" ;
        Date date = new SimpleDateFormat("yyyy-MM-dd").parse(birthdayDate);
        employee.setBirthday(new java.sql.Date(date.getTime()));
        ed.updateEmployee(employee); ;
    }
​
    //模糊搜索
    @Test
    public void testFindEmpByName() throws SQLException {
        List<Employee> list = ed.findEmpByName("张%");
        if(list!=null){
            for(Employee emp:list){
                System.out.println(emp);
            }
        }
    }
}
​

jdbc事务

package com.qf.jdbc_transaction_01;
​
import com.alibaba.druid.support.json.JSONUtils;
import com.qf.utils.DruidJdbcUtils;
​
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
​
/**
 * Jdbc控制事务:
 *    public void setAutoCommit(boolean auto) ;参数为true,表示自动提交,如果是false,手动提交
 *    void rollback():事务回滚,撤销之前所有更改,必须释放连接对象,连接对象需要从线程中解绑
 *    void commit():提交事务,将更改数据永久保存,提交完毕,释放连接对象,需要从线程中解绑
 *
 *  什么是事务?
 * 针对多个sql或者多张表的sql(增删改),要么同时执行成功,要么同时执行失败,应该将整个业务看成一个整体,一块执行!
 * 事务的特点:
 *      原子性,一致性,隔离性,持久性
 *
 *  需求:
 *      转账业务:
 *              account账户表中:id为3的用户给id为4的账户进行转账500
 */
public class TranserDemo {
    public static void main(String[] args) {
        Connection conn = null ;
        PreparedStatement ps1=  null ;
        PreparedStatement ps2=  null ;
        try {
            //获取连接池中的初始化连接数量中的连接对象
             conn = DruidJdbcUtils.getConnection();
​
             //开启手动提交模式(开启事务)
            //public void setAutoCommit(boolean auto) ;参数为true,表示自动提交,如果是false,手动提交
            conn.setAutoCommit(false) ;
​
​
            //sql语句
            String sql1 = "update account set balance = balance - ? where id = ?" ;
            String sql2 = "update account set balance = balance + ? where id = ?" ;
​
            //发送参数化的sql获取编译对象
             ps1 = conn.prepareStatement(sql1) ;
             ps2 = conn.prepareStatement(sql2) ;
​
            //参数赋值
            ps1.setInt(1,500) ;
            ps1.setInt(2,3) ;
​
            ps2.setInt(1,500) ;
            ps2.setInt(2,4) ;
​
            //在预编译对象中执行
            int count = ps1.executeUpdate();
            int i = 10/0 ; //明显给了异常,实际开发中可能其他系统监控代码出现bug了也会造成 前面sql执行了,后面没有执行1
            int count2 = ps2.executeUpdate();
            System.out.println(count+"----"+count2) ;
​
​
           // void commit():提交事务,将更改数据永久保存,提交完毕,释放连接对象,需要从线程中解绑
          conn.commit(); //事务提交
        } catch (SQLException throwables) {
            //事务回滚
           // void rollback():事务回滚,撤销之前所有更改,必须释放连接对象,连接对象需要从线程中解绑
            try {
                conn.rollback();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            throwables.printStackTrace();
        } finally {
            DruidJdbcUtils.close(ps1,conn) ;
            DruidJdbcUtils.close(ps2,conn) ;
        }
​
    }
}
​

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值