B站 MySQL学习随手记 全是满满的干货!

业务级别的MySQL学习与使用


1、数据库分类

1. 关系型数据库(SQL)

  • MySQL,Oracle,SQL Server,DB2,SQLlite
  • 通过表和表之间的,行与列之间的关系进行数据的存储。(例如:学生信息表)

2. 非关系型数据库(NoSQL)Not Only SQL

  • Redis,MongDB
  • 对象存储,通过对象的自身的属性来决定

2、MySQL安装与配置

  1. 下载压缩文件,并解压缩到目标文件夹下

  2. 配置环境变量,例如安装路径为:F:\Environment\mysql-8.0.17-winx64 ,系统环境变量下path中新建填写 F:\Environment\mysql-8.0.17-winx64\bin.环境变量

  3. 安装目录下新建并配置my.ini文件

    [mysql]
    default-character-set=utf8
    [mysqld]
    #注意将这两个路径替换成实际的安装目录
    basedir=F:\Environment\mysql-8.0.17-winx64
    datadir=F:\Environment\mysql-8.0.17-winx64\data
    port=3306
    max_connections=200
    character-set-server=utf8
    default-storage-engine=INNODB
    sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION
    
  4. 管理员身份启动命令提示符,运行mysqld -install命令安装MySQL,显示成功后,再运行mysqld --initialize,初始化数据库,此时安装目录下生成了data文件夹

  5. net start mysql命令启动MySQL,启动成功后,执行mysql -u root -p登录MySQL,此时需要密码,打开data文件夹下的一个.err文件,找到随机密码输入登录.

6.修改密码,执行以下命令:ALTER USER 'root'@'localhost' IDENTIFIED BY 'newpassword';就可以重设密码,然后重启MySQL即可正常使用。


3、MySQL简单的命令行操作

net start mysql --启动数据库服务
mysql -u root -p --连接数据库

--所有的语句都以 分号 结尾
show database; --查看所有数据库

use + 'database name' --切换数据库

show tables; --查看数据库中所有的表
describe student; --显示数据库中所有的表的信息

...

4、数据库语言

  • DDL(数据库定义语言)
  • DML(数据库操作管理语言)
  • DQL(数据库查询语言)
  • DCL(数据库控制语言)

4.1、数据库的数据类型

数值

数据类型数据大小数据说明
tinyint1个字节十分小的数据
smallint2个字节较小的数据
mediumint3个字节中等大小的数据
int(常用)4个字节标准整数
bigint8个字节较大的数据
float4个字节单精度浮点数
double8个字节双精度浮点数
decimal字符串形式的浮点数(金融计算使用)

字符串

数据类型数据大小数据说明
char0~255字符串固定大小(容易造成空间浪费)
varchar(常用)0~65535可变字符串
tinytext2^8 - 1微型文本
text(常用)2^16 - 1文本串

时间日期

类型名称格式描述
dateYYYY-MM-DD日期格式
timeHH:mm:ss时间格式
datetimeYYYY-MM-DD HH:mm:ss常用的时间格式
timestamp1970.1.1到现在的毫秒数时间戳

4.2、拓展

每一个表,都必须存在以下五个字段!未来的项目要求,表示一个记录的存在意义

id 主键
`version` 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间

4.3、navicat中用sql语句创建表

要求创建一个学生表包含以下字段
学号(int)姓名密码性别生日家庭住址邮箱

--注意点:
--1、表名和字段名都尽量用 ``(反单引号) 括起来
--2、所有语句结尾要加逗号

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

格式

