1.MySQL
JavaEE:企业级Java开发 Web
前端(页面:展示,数据!)
后台(连接点:连接数据库JDBC,链接前端(控制视图跳转传给前端数据))
数据库(存数据,Txt,Excel,word)
1.1 为什么学习数据库
市场需要
1.2 什么是数据库
数据库(DB)
概念:数据仓库,软件,安装在操作系统之上!SQL,可以存储大量的数据(500w之内)
作用:存储数据,管理数据
1.3 数据库管理系统(DBMS )
1.4 安装教程
安装MySQL
安装SQLyog
1.5 连接数据库
mysql -uroot -password #链接数据库 show databases; #查看所有的数据库 mysql> use school #切换数据库use数据库名 Database changed show tables; #查看数据库中的所有的表 describe student; #显示数据库中所有的表的信息 create database student; #创建一个数据库 exit; --退出 #单行注释 /*多行注释*/
数据库xxx语言
DDL 定义
DML 操作
DQL 查询
DCL 控制
1.6Mac安装mysql
1.6.1第一步 官网下载:MySQL :: Download MySQL Community Server(打开直接是社区版的,基础阶段只需要社区版本,别的版本要付费)
2.操作数据库
2.1 操作数据库(了解) 数据库的增删改查
操作数据库>操作数据库中的表>操作数据库中的表的数据
-
创建数据库
CREATE DATABASE [IF NOT EXISTS] (westos)#表名( `字段名` 列类型 [属性][索引][注释], `字段名` 列类型 [属性][索引][注释], `字段名` 列类型 [属性][索引][注释] …… `字段名` 列类型 [属性][索引][注释] )[表类型][字符集设置][注释]
-
删除数据库
DROP DATABASE IF EXISTS westos;
-
使用数据库
#tab键的上面,如果你的表名或者字段名是一个特殊字符,就要带` Eg:USE `school;`
-
查看数据库
SHOW DATABASES #查看所有的数据库
-
SHOW CREATE DATABASE school #查看创建数据库的语句 SHOW CREATE TABLE school #查看Student数据表的定义语句 DESC student #显示表的结构
-
修改数据库
#修改表名: ALTER TABLE 旧表名 RENAME AS 新表名 ALTER TABLE teacher RENAME AS teacher1 #增加表的字段: ALTER TABLE 表名 ADD 字段名 列属性 ALTER TABLE teacherl ADD age INT(11) #修改表的字段 (重命名,修改约束!) #ALTER TABLE 表名 MODIFY 字段名 列属性[] ALTER TABLE teacherl MODIFY age VARCHAR(11) -- 修改约束 #ALTER TABLE 表名CHANGE 旧名字 新名字 列属性[] ALTER TABLE teacher1 CHANGE age agel INT(1)-- 字段重名名 #删除表的字段 ALTER TABLE teacher1 DROP age1
2.2 数据类型
数值
-
tinyint 1个字节
-
smallint 2个字节
-
mediumint 3个字节
-
int 4个字节
-
bigint 8个字节
-
float 4个字节
-
double 8个字节
-
decimal 金融计算数
字符串
-
char 字符串固定大小的 0-255
-
varchar 可变字符串 0-65535 常用的String
-
tingtext 微型文本 2^8-1
-
text 文本串 2^16-1
时间日期
Java.util.Date
-
data
-
time
-
datetime YYYY-MM-DD HH:mm:ss
-
timestamp 时间戳 1970到现在的毫秒数
-
year 年份表示
null
-
没有值,未知
-
注意,不要使用NULL进行运算,结果为NULL
2.3 数据库的字段属性
Unsigned:
-
无符号的整数
-
声明了该列不能声明为负数
zerofill:
-
0填充的
-
不足的位数,使用0来填充
自增:auto incr
-
通常用于id中
非空 NULL not null
-
null不填默认为空
默认
-
默认初始值
规范拓展
/*每一个表,都必须存在以下五个字段!未来做项目用的,表示一个记录存在的意义 id 主键 `version` 乐观锁 is_delete 伪删除 gmt_create 创建时间 gmt_update 修改时间 */
2.4 数据表的类型(面试)
#关于数据库引擎 /* INNODB 默认使用~ MYISAM 早些年使用的 */
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间的大小 | 较小 | 较大,约为2倍 |
常规使用操作:
-
MYISAM 节约空间,速度较快
-
INNODB 安全性高,事务的处理,多表多用户操作
在物理空间存在的位置
所有的数据库文件都存在data目录下
本质还是文件的存储!
MySQL引擎在物理文件上的区别
-
InnoDB在数据库中只有一个*.frm文件,以及上级目录下的ibdata1 文件
-
MYISAM对应文件
-
*.frm -表结构的定义文件
-
*.MYD 数据文件(data)
-
*.MYI 索引文件(Index)
-
设置数据库表的字符集编码
CHARSET=utf8
不设置的话,回事mysql默认的字符集编码 (不支持中文)
MySQL的默认编码是Latin,不支持中文
或者
在my.ini中配置默认的编码
character-set-server=utf8 #这种设置了全部sql文件,一般使用上面的方法,为每个数据库设置
3.MySQL数据管理
3.1 外键(了解)
-
一般不用外键
-
一个外键是另一个表的主键
3.2 DML语言(全部记住) 数据库中表的增删改查
数据库意义:数据库的存储与管理
DML语言:数据操作语言
-
插入
insert into 表名(字段名1,字段名2) values('值1'),('值2')
-
修改
#不指定条件的情况下,会改动所有表 update student set name ='嫦娥一号' #修改多个属性,逗号隔开 update student set name ='嫦娥一号' where id =1 #通过多个条件定位数据 update student set name ='嫦娥一号' where id =1 and sex='女'
操作符 含义 范围 结果 = <>或 != 不等于 > < >= <= between ...and ... 区间 and or -
删除delete和truncate
delete
#删除数据 delete from 表名[where 条件] #删除数据(这样全删) delete from text #删除数据(删除某一个) delete from text where id =1
truncate
作用:完全清空一个数据库表,表的结构和索引约束不会变!
#清空 student 表 truncate student
delete和truncate的区别
-
turncate 重新设置自增量,数据归零
-
turncate 不会影响事务
4.DQL查询语言(重点)
4.1 DQL
(Data Query Language:数据查询语言)
-
所有的查询操作,select
-
数据库中最核心的语言,最重要的语句
-
使用频率最高的语句
select完整字段
select[select 选项] 字段列表[字段别名] /* from 数据源 [where条件字句] #指定结果需要满足的条件 [group by 字句] #指定结果按照哪几个字段来分组 [having 字句] #过滤分组的记录必须满足的次要条件 [order by 字句] #指定查询记录按一个或多个条件排序 [limit 字句] #指定查询的记录从哪条至哪条
4.2 指定查询
#查询全部的学生 select * from student #查询指定字段 select `studentid`,`studentName` from student #别名,给结果起一个名字 AS--起别名 select `studentid` AS 学号,`studentName` AS 学生姓名 from student #函数 concat(a,b) select concat('姓名:',studentName) AS 新名字 from student
-
去重
去重 distinct
select distinct `studentid`,`studentName` from student
4.3 where条件子句
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b 或a&&b | 与 |
or || | 或 | |
NOT ! | 非 |
模糊查询:比较运算符
运算符 | 语法 | 描述 |
---|---|---|
is null | a is null | 如果操作符为NULL,结果为真 |
is not null | a is not null | |
between | a between b and c | |
like | a like b | SQL匹配,如果a匹配到b,则结果为真 |
in | a in(a1,a2,a3) | 如a为 a1,a2,a3某一个,则结果为真 |
# 查询姓刘的同学 #like结合 %(代表0到任意个字符) _(一个字符) select studentNo,studentName from student where StudentName like '刘%' #查询姓刘后面只有一个字的 select studentNo,studentName from student where StudentName like '刘_' #查询姓刘后面只有两个字的 select studentNo,studentName from student where StudentName like '刘__' #=============in============ select studentNo,studentName from student where StudentNo in(1001,1002,1003)
4.4 联表查询
join 对比
-
交集
select s.studentNo,studentName,subjectNo,studentResult from student AS s inner join result AS r on s.studentNo=r.studentNo
-
右+交集
select s.studentNo,studentName,subjectNo,studentResult from student AS s right join result AS r on s.studentNo=r.studentNo #on后面是连接条件
-
左+交集
select s.studentNo,studentName,subjectNo,studentResult from student AS s left join result AS r on s.studentNo=r.studentNo
-
实例
/*查询参加考试的同学信息的 1.学号 2.学生姓名 3.科目名 4.分数 1.分析需求,分析查询的字段来自哪些表 student,result,subject 2.确定使用哪种连接查询 7种? 确定交叉点(交集) 判断的条件:学生表的中 studentNo =成绩表 studentNo */ select s.studentNo,studentName,subjectNo,studentResult from student AS s right join result AS r on r.studentNo=s.studentNo inner join subject sub on r.subjectNo =sub.subjectNo #查询学院所属的年级(学号,学生的姓名,年级名称) select studentNo,studentName,GradeName from student s inner join grade g on s.Gradeid=g.Gradeid
4.5 自连接(一表拆二表)
自连接(用于属性结构的 双亲表示法 且只有两层层次才可以用)
自己连接自己:也就是自己一张表当两张表使用
比如数据库关系如下表
catagoryid | pid | catagoryName |
---|---|---|
3 | 1 | 软件开发 |
5 | 1 | 美术设计 |
4 | 3 | 数据库 |
8 | 2 | 办公信息 |
2 | 1 | 信息技术 |
6 | 3 | Web开发 |
7 | 5 | Ps技术 |
父类
catagoryid | catagoryName |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类
pid | catagoryid | catagoryName |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | Web开发 |
5 | 7 | 美术设计 |
操作:查询父类对应的子类关系
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | Web开发 |
美术设计 | Ps技术 |
#查询父子信息 select categoryName as '父栏目',categoryName as '子栏目' from catagory as a,catagory as b where a.categoryid =b.pid
4.6 分页limit和排序order by
select s.studentNo,studentName,subjectName,studentResult from student as s inner join result r on s,studentNo = r.studentNo inner join subject as sub on s,subjectNo = sub.subjectNo where subjectName ='数据库结构' order by desc --desc降序排列 asc--升序排列 limit 0,5 -- 从哪里开始,一页有几个
4.7 子查询
where() 视频P23 不太明白
本质:在where语句中嵌套一个子查询语句
where(select * from)
联表查询写法
#查询课程为 高等数学-2 且分数不小于80的同学的学号和姓名 select s.studentNo,studentName from student s inner join result r on s.studentNo=r.studentNo inner join subject sub on r.subjectNo=sub.subjectNo where subjectName ='高等数学-2' and studentResult>=80
子查询写法
#分数小于80分的学生的学号和姓名 select distinct s.studentNo,studentName from student s inner join result r on r.studentNo=s.studentNo where studentResult>=80 #改造,在这个基础上再增加一个高等数学-2 select distinct s.studentNo,studentName from student s inner join result r on r.studentNo=s.studentNo where studentResult>=80 and subjectNo=( 为子查询写法 select subjectNo from subject where subjectName='高等数学-2' ) #在改造 select studentNo,studentName from student where studentNo in( select studentNo from result where studentResult>80 and subjectNo=( select subjectNo from subject where subjectName ='高等数学-2' ) )
4.7 分组和过滤
#查询不同课程的平均分,最高分,最低分,平均分大于80 #核心 :(根据不同的课程分组) select subjectName,avg(studentResult) as 平均分,max(studentResult) as 最高分,min(studentResult) as 最低分 from result r inner join subject sub on r.subjectNo=sub.subjectNo group by r.subjectNo #通过什么字段来分组 having 平均分>80 #group后面不用where用having
5.MySQL函数
官网查询使用
5.1 常用函数
百度可查常用函数
5.2 聚合函数
#=============聚合函数============= #都能够统计表中的数据(想查询一个和表中有多少个记录,就用这个count()) select count('studentName') from student #count(字段) 会忽略所有的null值 select count(*) from student #count(*),不会忽略null值,本质计算行数 select count(1) from student #count(1),不会忽略null值,本质计算行数 select sum(studentResult) as 总和 from result #总和 select avg(studentResult) as 平均分 from result #平均分 select max(studentResult) as 最大值 from result #最大值 select min(studentResult) as 最小值 from result #最小值
5.3 数据库级别的MD5加密
什么是MD5
主要增强算法复杂度和不可逆性
MD5不可逆,具体的值的MD5是一样
MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密前的值
=================测试MD5加密================== create table testmd5( 'id' int(4) not null 'name' varchar(20) not null 'pwd' varchar(50) not null primary key('id') )engine=innodb default charset=utf-8 #明文密码 insert into testmd5 values(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456') #加密id=1的密码 update testmd5 set pwd=MD5(pwd) where id=1 #加密所有的密码 update testmd5 set pwd=MD5(pwd) #插入时加密 insert into testmd5 values(1,'zhangsan',MD5'123456'),(2,'lisi',MD5'123456'),(3,'wangwu',MD5'123456') #如何校验 将用户传递进来的密码,进行MD5加密,然后对比加密后的值 select * from testmd5 where 'name'='xiaoming' and pwd =MD5('123456')
6.事务
6.1 什么是事务
数据库中:事务(Transaction)是访问和更新数据库的程序执行单元,事务中可能包含一个或多个sql语句,这些语句要么都执行,要么都不执行。
简单理解:将多各操作打包在一起执行,且支持回滚,就是事务!(事务)[事务的【ACID】四大原则 - 知乎 (zhihu.com)]
事务原则:ACID 原则
-
原子性
-
最终一致性
-
交易的双方最终(价格总数)要保证不变
-
-
持久性
-
事务没有提交,恢复到原装
-
事务已经调教,持久化到数据库
-
-
隔离性
-
事务隔离级别
-
1.脏读
指一个事务读取了另外一个事务未提交的数据。(读后写)
2.不可重复读
3.幻读(写后读)
执行事务 mysql是默认开启事务自动提交的
#模拟转账:事务 set autocommint=0; #关闭自动提交事务 start transaction #开启一个事务 update account set money=money-500 where 'name'='A' #A公司减500快 update account set money=money+500 where 'name'='B' #B公司加500快 commit; #提交事务,就被持久化 rollback; #事务回滚 set autocommit=1; 事务恢复默认值
一般事务的提交事务commit放在try中,回滚rollback放在catch中
7.索引
MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获得数据的数据结构
提取句子主干,就可以得到索引的本质:索引是数据结构。
7.1 索引的分类
在一个表中,主键索引只能有一个,唯一索引可以有多个
-
主键索引(primary key)
-
唯一的标识,主键不可重复,只能有一个列作为主键
-
-
唯一索引(union key)
-
避免重复的列出现,唯一索引可以重复,可以多个列有唯一索引
-
-
常规索引(key/index)
-
默认的
-
-
全文索引(FullText)
-
在特定的数据库引擎下才有
-
7.2测试索引
7.3索引原则
-
索引不是越多越好
-
不要对进程变动数据加索引
-
小数据量的表不需要加索引
-
索引一般夹在常用来查询的字段上
索引的数据结构
Hash类型的索引
Btree:innodb的默认数据结构
8.权限管理和备份
8.1 用户管理
本质:就是群主对群的管理
只有linex中使用window下可视化的
8.2 备份
为什么要备份:
-
保证数据不丢失
-
数据转移
MySQL备份数据库方式
-
直接拷贝物理文件
-
可视化工具中右键备份与导出
-
使用命令行 mysqldump导出
-
#导出 mysqldump -hlocalhost -uroot -p123456 school student >D:a.sql #导入 mysql -u用户名 -p密码 库名<备份文件地址
-
9.数据库规范设计
9.1 为什么需要设计
当数据库比较复杂的时候,我们就需要设计了
糟糕的数据库设计
-
数据冗余,浪费空间
-
数据库插入和删除都会麻烦,异常【一般不使用物理外键】
-
程序的性能差
良好的数据库设计
-
节省内存空间
-
保证数据库的完整性
-
方便开发
软件开发中,关于数据库的设计
-
分析需求:分析业务和需要处理的数据库的需求
-
概要设计:设计关系图 E-R图
9.2 三大范式
为什么需要数据规范化?
-
信息重复
-
更新异常
-
插入异常
-
无法正常显示信息
-
-
删除异常
-
丢失有效的信息
-
第一范式(1NF)
原子性:保证每一列不可再分
第二范式(2NF)
前提:满足第一范式
第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于候选码(在1NF基础上消除非主属性对主码的部分函数依赖)
第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言),通俗来讲是每张表只描述一件事情。
第三范式(3NF)
前提:满足第二范式
规范性 和 性能的问题
关联查询的表不得超过三张表
-
考虑商业化的需求和目标,(成本,用户体验!)数据库的性能更加重要
-
在规范性能的问题的时候,需要适当考虑一下规范性
-
故意给某些表增加一些冗余字段(从多表查询变为单表查询)
-
故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
10JDBC
10.1 数据库驱动
程序需要调入包(驱动)来进行执行
10.2 JDBC
Java 操作数据库的统一规范
对于开发人员只需要了解JDBC接口即可(相当于那个文件挂载的意思)
除了java.sql和javax.sql还需要导入一个数据库驱动包mysql-connector-java(Mearn)或者在MySQL官网下载
10.3 第一个JDBC程序
创建测试数据库
CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci; USE `jdbcStudy`; CREATE TABLE `users`( `id` INT PRIMARY KEY, `NAME` VARCHAR(40), `PASSWORD` VARCHAR(40), `email` VARCHAR(60), birthday DATE ); INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES('1','zhangsan','123456','zs@sina.com','1980-12-04'), ('2','lisi','123456','lisi@sina.com','1981-12-04'), ('3','wangwu','123456','wangwu@sina.com','1979-12-04')
1.创建一个项目
2.导入依赖包
3.编写测试代码
package com.hang.study01; import java.sql.*; //我的第一个JDBC程序 public class JDBCFrist { public static void main(String[] args) throws ClassNotFoundException, SQLException { //1.加载驱动 Class.forName("com.mysql.jdbc.Driver"); //会报错先把异常抛出 ,固定写法 //2.用户信息和url String url ="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true"; //useUnicode=true&characterEncoding=utf8&useSSL=true"固定的 String username="root"; String password="123456"; //3.连接成功,数据库对象 Connection connection= DriverManager.getConnection(url,username,password); //4.执行SQL的对象 Statement statement=connection.createStatement(); //5.执行SQL的对象 去执行sql,可能存在结果,查看返回结果 String sql="SELECT * FROM users"; ResultSet resultSet = statement.executeQuery(sql); //返回的结果集,结果集中封装了我们全部的查询出来的结果 while(resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); } //6.释放连接 resultSet.close(); connection.close(); statement.close(); } }
步骤总结
-
加载驱动
-
连接数据库DriverManager
-
获得执行SQL的对象statement
-
获得返回的结果集
-
释放连接
DriverManager
Class.forName("com.mysql.jdbc.Driver"); //会报错先把异常抛出 ,固定写法,加载驱动 Connection connection= DriverManager.getConnection(url,username,password); //connection 代表数据库对象,数据库语言都可以在这里应用 connection.getAutoCommit(); //数据库设置自动提交 connection.commit(); //事务提交 connection.rollback(); //事务回滚
URL
String url ="jdbc:mysql://localhost:3306/jdbcstudy? //协议:服务器(主机地址:端口号) :数据库名?参数1&参数2&..... //Oracle中的URL与MySQL中不同 //1521--为Oracle端口号 //jdbc:oracle:thin:@localhost:1521:sid
Statement执行SQL对象 PrepareStatement执行SQL的对象
String sql="select * from users" statement.executeQuery(sql); //查询操作返回ResultSet statement.execute(sql); //可用于所有操作就是效率问题 statement.executeUpdate(sql); //可用于增删改查
resultSet查询结果集,封装了所有的查询结果
获取指定的数据类型
resultSet.getObject //什么类型都可以获取 ,肯定浪费时间 resultSet.getInt //获取整数类型 resultSet.getString resultSet.getFloat resultSet.getDate
遍历数据
resultSet.beforeFirst() //第一个 resultSet.afterLast() //最后一个 resultSet.next() //下一个 resultSet.provious() //前一个 resultSet.absolute(row) //移动到指定行
释放资源
//6.释放连接 resultSet.close(); connection.close(); statement.close();
10.4 statement对象
Idbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改査,只需要通过这个对象向数据库发送增删改查语句即可。 Statement对象的executeUpdate方法,用于向数据库发送(增、删、改)的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)。 Statement.executeQuery方法用于向数据库发送査询语句,executeQuery方法返回代表査询结果的Resultset对象。
CRUD 操作-create
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement statement=connection.createStatement(); String sql="insert into users(....) values (....)"; int sum =statement.excuteUpdate(sql); if(num>0) { System.out.println("插入成功"); }
CRUD 操作-update
使用executeUpdate(String sql)方法完成数据添加操作,示例操作:
Statement statement=connection.createStatement(); String sql="update users set name ='' where name =''"; int sum =statement.excuteUpdate(sql); if(num>0) { System.out.println("修改名字成功"); }
CRUD 操作-Query
使用executeQuery(String sql)方法完成数据添加操作,示例操作:
Statement statement=connection.createStatement(); String sql="select * from users where id =1"; ResultSet resultSet=statement.executeQuery(sql); while(resultSet.next()){ System.out.println(); //根据需要映射到前端 }
statement步骤
-
提取工具类
-
读取工具类
读取工具类的具体函数
package com.hang.study02.utils; import java.io.InputStream; import java.sql.*; import java.util.Properties; public class JdbcUtils { private static String driver; private static String url; private static String username; private static String passsword; static { try{ InputStream in=JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties"); //拿到输入流 Properties properties = new Properties; properties.load(in); //此时输入流在in对象中 //此时拿到db.properties中各个的值 driver= properties.getProperty("driver"); url= properties.getProperty("url"); username= properties.getProperty("username"); passsword= properties.getProperty("passsword"); //1.驱动只加载一次 Class.forName(driver); } catch (Exception e) { throw new RuntimeException(e); } } //2.获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,passsword); } //3.释放连接 public static void release(Connection connection, Statement statement , ResultSet resultSet){ if (resultSet!=null){ try { connection.close(); } catch (SQLException e) { throw new RuntimeException(e); } } if (statement!=null){ try { connection.close(); } catch (SQLException e) { throw new RuntimeException(e); } } if (connection!=null){ try { connection.close(); } catch (SQLException e) { throw new RuntimeException(e); } } } }
增
public static void main(String[] args) { Connection connection = null; Statement statement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 statement=connection.createStatement(); //获取SQL的执行对象 String sql="insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values('4','hang','123456','1@qq.com','2001-01-20')"; int i= statement.executeUpdate(sql); if(i>0){ System.out.println("插入成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,statement,resultSet); } }
删
public static void main(String[] args) { Connection connection = null; Statement statement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 statement=connection.createStatement(); //获取SQL的执行对象 String sql="delete from users where id= 4"; int i= statement.executeUpdate(sql); if(i>0){ System.out.println("删除成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,statement,resultSet); } }
改
public static void main(String[] args) { Connection connection = null; Statement statement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 statement=connection.createStatement(); //获取SQL的执行对象 String sql="update users set `name`='hang',`email`='702669001@qq.com' where id =1"; int i= statement.executeUpdate(sql); if(i>0){ System.out.println("更新数据成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,statement,resultSet); } }
查
public static void main(String[] args) { Connection connection = null; Statement statement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 statement=connection.createStatement(); //获取SQL的执行对象 String sql="select * from users"; resultSet= statement.executeQuery(sql); if(resultSet.next()){ System.out.println("id:"+resultSet.getInt("id")); System.out.println("name:"+resultSet.getString("name")); System.out.println("password:"+resultSet.getString("password")); System.out.println("email:"+resultSet.getString("email")); System.out.println("birthday:"+resultSet.getDate("birthday")); System.out.println("查询成功\n================================\n"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,statement,resultSet); } }
10.5 SQL注入
漏洞
10.6 PreparedStatement对象
PreparedStatement与statement的本质区别就是可以防止SQL注入
增加
public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 //区别 //使用? 占位符代替参数 String sql = "INSERT INTO users (id, `NAME`, `PASSWORD`, email, birthday) VALUES (?,?,?,?,?)"; preparedStatement=connection.prepareStatement(sql); //预编译SQL,险些SQL,然后不执行 //手动给参数赋值 preparedStatement.setInt(1,4); preparedStatement.setString(2,"lu"); preparedStatement.setString(3,"123456"); preparedStatement.setString(4,"70266239001@qq.com"); //st.setDate(5, date); preparedStatement.setDate(5,new Date(System.currentTimeMillis())); int i=preparedStatement.executeUpdate(); if(i>0){ System.out.println("插入成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,preparedStatement,resultSet); } }
删除
public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 //区别 //使用? 占位符代替参数 String sql = "delete from users where id= ?"; preparedStatement=connection.prepareStatement(sql); //预编译SQL,险些SQL,然后不执行 //手动给参数赋值 preparedStatement.setInt(1,4); //st.setDate(5, date); int i=preparedStatement.executeUpdate(); if(i>0){ System.out.println("删除成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,preparedStatement,resultSet); } }
更新
public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 //区别 //使用? 占位符代替参数 //update users set `name`='hang',`email`='702669001@qq.com' where id =1 String sql = "update users set `name`='yi' where id=?"; preparedStatement=connection.prepareStatement(sql); //预编译SQL,险些SQL,然后不执行 //手动给参数赋值 preparedStatement.setInt(1,1); int i=preparedStatement.executeUpdate(); if(i>0){ System.out.println("更新成功"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,preparedStatement,resultSet); } }
查询
public static void main(String[] args) { Connection connection = null; PreparedStatement preparedStatement=null; ResultSet resultSet=null; //这个一般只有在查询语句中使用 try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 String sql="select * from users where id =?"; preparedStatement=connection.prepareStatement(sql); preparedStatement.setInt(1,1); resultSet= preparedStatement.executeQuery(); if(resultSet.next()){ System.out.println("id:"+resultSet.getInt("id")); System.out.println("name:"+resultSet.getString("name")); System.out.println("password:"+resultSet.getString("password")); System.out.println("email:"+resultSet.getString("email")); System.out.println("birthday:"+resultSet.getDate("birthday")); System.out.println("查询成功\n================================\n"); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(connection,preparedStatement,resultSet); } }
10.7 事务
要么都成功,要么都失败
模拟转账
数据库代码
CREATE TABLE account( id Int PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(40), money FLOAT ); /*插入测试数据*/ insert into account(name,money) values('A',1000); insert into account(name,money) values('B',1000); insert into account(name,money) values('B',1000);
java代码
public static void main(String[] args) { Connection connection=null; PreparedStatement preparedStatement=null; ResultSet resultSet=null; try { connection= JdbcUtils.getConnection(); //这个是utils包中定义的那个拿到connection的函数体 connection.setAutoCommit(false); //关闭自动提交,也就是开启事务 String sql1="update account set money=money-100 where name = 'A'"; preparedStatement=connection.prepareStatement(sql1); preparedStatement.executeUpdate(); String sql2="update account set money=money+100 where name = 'B'"; preparedStatement=connection.prepareStatement(sql2); preparedStatement.executeUpdate(); //业务完毕,提交事务 connection.commit(); System.out.println("转账成功"); } catch (SQLException e) { try { connection.rollback(); } catch (SQLException ex) { e.printStackTrace(); } e.printStackTrace(); } finally { JdbcUtils.release(connection,preparedStatement,resultSet); } }
10.8 数据库连接池
数据库连接--执行完毕--释放 --每次连接浪费很大空间
池化技术:准备一些预先的资源,过来就连接预先准备好的
最小连接数:10
最大连接数:15
等待超时:100ms
编写连接池,实现一个接口 DateSourse
开源数据源实现
DBCP
C3P0
Druid:阿里巴巴
DBCP
需要用到的jar包DBCP数据源jar包下载与IDEA配置以及NoClassDefFoundError问题解决_dbcpjar包下载-CSDN博客
连接配置 properties格式
#连接设置 driverClassName=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=123456 #<!-- 初始化连接 --> initialSize=10 #最大连接数量 maxActive=50 #<!-- 最大空闲连接 --> maxIdle=20 #<!-- 最小空闲连接 --> minIdle=5 #<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 --> maxWait=60000 #JDBC驱动建立连接时附带的连接属性属性的格式必须为这样:【属性名=property;】 #注意:"user" 与 "password" 两个属性会被明确地传递,因此这里不需要包含他们。 connectionProperties=useUnicode=true;characterEncoding=UTF8 #指定由连接池所创建的连接的自动提交(auto-commit)状态。 defaultAutoCommit=true #driver default 指定由连接池所创建的连接的只读(read-only)状态。 #如果没有设置该值,则“setReadOnly”方法将不被调用。(某些驱动并不支持只读模式,如:Informix) defaultReadOnly= #driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。 #可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE defaultTransactionIsolation=READ_UNCOMMITTED