数据库基础
一、数据库
1.1 概念
数据库(Database)是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库。
1.2 数据库分类
关系型数据库(SQL)
- MySQL,Oracle,Sql Server,DB2,SQLlite
- 通过表和表之间,行和列之间的关系进行数据的存储
非关系型数据库(NoSQL)
- Redis,MongDB
- 对象存储,通过对象的自身的属性来决定
1.3 数据库管理系统
数据库管理系统DBMS(Database Management System)
- 数据库的管理软件,科学有效地管理数据库,维护和获取数据。
- MySQL,本质上是数据库管理系统(关系型数据库管理系统)。
- MySQL是一种开放源代码的关系型数据库管理系统(RDBMS),使用最常用的数据库管理语言,结构化查询语言(SQL)进行数据库管理。
- MySQL因为其速度、可靠性和适应性而备受关注。
- 最新版本8.0,最稳版本5.7,建议使用zip安装。
1.4 操作数据库
操作数据库->操作数据库中的表->操作数据库中表的数据
-
创建数据库
create database [if not exists] `myDB`;
-
删除数据库
drop database [if exists] `myDB`;
-
使用数据库
use `myDB`;
-
查看数据库
-- 查看所有数据库 show databases;
1.5 数据库的列类型
-
数值
- tinyint:微小的数据(1个字节)
- smallint:较小的数据(2个字节)
- mediumint:中等的数据(3个字节)
- int:标准的数据(4个字节)
- bigint:较大的数据(8个字节)
- float:浮点数(4个字节)
- double:双精度浮点数(8个字节)
- decimal:字符串形式的浮点数(用于金融计算)
-
字符串
- char:固定长度字符串(0~255)
- varchar:可变长度字符串(0~65535)
- tinytext:微型文本(2^8 - 1)
- text:文本串(2^16 - 1),保存大文本
-
时间日期
java.util.Date
- date:YYYY-MM-DD,日期格式
- time:HH:mm:ss,时间格式
- datetime:YYYY-MM-DD HH:mm:ss
- timestamp:时间戳,1970.1.1到现在的毫秒数
- year:年份表示
-
NULL
- 没有值,未知
- 注意,不要用NULL进行运算,结果为NULL
1.6 数据库的字段属性
- Unsigned:
- 无符号的整数
- 声明该列不能为负数
- zerofill:
- 0填充
- 不足的位数,用0来填充
- 例:int(3),5 --> 005
- 自增:outo_increment
- 自动在上一条记录的基础上 +1
- 通常用来设计唯一的主键,必须是整数类型
- 可以自定义主键自增的起始值和步长
- 非空
- 设置为
not null
,如果不赋值,则报错 - 设置为
null
,如果不赋值,则为null
- 设置为
- 默认
- 设置默认值
- 例:sex,默认值为 男,如果不赋值,则默认为男
拓展
每一个表,都必须存在以下5个字段,表示每一个记录存在的意义
- id,主键
- version,乐观锁
- is_delete,伪删除
- gmt_create,创建时间
- gmt_update,修改时间
二、SQL
2.1 基本命令
-- 查看所有的数据库
show databases;
-- 切换数据库 "use 数据库名"
use `myDB`;
-- 查看数据库中所有的表
show tables;
-- 显示数据库中所有表的信息
describe `myDB`;
-- 创建一个数据库
create database DBtest;
-- 退出连接
exit;
2.3 操作表
所有的创建和删除操作,尽量加上判断,以免报错
-
新建表
create table [if not exists] `表名`( `字段名` 列类型 [属性][索引][注释], `字段名` 列类型 [属性][索引][注释], ...... `字段名` 列类型 [属性][索引][注释] )[表类型][字符集设置][注释]
例:
create table if not exists `student`( `id` int(4) not null auto_increment comment '学号', `name` varchar(30) not null default '匿名' comment '姓名', `pwd` varchar(20) not null default '123456' comment '密码', `sex` varchar(2) not null default '女' comment '性别', `birthday` datetime default null comment '出生日期', `address` varchar(100) default null comment '家庭住址', `email` varchar(50) default null comment '邮箱', primary key(`id`) )engine=InnoDB default charset=utf8;
-
查看表
查看创建语句:
show create database school; -- 查看创建数据库的语句 show create table student; -- 查看student数据表的定义语句
查看表的结构:
desc student;
-
删除表
drop table if exists teacher;
-
更改表
-- 修改表名 alter table `previousname` rename as `currentname`; -- 增加列 alter table `currentname` add age int(11); -- 修改列的约束 alter table `currentname` modify age varchar(11); -- 修改列的名字 alter table `currentname` change age age1 int(11); -- 删除列 alter table `currentname` drop age1;
2.4 表的类型
MYISAM | INNODB | |
---|---|---|
事务 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表的空间大小 | 较小 | 较大,2倍MYISAM |
- 事务:InnoDB 是事务型的,可以使用 Commit 和 Rollback 语句。
- 并发:MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
- 外键:InnoDB 支持外键。
- 备份:InnoDB 支持在线热备份。
- 崩溃恢复:MyISAM 崩溃后发生损坏的概率比 InnoDB 高很多,而且恢复的速度也更慢。
- 其它特性:MyISAM 支持压缩表和空间数据索引。
- MYISAM:节约空间,速度较快
- INNODB:安全性高,事务处理,多表多用户操作
三、SQL数据管理
3.0 添加外键
创建表时添加:
create table if no exists `grade`(
`gradeid` int(10) not null auto_increment comment '年级id',
`gradename` varchar(30) not null comment '年级名称'
)engine=InnoDB default charset=utf8;
create table if not exists `student`(
`id` int(4) not null auto_increment comment '学号',
`name` varchar(30) not null default '匿名' comment '姓名',
`pwd` varchar(20) not null default '123456' comment '密码',
`sex` varchar(2) not null default '女' comment '性别',
`gradeid` int(10) not null comment '年级id',
`birthday` datetime default null comment '出生日期',
`address` varchar(100) default null comment '家庭住址'
`email` varchar(50) default null comment '邮箱',
primary key(`id`),
key `FK_gradeid` (`gradeid`),
constraint `FK_gradeid` foreign key (`gradeid`) references `grade`(`gradeid`)
)engine=InnoDB default charset=utf8;
通过修改表,添加:
create table if no exists `grade`(
`gradeid` int(10) not null auto_increment comment '年级id',
`gradename` varchar(30) not null comment '年级名称'
)engine=InnoDB default charset=utf8;
create table if not exists `student`(
`id` int(4) not null auto_increment comment '学号',
`name` varchar(30) not null default '匿名' comment '姓名',
`pwd` varchar(20) not null default '123456' comment '密码',
`sex` varchar(2) not null default '女' comment '性别',
`gradeid` int(10) not null comment '年级id',
`birthday` datetime default null comment '出生日期',
`address` varchar(100) default null comment '家庭住址'
`email` varchar(50) default null comment '邮箱',
primary key(`id`)
)engine=InnoDB default charset=utf8;
alter table `student`
add constraint `FK_gradeid` foreign key(`gradeid`) references `grade`(`gradeid`);
注意:
-
删除有外键关系的表时,必须先删除引用别人的 表(从表),再删除被引用的表(主表)。
-
以上都是物理外键,数据库级别的外键,不建议使用。
-
数据库就是单纯的表,只用于存数据。
-
用程序实现外键,引用多张表的数据。
3.1 添加
语法:insert into 表名([字段]) values(值1),(值2),···,(值)
insert into `grade`(`gradename`) values('大一'),('大二');
insert into `student`(`name`,`pwd`,`sex`) values('张三','zhangsan','男'),('李四','lisi','男');
insert into `student` values(1,'张三','zhangsan','男','10086'),(2,'李四','lisi','男','10010');
3.2 修改
语法:update 表名 set colnum_name1=value1[,colnum_name2=value2] where [条件]
update `student` set name='周星星',pwd='zhouxingxing' where id=1;
条件:
操作运算符,返回 布尔值
操作符 | 意义 | 例子 | 例子返回的布尔值 |
---|---|---|---|
= | 等于 | 5=6 | false |
<>或!= | 不等于 | 5<>6 | true |
> | 大于 | ||
< | 小于 | ||
<= | 小于等于 | ||
>= | 大于等于 | ||
between…and… | 在某个闭合的范围内 | ||
and | 和 | 5>1 and 1>2 | false |
or | 或 | 5>1 or 1>2 | true |
3.3 删除
delete
语法:delete from 表名 [where 条件]
delete from `student` where id=1;
清空(truncate):完全清空一个数据库表,表的结构和索引不变
语法:truncate table 表名
truncate table student;
delete 和 truncate 的区别
- 相同点:都能删除数据,都不会删除表结构
- 不同点:
- truncate 重新设置 自增列,计数器会归零
- truncate 不会影响事务
delete删除,重启数据库:
- INNODB,自增列会从1开始(存在内存中,断电即失)
- MYISAM,继续从上一个自增量开始(存在文件中,不会丢失)
四、DQL查询数据
DQL(数据查询语言Data Query Language)
- 查询 select
- 数据库中最核心的语言,最重要的语句
4.1 查询
语法:select 字段,... from 表
-
查询所有
select * from student;
-
查询指定字段
select `StudentNo`,`StudentName` from student;
-
给查询结果起一个别名
AS,可以给字段起别名,也可以给表起别名
select `StudentNo` AS 学号,`StudentName` AS 学生姓名 from student;
-
拼接字符串
concat(a,b)
select concat('姓名:',StudentName) AS 新名字 from student;
-
去重
distinct
去除select查询出来的结果中重复的数据
-- 查询有哪些学生参加了考试,即有成绩者 select * from result; -- 查询全部考试成绩 select `StudentNo` from result; -- 查询哪些学生有成绩 select distinct `StudentNo` from result; -- 去除重复数据
-
数据库的列
select version() -- 查询系统版本号(函数) select 100*3-1 AS 计算结果 -- 计算(表达式) select @@auto_increment_increment -- 查询自增的步长(变量) -- 所有学生成绩+1,查看 select `StudentNo`,`StudentResult`+1 AS 提分后 from result;
数据库中的表达式:文本值,列,Null,函数,计算表达式,系统变量…
语法:
select 表达式 from 表
4.2 条件
检索数据中符合条件的值
逻辑运算符:
运算符 | 语法 | 描述 |
---|---|---|
and 或 && | a and b 或 a&&b | 逻辑与,两个都为真,结果为真 |
or 或 || | a or b 或 a||b | 逻辑或,其中一个为真,结果为真 |
not 或 ! | not a 或 !a | 逻辑非,真为假,假为真 |
select `StudentNo`,`StudentResult` from result
where `StudentResult`>=95 and `StudentResult`<=100;
select `StudentNo`,`StudentResult` from result
where `StudentResult`>=95 && `StudentResult`<=100;
select `StudentNo`,`StudentResult` from result
where `StudentResult` between 95 and 100;
select `StudentNo`,`StudentResult` from result
where `StudentNo` != 1000;
select `StudentNo`,`StudentResult` from result
where not `StudentNo` = 1000;
4.3 模糊查询
运算符 | 语法 | 描述 |
---|---|---|
between | a between b and c | 若a在b和c之间,结果为真 |
like | a like b | 如果a匹配b,结果为真 |
in | a in (a1,a2,a3,…) | 假设a是(a1,a2,a3,…)其中的某一个值,结果为真 |
like
-- 查询姓刘的同学
select `StudentNo`,`StudentName` from `student`
where `StudentName` like '刘%';
-- 查询姓刘单字名的同学
select `StudentNo`,`StudentName` from `student`
where `StudentName` like '刘_';
-- 查询姓刘双字名的同学
select `StudentNo`,`StudentName` from `student`
where `StudentName` like '刘__';
-- 查询名字中间有嘉字的同学
select `StudentNo`,`StudentName` from `student`
where `StudentName` like '%嘉%';
in(具体的值)
-- 查询学号为 1001,1002,1003 的同学
select `StudentNo`,`StudentName` from `student`
where `StudentNo` in(1001,1002,1003);
-- 查询住址为 河南,安徽,广东 的同学
select `StudentNo`,`StudentName` from `student`
where `Address` in('河南','安徽','广东');
4.4 联表查询
联表:join (连接的表) on (判断条件)
操作 | 描述 |
---|---|
inner join | 如果表中至少有一个匹配,就返回行 |
left join | 从左表中返回所有的值,即使右表中没有 |
right join | 从右表中返回所有的值,即使左表中没有 |
4.5 排序和分页
排序:升序ASC,降序DESC,默认升序
order by 排序字段 [ASC|DESC]
分页:
limit 起始, 检索数量
limit (n-1)*pageSize,pageSize
select s.studentno,studentname,subjectname,studentresult
from student s
inner join `result` r
on s.studentno = r.studentno
inner join `subject` sub
on r.subjectno = sub.subjectno
where subjectname = 'JAVA第一学年' and studentresult > 80
order by studentresult desc
limit 0,10
4.6 子查询
select `StudentNo`,`SubjectNo`,`StudentResult`
from `result`
where `SubjectNo` = (
select `SubjectNo` from `subject`
where `SubjectName` = '数据库结构1'
)
order by `StudentResult` desc
select s.studentno,studentname,studentresult
from student s
inner join result r
on s.studentno = r.studentno
where subjectno = (
select subjectno from `subject` where subjectname = 'C语言-1'
)
order by studentresult desc
limit 0,5
4.7 聚合函数
函数名 | 描述 |
---|---|
count() | 统计表中 数据 |
sum() | 总和 |
avg() | 平均分 |
max() | 最大值 |
min() | 最小值 |
count(字段)
:查询表中包含这个字段的数量,忽略此字段为null的数据
count(*)
:不会忽略null值,本质是计算行数,计算所有字段的行数,将所有的列都走一遍
count(1)
:不会忽略null值,本质是计算行数,计算其中一个字段的行数,只走一个列
-
MD5加密
调用
MD5()
函数对数据加密
4.8 分组和过滤
-- 查询不同课程的平均分、最高分、最低分,平均分大于80
select subjectname,avg(studentresult) as 平均分,max(studentresult) as 最高分,min(studentresult) as 最低分
from `subject` s
inner join `result` r
on s.subjectno = r.subjectno
group by subjectno
having 平均分>80
4.8 汇总
顺序:
select 去重 要查询的字段 from 表 (表和字段都可以取别名)
xxx join 表 on 等值判断
where (具体的值,子查询语句)
Group By (通过哪个字段分组)
Having (过滤分组后的信息,条件和where一样)
Order By (通过哪个字段排序)[升序/降序]
Limit startIndex,pageSize
五、事务
一个事务(包含几条SQL操作)要么都成功,要么都失败。
ACID原则,保证数据的安全:
- 原子性(Atomicity):一个事务(包含几条SQL操作)是一个不可分割的原子,要么都成功,要么都失败。
- 一致性(Consistency):事务前后,数据的完整性要保持一致。
- 隔离性(Isolation):多个用户并发访问数据库时,数据库为每个用户开启一个事务,不会被其他事务的操作所干扰。
- 持久性(Durability):事务一旦提交则不可逆,被持久化到数据库中。
事物的隔离级别(隔离导致的问题):
- 脏读:一个事务读取了另一个事务未提交的数据。
- 不可重复读:在一个事务内,读取表中某一行数据,多次读取结果不同。
- 幻读:在一个事务内,读取到了别的事务插入的数据,导致前后读取不一致。
隔离级别:
- 未提交读:即使一个更新语句没有提交,但是别的事务可以读取到这个改变。即一个事务读取了另一个未提交事物的数据。
- 提交读:执行了commit之后,别的事务就能读到这个改变,并且只能读到已经提交的数据。
- 重复读:在同一个事务里先后执行同一个查询语句时,得到的结果是一样的。
- 串行读:事务执行时,不允许别的事务并发执行,完全串行化的读,每次读都需要获得表级共享锁,读写相互阻塞。
开启事务
若出现错误:
事务回滚 rollback()
(回到事务开启前)
若没有出现错误:
事务提交 commit()
关闭事务
转账:
A:1000
B:1000
A(900) --100--> B(1100)
SQL中事务:
-- mysql默认开启事务自动提交
-- 手动处理事务
set autocommit = 0; /*关闭自动提交*/
-- 事务开启
start transaction;
-- sql操作
-- insert ***
-- insert ***
-- 成功则提交,持久化
commit;
-- 失败则回滚
rollback;
-- 事务结束,开启自动提交
set autocommit = 1;
-- 拓展
-- 设置一个事务的保存点
savepoint;
-- 回滚到保存点
rollback to savepoint;
-- 撤销保存点
release savepoint;
-- MySQL模拟转账事务
set autocommit = 0; -- 关闭自动提交
start transaction; -- 开启事务
update account set money=money-500 where `name`='A';
update account set money=money+500 where `name`='B';
commit; -- 提交事务
rollback; -- 回滚
set autocommit = 1; -- 恢复默认值
JDBC中事务:
@Test
public void test() {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码问题
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String name = "root";
String password = "123456aB";
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
connection = DriverManager.getConnection(url, name, password);
//3.通知数据库开启事务,false关闭自动提交,true开启自动提交
connection.setAutoCommit(false);
//4.sql语句
String sql = "update account set money = money-100 where name='A'";
//5.预编译
preparedStatement = connection.prepareStatement(sql);
preparedStatement.executeUpdate();
// 错误
// int i = 1/0;
String sql2 = "update account set money = money+100 where name='B'";
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
//6.提交事务
connection.commit();
System.out.println("success");
}catch (Exception e){
//7.事务回滚
try {
connection.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally {
//8.关闭连接
try {
preparedStatement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
六、索引
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。
索引是数据结构。
6.1 索引的分类
- 主键索引(Primary Key):唯一的标识,主键不可重复,只能有一个列作为主键
- 唯一索引(Unique Key):避免重复的列出现,唯一索引可以重复,多个列都可以定义为唯一索引
- 常规索引(Key/Index):默认索引,用Key/Index关键字设置
- 全文索引(FullText):在特定的数据库引擎(MyISAM)下,快速定位数据
6.2 MySQL设置索引
-- 显示所有的索引信息
show index from student;
-- 增加一个全文索引
alter table school.student add fulltext index `studentName` (`studentName`);
-- 创建一个索引
create index id_app_user_name on app_user(`name`);
-- explain 分析sql执行状况
explain select * from student; -- 非全文索引
explain select * from student where Match(studentName) against('刘');
6.3 测试索引
-- 创建表
CREATE TABLE `app_user`(
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) DEFAULT '' COMMENT '用户昵称',
`email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
`phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
`gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男;1:女)',
`password` VARCHAR(100) NOT NULL COMMENT '密码',
`age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'
-- 创建函数:插入一百万条数据(执行不通过)
DELIMITER $$
CREATE FUNCTION mock_data()
DETERMINISTIC
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i<num DO
INSERT INTO app_user(`name`,`email`,`phone`,`gender`,`password`,`age`)VALUES(CONCAT('用户',i),'[email protected]',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
SET i = i+1;
END WHILE;
RETURN i;
END;
select mock_data();
-- 测试查询
select * from app_user where `name`='用户9999';
explain select * from app_user where `name`='用户9999';
-- 创建索引
create index id_app_user_name on app_user(`name`);
-- 测试查询
select * from app_user where `name`='用户9999';
explain select * from app_user where `name`='用户9999';
6.4 索引原则
- 索引不是越多越好
- 不要对经常变动的数据加索引
- 小数据量的表不需要加索引
- 索引一般夹在常用来查询的字段上
七、权限管理
-- 创建用户:create user 用户名 identified by '密码'
create user dongdong identified by '123456';
-- 修改密码(修改当前用户密码)
set password = password('123456')
-- 修改密码(修改指定用户密码)
set password for dongdong = password('123456')
-- 重命名:rename user 原名字 to 新名字
rename user dongdong to dongdong2
-- 用户授权:grain 权限 on 库.表 to 用户
-- all privileges 除了给别人授权,其他都能做
grain all privileges on *.* to dongdong2
-- 查询权限
show grains for dongdong2
show grains for root@localhost
-- 撤销权限:revoke 权限 on 库.表 from 用户
revoke all privileges on *.* from dongdong2
-- 删除用户
drop user dongdong2
八、规范数据库设计
糟糕的数据库设计:
- 数据冗余,浪费空间
- 数据库插入和删除麻烦、出现异常【屏蔽使用物理外键】
- 程序性能差
良好的数据库设计:
- 节省内存空间
- 保证数据库的完整性
- 方便系统开发
软件开发中,关于数据库的设计
- 分析需求:分析业务和数据库需求
- 概要设计:设计关系图 E-R 图
数据不规范导致的问题:
- 信息重复
- 更新异常
- 插入异常
- 删除异常
三大范式:
- 第一范式:原子性,保证每一列都不可再分
- 第二范式:满足第一范式,每张表只描述一件事情
- 第三范式:满足第一范式和第二范式,每一列数据都和主键直接相关
规范性 和 性能:关联查询的表不得超过三张
- 考虑商业化的需求和目标,数据库的性能更重要
- 在兼顾性能的时候,适当考虑规范性
- 故意给某些表增加冗余字段(从多表查询变成单表查询)
- 故意增加一些计算列(从大数据量降低为小数据量的查询)
九、JDBC
JDBC固定步骤
- 加载驱动
- 连接数据库,代表数据库
- 向数据库发送SQL的对象Statement:CRUD
- 编写SQL(根据业务,不同的SQL)
- 执行SQL
- 关闭连接
public class TestJdbc {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码问题
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String name = "root";
String password = "123456aB";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, name, password);
//3.向数据库发送SQL的对象Statement,PreparedStatement : CRUD
Statement statement = connection.createStatement();
//4.编写SQL
String sql = "select * from users";
//5.执行SQL,返回一个ResultSet 结果集
ResultSet rs = statement.executeQuery(sql);
while (rs.next()) {
System.out.println("id=" + rs.getObject("id"));
System.out.println("name=" + rs.getObject("name"));
System.out.println("password=" + rs.getObject("password"));
System.out.println("email=" + rs.getObject("email"));
System.out.println("birthday=" + rs.getObject("birthday"));
}
//6.关闭连接,释放资源(必做),先开后关
rs.close();
statement.close();
connection.close();
}
}
9.1 URL
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
// 协议://主机地址:端口号/数据库名?参数1&参数2
// MySQL 端口号默认 3306
// jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2
// Oracle 端口号默认 1521
// jdbc:oracle:thin:@localhost:1521:sid
9.2 加载驱动
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
// connection 代表数据库
Connection connection = DriverManager.getConnection(url,username,password);
// 数据库提交
connection.commit();
// 数据库回滚
connection.rollback();
// 数据库设置自动提交
connection.setAutoCommit();
9.3 Statement
执行SQL的对象,向数据库发送SQL语句
Statement statement = connection.createStatement();
statement.executeQuery(); // 查询,返回ResultSet
statement.executeUpdate(); // 更新、插入、删除,返回受影响的行数
statement.execute(); // 执行任何SQL
SQL注入
// 正常情况
Statement statement = connection.createStatement();
String sql = "select * from users where name='赵六' and password = '123456'";
statement.executeQuery(sql);
// SQL注入
Statement statement = connection.createStatement();
String name = "' or '1=1";
String password = "' or '1=1";
String sql = "select * from users where name='"+name+"' and password = '"+password+"'";
// select * from users where name='' or '1=1' and password = '' or '1=1'
statement.executeQuery(sql);
预编译
public class TestJDBC2 {
public static void main(String[] args) throws SQLException, ClassNotFoundException {
//配置信息
//useUnicode=true&characterEncoding=utf-8 解决中文乱码问题
String url = "jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf-8";
String name = "root";
String password = "123456aB";
//1.加载驱动
Class.forName("com.mysql.jdbc.Driver");
//2.连接数据库,代表数据库
Connection connection = DriverManager.getConnection(url, name, password);
//3.编写SQL
String sql = "insert into users (id, name, password, email, birthday) values (?,?,?,?,?)";
//4.预编译
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1,4);
preparedStatement.setString(2,"赵六");
preparedStatement.setString(3,"123456");
preparedStatement.setString(4,"[email protected]");
preparedStatement.setDate(5,new Date(new java.util.Date().getTime()));
int i = preparedStatement.executeUpdate();
if (i>0) {
System.out.println("插入成功");
}
//6.关闭连接,释放资源(必做),先开后关
preparedStatement.close();
connection.close();
}
}
PreparedStatement防止SQL注入
// SQL注入
Statement statement = connection.createStatement();
String name = "' or '1=1";
String password = "' or '1=1";
String sql = "select * from users where name='"+name+"' and password = '"+password+"'";
// select * from users where name='' or '1=1' and password = '' or '1=1'
ResultSet rs = statement.executeQuery(sql);
// 防止SQL注入
String name = "'' or '1=1'";
String password = "'' or '1=1'";
String sql = "select * from users where name=? and password = ?";
// PreparedStatement防止SQL注入的本质,把传递进来的参数当作字符
// 比如:'会被直接转义
PreparedStatement pstm = connection.prepareStatement();
pstm.setString(1,name);
pstm.setString(2,password);
ResultSet rs = pstm.executeQuery();
9.4 ResultSet
查询的结果集,封装所有的查询结果
获得指定的数据类型
resultSet.getObject(); // 不知道列类型的情况下使用
resultSet.getString();
resultSet.getInt();
resultSet.getFloat();
resultSet.getDouble();
resultSet.getDate();
......
遍历,指针
resultSet.next(); // 下一行
resultSet.previous(); // 上一行
resultSet.beforeFirst(); // 最前面
resultSet.afterLast(); // 最后面
resultSet.absolute(row); // 指定行
9.5 释放资源
resultSet.close();
statement.close();
connection.close();