Java的数据库基础(MySQL):SQL命令和JDBC

数据库基础

一、数据库

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 操作数据库

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

  1. 创建数据库

    create database [if not exists] `myDB`;
    
  2. 删除数据库

    drop database [if exists] `myDB`;
    
  3. 使用数据库

    use `myDB`;
    
  4. 查看数据库

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

1.5 数据库的列类型

  1. 数值

    • tinyint:微小的数据(1个字节)
    • smallint:较小的数据(2个字节)
    • mediumint:中等的数据(3个字节)
    • int:标准的数据(4个字节)
    • bigint:较大的数据(8个字节)
    • float:浮点数(4个字节)
    • double:双精度浮点数(8个字节)
    • decimal:字符串形式的浮点数(用于金融计算)
  2. 字符串

    • char:固定长度字符串(0~255)
    • varchar:可变长度字符串(0~65535)
    • tinytext:微型文本(2^8 - 1)
    • text:文本串(2^16 - 1),保存大文本
  3. 时间日期

    java.util.Date

    • date:YYYY-MM-DD,日期格式
    • time:HH:mm:ss,时间格式
    • datetime:YYYY-MM-DD HH:mm:ss
    • timestamp:时间戳,1970.1.1到现在的毫秒数
    • year:年份表示
  4. NULL

    • 没有值,未知
    • 注意,不要用NULL进行运算,结果为NULL

1.6 数据库的字段属性

  1. Unsigned:
    • 无符号的整数
    • 声明该列不能为负数
  2. zerofill:
    • 0填充
    • 不足的位数,用0来填充
    • 例:int(3),5 --> 005
  3. 自增:outo_increment
    • 自动在上一条记录的基础上 +1
    • 通常用来设计唯一的主键,必须是整数类型
    • 可以自定义主键自增的起始值和步长
  4. 非空
    • 设置为not null,如果不赋值,则报错
    • 设置为null,如果不赋值,则为null
  5. 默认
    • 设置默认值
    • 例: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 操作表

所有的创建和删除操作,尽量加上判断,以免报错

  1. 新建表

    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;
    
  2. 查看表

    查看创建语句:

    show create database school; -- 查看创建数据库的语句
    show create table student; -- 查看student数据表的定义语句
    

    查看表的结构:

    desc student;
    
  3. 删除表

    drop table if exists teacher;
    
  4. 更改表

    -- 修改表名
    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 表

  1. 查询所有

    select * from student;
    
  2. 查询指定字段

    select `StudentNo`,`StudentName` from student;
    
  3. 给查询结果起一个别名

    AS,可以给字段起别名,也可以给表起别名

    select `StudentNo` AS 学号,`StudentName` AS 学生姓名 from student;
    
  4. 拼接字符串 concat(a,b)

    select concat('姓名:',StudentName) AS 新名字 from student;
    
  5. 去重 distinct

    去除select查询出来的结果中重复的数据

    -- 查询有哪些学生参加了考试,即有成绩者
    select * from result; -- 查询全部考试成绩
    select `StudentNo` from result; -- 查询哪些学生有成绩
    select distinct `StudentNo` from result; -- 去除重复数据
    
  6. 数据库的列

    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 (判断条件)

sql_joins

操作 描述
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 joinon 等值判断
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固定步骤

  1. 加载驱动
  2. 连接数据库,代表数据库
  3. 向数据库发送SQL的对象Statement:CRUD
  4. 编写SQL(根据业务,不同的SQL)
  5. 执行SQL
  6. 关闭连接
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();

猜你喜欢

转载自blog.csdn.net/yuDong1109/article/details/115416559
今日推荐