CREAT TABLE [IF NOT EXISTS] `表名`(
    `字段名` 列类型 [属性] [索引] [注释],
    `字段名` 列类型 [属性] [索引] [注释],
    ...
    `字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集设置][注释]

4.4、删除和修改数据表

修改

-- 修改表名 ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE `student` RENAME AS `stu`
-- 增加字段 ALTER TABLE 表名 ADD `字段名` 列属性
ALTER TABLE `stu` ADD `age` INT(3) AFTER `sex`

-- 修改表的字段
-- ALTER TABLE 表名 MODIFY 字段名 列属性
ALTER TABLE stu MODIFY age VARCHAR(3) -- 修改约束
-- ALTER TABLE 表名 CHANGE 表名 新表名 列属性
ALTER TABLE stu CHANGE age sage int(3) -- 字段重命名

-- 删除表的字段
-- ALTER TABLE 表名 DROP 字段名
ALTER TABLE stu DROP sage

-- 删除表(先判断是否存在再删除)
DROP TABLE IF EXISTS `tch`
  • 建议所有的创建删除操作尽量加上判断,一面报错

常用命令

show CREATE DATABASE school --查看创建数据库的语句
SHOW CREATE TABLE student --查看创建student数据表的定义语句
DESC student --查看student表的结构

5、数据表类型

5.1关于数据库引擎

  • INNODB 默认使用
  • MYISAM 早期使用
MYISAMINNODB
事务支持不支持支持
数据行锁定不支持支持
外键约束不支持支持
全文索引支持不支持
表空间大小较小较大(约为前者2倍)
优点节约空间,速度快安全性高,多表多用户操作

5.2引擎在物理文件上的区别

  • INNODB 在数据库表中只有一个.frm文件(MySQL8.0后没有),以及上级目录下的ibdata1文件。

  • MYISAM 对应的文件

    • .frm文件 --> 表结构定义文件
    • .MYD文件 --> 数据文件(data)
    • .MYI文件 --> 索引文件(index)

设置数据库表的字符编码

charset=utf8
  • 不设置的话,MySQL的默认的字符集编码会导致中文乱码

6、MySQL数据管理

6.1外键

6.1.1、外键的添加
  • 1、创建时添加
-- 将学生表中的grade字段设置为外键,引用gradelist中的gradeid字段
-- 方式一 自定约束名
KEY `约束名` (`设为外键的字段号`),
constraint `约束名` foreign key (`设为外键的字段号`) references `被引用的表`(`被引用的字段`)

-- 示例
KEY `FK_gradeid` (`grade`),
constraint `FK_gradeid` foreign key (`grade`) references `gradelist`(`gradeid`)

-- 方式二
foreign key (`设为外键的字段号`) references `被引用的表`(`被引用的字段`)
  • 2、创建后修改表添加外键
alter table `表名`
add constraint `约束名` foreign key (`设为外键的字段号`) references `被引用的表`(`被引用的字段`);

-- 示例
ALTER TABLE `stu`
ADD constraint `FK_gradeid` FOREIGN KEY (`grade`) REFERENCES `gradelist` (`gradeID`);

以上的操作都是物理外键,数据库级别的外键,不建议使用!

阿里Java规范:[强制]不得使用外键与级联,一切外键概念必须在应用层(代码层)解决
每次做delete和update都必须考虑外键的约束,会导致开发的时候很痛苦,测试数据极为不方便。

6.1.2、最佳实践
  • 数据库中之存放数据,只有行(数据)和列(字段)。
  • 当需要使用多张表的时候,可以用程序去实现外键。

6.2、DML语言(牢记)

  • DML语言:数据操作语言

    • Insert

      -- 插入数据
      -- 语法:INSERT INTO `表名`([`字段1`,`字段2`,...])VALUES('值1','值2',...)
      -- 值与字段一一对应
      INSERT INTO `gradelist`(`gradeName`)VALUES ('大一');
      
      -- 一次插入多条数据
      INSERT INTO `gradelist`(`gradeName`)VALUES ('大二'),('大三'),('大四');
      
    • update

      -- 修改数据
      -- 语法:UPDATE 表名 set `字段名` = '新值' [where (条件)]
      UPDATE `stu` SET `name` = '路人甲' WHERE `name` = '张三';
      
      -- 若不指定条件 默认修改所有
      UPDATE `stu` SET `name` = '路人'
      
      -- 修改多个数据
      UPDATE `stu`
      SET `grade` = 1,birthday = '2001-7-9' -- 修改的数据用逗号隔开
      WHERE `name` = '路人甲';
      
    • delete

      -- 语法 delete from 表名 [where 条件]
      -- 全部删除(危险操作)
      DELETE FROM `stu`
      
      -- 删除指定数据
      DELETE FROM `stu` where id = 3;
      
      • TRANCATE命令

      作用:完全清空一个数据库表,表的结构和索引约束不会改变

      • delete 与 trancate命令

      相同点:
      都能够删除数据,都不会删除表结构
      不同点:
      TRANCETE 重新设置自增列,计数器归零TRANCATE不会影响事务


7、DQL查询数据(重点)

  • (Data Query LANGUAGE)数据查询语言

7.1、简单的select查询

7.2、联表查询 Join ON

在这里插入图片描述

连接方式描述
Inner Join如果表中有一个匹配项,就返回行
Left Join从左表中返回所有值,即使在右表中没有匹配
Right Join从右表中返回所有值,即使在左表中没有匹配

7.3、分页(limit)和排序 (order by)

limit(起始下标,页面大小)

-- 表示显示从第几条起的多少条数据
select..
from..
where..
...
limit 0,5 -- 显示查询的从第一条开始的五条数据

7.4、聚合函数及分组过滤

7.4.1、常用的聚合函数
函数名描述
Count()计数
SUM()求和
AVG()求平均值
MAX()、MIN()最大、最小值

count(列名),count(1),count(*) 的区别

使用方法区别
count(列名)只包括列名那一列,在统计结果的时候,会忽略列值为空
count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL

后两者本质上区别不大,都不会忽略值为NULL的数据行,在特定的使用场景下,执行效率有所不同

7.4.2、group by (分组)及 having(过滤分组)

group by 是让排序结果按规则进行分组排列
having 与 where用途相似 用来过滤分组中不符合要求的分组

-- 代码示例:
    -- 要求筛选平均分>80的学科
    select SubjectName as '科目',
           AVG(StudentResult) as '平均分',
           MAX(StudentResult) as '最高分',
           MIN(StudentResult) as '最低分'
    FROM result
    LEFT JOIN `subject`
    ON result.SubjectNo = `subject`.SubjectNo
    GROUP BY result.SubjectNo
    HAVING 平均分>80

7.5、(拓展)数据库级别的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 = utf8

  insert into testmd5 values (1,'张三','123456'),(2,'李四','123456'),(3,'王五','123456')

  -- 加密
  UPDATE testmd5
  SET pwd=MD5(pwd)
  WHERE id = 1

  -- 插入时加密
  insert into testmd5 values (4,'小明',MD5('123456'))

  -- 查询校验
  SELECT *
  FROM testmd5
  where `name` = '小明' and pwd = MD5('123456')

7.6、select总结

-- 语法顺序
select [去重] `要查询的字段` [as '别名'] -- 联表查询时避免模棱两可
from `表名`
(Inner/left/right) join `连接的表` on 等值条件
where (具体的值,或者子查询语句)
group by (分组参照)
having (过滤分组的条件) -- 用法与where一样
order by `排序的参考字段` [ASC/DECS] -- 默认递增
limit index,count -- 列出从第index条开始的count条数据

8、事务(Transaction)

8.1、什么是事务

作为单个逻辑工作单元执行的一系列操作,要么都成功,要么都失败


事务的特性(4个) 又叫ACID特性

  • 原子性(Atomicity)
  • 一致性(Consistency)
  • 隔离性(Isolation)
  • 持久性(Durability)

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

原子性(Atomicity):
要么都成功,要么都失败

一致性(Consistency):
事务前后的数据完整性要保证一致

持久性(Durability):
事务一旦提交不可逆,被持久化到数据库中

隔离性(Isolation):
多个用户并发访问数据库时,数据库为每个用户开启事务,不被其他事务的操作所干扰,并发事务之间相互隔离

隔离所导致的一些问题:
脏读,不可重复读,幻读。

8.2、具体实现

-- mysql 默认开启事务自定提交
SET autocommit = 0 -- 关闭
SET autocommit = 1 -- 开启(默认)

-- 简单流程

-- 1、手动处理事务
SET autocommit = 0 -- 关闭自动提交

-- 2、事务开启
START TRANSACTION -- 标记一个事务的开启

/* 之后的sql操作都在这同一个事务内进行 */



-- 3、提交:持久化(成功!)
COMMIT
-- 3、回滚:回到起始状态(失败!)
ROLLBACK

-- 4、事务结束
SET autocommit = 1 -- 开启自动提交


-- 拓展了解
SAVEPOINT `保存点名` --设置一个事务的保存点
ROLLBACK TO SAVEPOINT `保存点名` --若事务失败 回滚到上一个保存点
RELEASE SAVEPOINT `保存点名`  -- 撤销保存点

8.2.1、模拟场景
-- =======模拟转账场景=========
CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci

USE shop

  CREATE TABLE `account`(
    `id` INT(3) NOT NULL auto_increment,
    `name` VARCHAR(10) not NULL,
    `money` DECIMAL(9,2) NOT NULL,
    PRIMARY KEY(`id`)
)ENGINE = INNODB CHARSET = utf8

INSERT INTO `account`(`name`,`money`) VALUES ('A','2000'),('B','10000')

SET autocommit = 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;

9、索引

索引(index)是帮助MySQL高效获取数据的数据结构。

9.1、索引的分类

在一个表中,主键索引只能有一个,而唯一索引可以有多个

  • 主键索引(primary key)

    唯一的标识,主键不可重复,只能有一个列作为主键

  • 唯一索引(unique key)

    避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引

  • 常规索引(index/key)

    默认,用index/key关键字设置

  • 全文索引(FullText)

    快速定位数据位置

9.2、基础语法

-- =======索引的使用=====
-- 显示所有索引信息
show index from student

-- 增加一个索引 add fulltext index `索引名`(`列名`)
alter table student add fulltext index `studentname`(`studentname`)

-- 删除索引:
DROP INDEX 索引名 ON 表名字;
-- 删除主键索引:
ALTER TABLE 表名 DROP PRIMARY KEY;

-- explain 分析sql执行状况
explain select * from student

explain select * from student where match(studentname) against ('刘')

9.3、测试索引

  SELECT *
  FROM app_user
  where  `name` = '用户99999'  -- 创建索引前 > 时间: 1.924s
                              -- 创建索引后 > 时间: 0.083s

  -- 索引名 命名规范 id_表名_字段名
  -- CREATE INDEX 索引名 ON 表(字段)
  CREATE INDEX id_app_user_name ON app_user(`name`);

在这里插入图片描述
在这里插入图片描述

从测试结果可以发现索引显著提高了大量数据的查询性能

9.4、索引原则

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

索引的数据结构

Hash类型的索引
Btree:InnoDB的默认数据结构

推荐阅读 MySQL索引背后的数据结构及算法原理


10、权限管理与数据库备份

10.1、用户管理

可视化窗口管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaEaWt5D-1581391881960)(Mysql学习文件/用户管理.png)]

SQL命令

系统数据库中有一用户表即:mysql.user,
本质上还是对表数据的增删改查。

-- 创建用户  CREATE USER 用户名 IDENTIFIED BY '密码'
CREATE USER sakura0817 IDENTIFIED BY '170312'

-- 修改密码(修改当前用户密码)
SET password = '170312';

-- 修改密码(修改指定用户密码)
set password FOR sakura0817 = '170312'

-- 用户重命名
RENAME USER sakura0817 TO 5akura

-- 用户授权 all privileges全部的权限 (Grant Option)无法授予
grant all privileges on *.* to 5akura

-- 查看权限
show grants for 5akura -- 查看指定用户
show grants for root@localhost -- 查看管理员

-- 撤销权限
REVOKE ALL PRIVILEGES ON *.* FROM 5akura

-- 删除用户
DROP USER 5akura

10.2、MySQL备份

备份方式

  • 直接拷贝data文件夹
  • 在可视化工具中手动导出
  • 使用命令行
模板:
mysqldump -h主机地址 -u用户名 -p密码 数据库名 表名 >导出路径
示例:
mysqldump -hlocalhost -uroot -p170312 shop >F:/文档文件/shop.sql

# 导入
登陆后
source 备份文件

11、数据库的规约,三大范式

11.1、为什么要需要设计

当数据较复杂时,我们需要设计数据库辅助管理数据

  • 糟糕的数据库设计

数据冗余,浪费空间

数据库插入删除操作麻烦、产生异常[屏蔽使用物理外键]

程序的性能差

  • 良好的数据库设计

节省内存空间

保证数据库的完整性

方便我们开发系统

  • 关于数据库的设计

    • 分析需求:分析业务和需要处理的数据库要求
    • 概要设计:设计关系的ER图
  • 数据库设计具体步骤(个人博客为例)

    • 收集信息,分析需求

      • 用户表(用户登录注销,用户个人信息,写博客,创建分类)
      • 分类表(文章分类,创建者)
      • 文章类(文章的信息)
      • 评论表
      • 友联表(友链信息)
      • 自定义表(系统信息,某个关键字,或者一些主字段)
    • 标识实体(将每个需求落地到每个关键字)

11.2、三大范式

11.1、为什么要需要设计

当数据较复杂时,我们需要设计数据库辅助管理数据

  • 糟糕的数据库设计

数据冗余,浪费空间

数据库插入删除操作麻烦、产生异常[屏蔽使用物理外键]

程序的性能差

  • 良好的数据库设计

节省内存空间

保证数据库的完整性

方便我们开发系统

  • 关于数据库的设计

    • 分析需求:分析业务和需要处理的数据库要求
    • 概要设计:设计关系的ER图
  • 数据库设计具体步骤(个人博客为例)

    • 收集信息,分析需求

      • 用户表(用户登录注销,用户个人信息,写博客,创建分类)
      • 分类表(文章分类,创建者)
      • 文章类(文章的信息)
      • 评论表
      • 友联表(友链信息)
      • 自定义表(系统信息,某个关键字,或者一些主字段)
    • 标识实体(将每个需求落地到每个关键字)

    • 标识实体之间的关系

11.2、三大范式(数据库设计规范)

  • 为什么需要数据规范化

    • 信息重复
    • 更新异常
    • 插入异常
    • 删除异常
11.2.1、三大范式具体内容

第一范式(1NF)

  • 要求数据库表中属性都是不可再分的原子数据项

第二范式(2NF)

  • 在1NF的基础上,所有的非码属性必须完全依赖于候选码(消除部份依赖)。

第三范式(3NF)

  • 在2NF的基础上,任何非主属性不依赖与其他任何非主属性(消除传递依赖)。
11.2.2、规范性与性能问题

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

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

12、JDBC(重点!!)

12.1、简介

12.1.2、数据库驱动

程序 连接访问 数据库 需要通过数据库驱动

12.1.2、JDBC是什么

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U86KlsIb-1582618981763)(JDBC是什么.png)]

由于不同数据库的驱动都不相同,操作也各不相同


SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库)规范,俗称JDBC,规范的实现由各个厂商去做,开发人员只需要掌握JDBC接口的使用即可。

12.2、第一个JDBC程序

12.2.1、创建测试数据库
  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 values (1,'张三','123456','zs@sina.com','1999-12-03'),
  (2,'李四','123456','ls@sina.com','1997-11-13'),
  (3,'王五','123456','ww@sina.com','2000-2-08');
12.2.2、编写Java程序
  1. 创建一个空项目
  2. 导入数据库驱动jar包
  3. 编写Java程序
package com.sakura.jdbcstudy;

import java.sql.*;

/**
 * 第一个JDBC程序
 *
 * @author 桜
 * @Date 2020/2/11
 */
public class JDBC_demo01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {

        //1、加载驱动
        /**
         * com.mysql.jdbc
         * 使用新版驱动 com.mysql.cj.jdbc
         */
        Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法

        //2、用户信息和url
        /**
         * ?:访问链接
         * 三个参数:
         * useUnicode=true 支持中文编码
         * characterEncoding=utf8 字符集utf-8
         * useSSL=true 使用安全链接
         */
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
        String userName = "root";
        String passWord = "170312";

        //3、连接成功,获取数据库对象(getConnection(url,username,password)方法)  返回对象为数据库
        Connection connection = DriverManager.getConnection(url, userName, passWord);

        //4、执行SQL对象(createStatement()方法)
        Statement statement = connection.createStatement();

        //5、SQL的对象去执行SQL(若有执行结果,需要查看返回结果)
        String sql = "select * from users";

        ResultSet resultSet = statement.executeQuery(sql);//执行sql查询语句,并返回封装好的结果集;

        //解读结果集 getObject(列名)
        while (resultSet.next()) {
            System.out.println("id = "+resultSet.getObject("id"));
            System.out.println("name = "+resultSet.getObject("NAME"));
            System.out.println("password = "+resultSet.getObject("PASSWORD"));
            System.out.println("email = "+resultSet.getObject("email"));
            System.out.println("birth = "+resultSet.getObject("birthday"));
            System.out.println("-------------------");
        }

        //6、关闭连接
        resultSet.close();
        statement.close();
        connection.close();

    }
}

12.2.3、代码步骤总结
  1. 加载驱动(使用新版驱动com.mysql.cj.jdbc.Driver
  2. 与数据库建立连接,获取Connection对象(DriverManager.getConnection()
  3. 获取执行sql语句的Statement对象(connection.creatStatement()
  4. 执行sql语句获得结果集
  5. 释放连接
12.2.4、代码详细
创建驱动
    //DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
    Class.forName("com.mysql.cj.jdbc.Driver"); //固定写法
package com.mysql.cj.jdbc;

import java.sql.DriverManager;
import java.sql.SQLException;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            //注册驱动
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

可以看到在com.mysql.cj.jdbc.Driver()类中有一个静态代码块会在加载时自动执行注册驱动,所以只需用forname()方法即可,因为对类进行反射调用,一定会引发类初始化从而执行驱动的注册


URL
  String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

  // 协议/主机地址:端口号/数据库名?参数1&参数2&参数3

  //mysql-->3306,Oracle-->1521
  //jdbc:oracle:thin@localhost:1521:sid

Connection (代表数据库)
//能执行大多数数据库中的操作
connection.rollback();//事务回滚
connection.commit();//事务提交
connection.setAutoCommit();//设置自动提交

执行SQL的对象
  • statement(不安全)
//可以执行多种SQL语句
statement.executeQuery();//查询  返回查询结果集
statement.executeUpdate();// 更新,插入,删除 返回受影响行数
statement.execute();//执行所有SQL语句
statement.executeBatch();//批次处理
  • connection.prepareStatement()(防止SQL注入)

ResultSet(只有查询有结果集返回)
  • 获取数据
resultSet.getObject()//在不清楚列数据类型时使用
//如果知道列类型就使用指定方法get数据
getString(),getFloat(),getDate(),....
  • 遍历(指针)
resultSet.next();//下一条
resultSet.previous();//上一条
resultSet.beforeFirst();//第一条
resultSet.afterLast();//最后一条
resultSet.absolute();//指定行

资源释放
resultSet.close();
statement.close();
connection.close();//耗费资源,用完即关

12.3、SQL注入的问题

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

  • 数据输入过滤不严格,通过SQL拼接字符串 or,进入数据库盗取数据。
public class SQL注入 {

    public static void main(String[] args) {
        login(" 'or '1=1","123456");
    }

    public static void login(String userName, String password) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();
            statement = connection.createStatement();

            //SQL语言
            String sql = "select * from users where `NAME`= '"+userName+"' and `passWord` = '" +password+ "'";


            resultSet = statement.executeQuery(sql);
            while (resultSet.next()) {
                System.out.println("NAME = "+resultSet.getString("NAME")+"--> email = " + resultSet.getString("email"));
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.release(connection, statement, resultSet);
        }
    }
}

12.4、PreparedStatement对象

  • 可以防止SQL注入,效率更高。
public class TestInsert {
    public static void main(String[] args) {
        Connection connection =null;
        PreparedStatement preparedStatement =null;
        ResultSet resultSet = null;
        try {
            connection = JdbcUtils.getConnection();

            //区别
            //1、使用 '?'占位符代替数据作为参数
            String sql = "insert into users(id, `NAME`, `passWord`, email, birthday) values(?,?,?,?,?)";

            //2、预编译SQL,先写SQL,但是不执行
            preparedStatement = connection.prepareStatement(sql);

            //3、手动参数赋值
            // preparedStatement.setObject(); 不清楚列类型时使用
            /**
             * 参数为(列标,具体数据)
             * 1代表第一个字段,2代表第二个字段....
             */
            preparedStatement.setInt(1,5);//设置id
            preparedStatement.setString(2,"官宇辰");//设置name
            preparedStatement.setString(3,"170312");//设置passWord
            preparedStatement.setString(4,"G843452233@outlook.com");//设置email
            // 注意点 sql.Date 与 util.Date 不同
            preparedStatement.setDate(5,new Date(new SimpleDateFormat("yyyy-MM-dd").parse("2000-08-17").getTime()));//设置birthday

            //4、执行 直接执行无需传参
            int i = preparedStatement.executeUpdate();
            if (i>0) {
                System.out.println("操作成功");
            }

        } catch (SQLException | ParseException e) {
              e.printStackTrace();
        } finally {
             //...释放资源
            JdbcUtils.release(connection, preparedStatement, resultSet);

        }
      }
}
  • PreparedStatement 如何避免SQL注入

本质:把传入的参数当作字符,把用户非法输入的单引号用\反斜杠做了转义,就避免了参数也作为条件的一部分。

12.5、IDEA连接Mysql 处理事务

  1. 开启事务connection.setAutoCommit(false);
  2. 一组业务执行完毕,提交事务。
  3. 可以在catch语句中显式的定义回滚语句,但默认失败了就会回滚。

代码实现

public class TestTransacation02 {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JdbcUtils.getConnection();
            //关闭数据自动提交,会自动开启事务
            connection.setAutoCommit(false);

            String sql1 = "update account set money = money - 100 where name = 'A'"; //A转出100
            preparedStatement = connection.prepareStatement(sql1);
            preparedStatement.executeUpdate();



            String sql2 = "update account set money = money + 100 where name = 'B'"; //B入账100
            preparedStatement = connection.prepareStatement(sql2);
            preparedStatement.executeUpdate();

            //业务完毕,提交事务
            connection.commit();
            System.out.println("转账成功");


        } catch (SQLException e) {
            try {
                connection.rollback(); //失败回滚
                System.out.println("转账失败");
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            JdbcUtils.release(connection, preparedStatement, resultSet);
        }
    }
}

12.6、数据库连接池

产生原因:因为数据库的连接与释放 十分浪费系统资源


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

  • 常用连接数
  • 最小连接数
  • 最大连接数(业务最高承载上限)
    • 等待超时

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZN9t0Nru-1582618981766)(dbcp实现接口.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c5LRonNM-1582618981767)(c3p0继承接口.png)]


优秀的开源数据源实现(使用后,项目开发中不需要编写连接数据库的代码了)

  • DBCP(commons-dbcp-1.4.jar,commons-pool-1.6.jar)
  • C3P0
  • Druid(阿里巴巴)

结论

无论使用什么数据源,本质都是一样,都要实现DataSource接口,方法不变,只是不同的实现方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值