zoukankan      html  css  js  c++  java
  • MySQL入门


    参考视频遇见狂神说-mysql

    一、初识MySQL

    1.命令行

    1.进入root账户
    mysql -u root -p

    2.查看所有的数据库
    show databases;

    3.切换数据库
    use [databases_name]

    4.查看数据库中所有表
    show tables;

    5.显示数据库中所有的表的信息
    describe [tables_name];

    6.创建一个数据库
    create database [databases_name]

    7.退出链接
    exit;

    8.单行注释
    --

    9.多行注释
    /**/

    二、操作数据库

    2.操作数据库

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

    1.创建数据库

    create database [if not exists] westos;
    

    2.删除数据库

    drop database [if exists] westos;
    

    3.使用数据库

    use `school`;
    

    4.查看数据库

    show databases;
    

    3.数据库的列类型

    3.1 数据

    tinyint 十分小的数据 1字节
    smallint 较小的数据 2字节
    mediumint 中等大小的数据 3字节
    int 数据 4字节
    bigint 较大的数据 8字节
    float 浮点数 4字节
    double 浮点数 8字节
    decimal 字符串形式的浮点数 金融计算的时候,一般用decimal

    3.2 字符串

    char 字符串固定大小的 0-255
    varchar 可变字符串 0-65535 常用的 类似于java的String
    tinytext 微型文本 2^8-1
    text 文本串 2^16-1 保存大文本

    3.3 时间日期

    java.util.Date

    • Date YYYY-MM-DD 日期格式

    • Time HH: mm: ss 时间格式

    • Datetime YYYY-MM-DD HH: MM: ss 最常用的时间格式

    • Timestamp 时间戳 1970.1.1到现在的毫秒数也较为常用

    • Year 年份表示

    3.4 null

    • 没有值,未知
    • 不要使用null进行运算

    4.!数据库的字段属性

    4.1 unsighed:

    • 无符号的整数
    • 声明了该列不能声明为负数

    4.2 zerofill

    • 0填充的
    • 不足的位数,用0填充,int(3), 5 ... 005

    4.3 自增aoto_increment

    • 通常理解为自增,自动在上一条记录的基础上+1
    • 通常用来设计唯一主键~index,必须是整数类型
    • 可以自定义设计自增的起步值和步长

    4.4 非空NUll not null

    • 假设设为not null,如果不赋值,就会报错
    • Null如果不填写值,默认就是NULL

    4.5 默认defaut

    • 设置默认的值
    • Sex 默认值为男,如果不指定该列的值,则会有默认的值

    4.6 拓展

    //每一个主键都应该存在一下5个字段
     
        `id`      主键
    `version`     乐观锁
    `is_delete`   伪删除
    `gmt_create`  创建时间
    `gmt_update`  修改时间
    

    5.!创建数据库表

    5.1 实例

    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(20) 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;
    

    5.2 格式

    create table [if not exists] `表名`(
        `字段名` 列类型 [属性] [索引] [注释],
        `字段名` 列类型 [属性] [索引] [注释],
        ...
        `字段名` 列类型 [属性] [索引] [注释],
    )[表类型][字符集设置][注释]
    

    5.3 常用命令

    SHOW CREATE DATABASE `school`; --查看数据库创建
    SHOW CREATE TABLE student; --查看表创建
    DESC `student`;  --查看表的细节
    

    6.数据表的类型

    6.1 MYISAM与INNODB对比

        /*
        INNODB 默认使用
        MYISAM 早些年使用
        */
    
    MYISAM INNODB
    事务支持 不支持 支持
    数据行锁定 不支持 支持
    外键约束 不支持 支持
    全文索引 支持 不支持
    表空间的大小 较小 较大,约为MYISAM的两倍
    常规使用操作:
    • MYISAM 节约空间,速度较快
    • INNODB 安全性高,支持事务处理,多表多用户操作

    6.2 在物理空间存在的位置

    所有的数据库文件都存在data目录下
    本质还是文件的存储

    6.3 MySQL引擎在物理文件上的区别

    • InnoDB 在数据库表中只有一个*.frm文件,以及上级文件目录的ibdata1文件
    • MYISAM对应文件
      • *.frm 表结构的定义文件
      • *.MYD 数据文件(data)
      • *.MYI 索引文件(index)

    6.4 设置数据库表的字符集编码

    charset=utf8
    

    不设置的话,会是mysql默认的字符集编码latin1(不支持中文)

    7.修改删除表

    7.1 修改

    7.1.1 修改表名

    -- alter table [old_table_name] as [new_table_name];
    -- 范例:
    alter table student as teacher;
    

    7.1.2 增加表的字段

    -- alter table [table_name] add [字段名] [列属性];
    -- 示例:
    alter table teacher add age int(3);
    

    7.1.3 修改表的字段

    alter table teacher modify age varchar(11);  -- 修改约束
    alter table teacher change age age1 int(1);  -- 字段重命名 现在也可以修改约束
    

    7.2 删除

    7.2.1 删除表的字段

    alter table teacher drop age1;
    

    7.2.2 删除表(如果表存在再删除)

    drop table if exists teacher1;
    

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

    三、MySQL数据管理

    8.外键(了解)

    图8.1:
    图8.1

    • 将student(若为其他名,省略该步)删除
    drop table student;
    
    • 添加如下表:
    CREATE TABLE `grade`(
        `gradeId` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
        `gradeName` VARCHAR(50) NOT NULL COMMENT '年级名称',
        PRIMARY KEY(`gradeId`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8;
    

    8.1 添加外键的三种方式

    8.1.1 创建表时添加约束

    -- 学生表的 gradeId 字段 要去引用年级表的 gradeId
    -- 定义外键key
    -- 给这个外键添加约束(执行引用) references 引用
    -- constraint 限制,约束
    -- foreign 涉外的 外国的
    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(20) not null default '女' comment '性别',
        `birthday` datetime default null comment '生日',
        `gradeId` int(10) not 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 references `grade` (`gradeid`)
    )engine=INNODB default charset = utf8;
    

    8.1.2 修改外键关系

    alter table `student` add constraint `FK_gradeId` foreign key (`gradeId`) references `grade`(`gradeId`);
    
    alter table [slave-table-name] add constraint `FK_slave-key` foreign key (`slave-key`) references `master-table-name` (`masger-key`) 
    

    以上操作都是物理外键,是数据库级别的外键不建议使用!(避免数据库过多造成困扰)

    8.1.3 最佳实践

    • 数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)
    • 我们想使用多张表的数据,想使用外键(程序去实现)

    9.!DML语言(全部记住)

    数据库意义: 数据存储,数据管理
    DML语言: 数据操作语言

    • Insert
    • update
    • delete

    9.1 添加

    -- 插入语句,添加
    insert into 表名([字段名1,字段名2,字段3])values(`值1`),(`值2`),(`值3`),(...);
    
    insert into `grade` (`gradeName`) values('大四')
    
    -- 由于主键自增可以省略,如果不写表的字段,就会一一匹配
    insert into `grade` values('大四'); -- 发生错误
    
    -- 相当于:
    insert into `grade`(`gradeId`,`gradeName`) values('大四',null);
    

    尽量写上字段名
    案例:

    insert into student(`name`,`pwd`,`sex`) values('zhangshan','aaaaaa','man');
    
    insert into `student`(`name`,`pwd`,`sex`) values('张三','aaaa','男'),
    ('李四','bbbb','男');
    

    9.2 修改

    1. 语法1:
    update 修改谁 (条件) set 原来的值 = 新值; 
    

    案例:

    update `student` set name='狂神' where id = 1;
    
    不指定条件的情况下,会改变所有的值
    ~~只能删库跑路~~
    1. 语法2:
    update 表名 set colnum_name = value,[colnum_name = value,...] where [条件]
    
    -- 修改多个属性
    update `student` set `name` = '狂神', email = '24736743@qq.com' where id=1;
    

    条件:where子句 运算符 id等于某个值 大于某个值 再某个区间

    操作符会返回布尔值

    操作符 含义 范围 结果
    == 等于 5=6 false
    <>或!= 不等于 5<>6 true

    |||
    <|||
    =|||
    <=|||
    between ... and ...|[2,5]|在某个范围内|
    and|&&||
    or|或||

    -- 通过多个条件定位数据
    update `student` set `name`='长江7号' where name='狂神' and sex=`女`;
    

    注意:

    • colnum_name是数据库的列,尽量带上``
    • 条件,是筛选的条件,如果没有指定,则会修改所有的列
    • value,是一个具体的值,也可以是一个变量,如:
      update `student` set `birthday` = current_time where `name`= '长江7号' and `sex` = '女';
      

    9.3 删 除

    9.3.1 删除

    语法

    delete from 表名 [where 条件];
    
    -- 例子
    delete from `student` where id = 3;
    

    9.3.2 清空

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

    truncate 表名;
    
    truncate `student`;
    

    9.3.3 delete和truncate区别

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

    了解:delete删除的问题,重启数据库现象:

    • InnoDB 自增列会从1开始(存在内存当中的,断电即失)
    • MyISAM 继续从上一个自增量开始(存在文件中的,不会丢失)

    四、!!DQL查询数据(最重点)

    10.DQL

    (Data Query Language:数据查询语言)

    • 所有的查询操作都用它 select
    • 简单的查询,复杂的查询都能做
    • 数据库中最核心的语言,最重要的语句
    • 使用频率最高的语句

    10.1 select语法

    
    SELECT [ALL | DISTINCT]
    {* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
    FROM table_name [as table_alias]
        [left | right | inner join table_name2]  #联合查询
        [WHERE ...]  #指定结果需满足的条件
        [GROUP BY ...]  #指定结果按照哪几个字段来分组
        [HAVING]  #过滤分组的记录必须满足的次要条件
        [ORDER BY ...]  #指定查询记录按一个或多个条件排序
        [LIMIT {[offset,]row_count | row_countOFFSET offset}];
        # 指定查询的记录从哪条至哪条
    

    注意 : [ ] 括号代表可选的 , { }括号代表必须得

    提供素材:

    /*
    SQLyog Ultimate v10.00 Beta1
    MySQL - 5.7.19 : Database - school
    *********************************************************************
    */
    
    
    /*!40101 SET NAMES utf8 */;
    
    /*!40101 SET SQL_MODE=''*/;
    
    /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
    /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
    /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
    /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
    CREATE DATABASE /*!32312 IF NOT EXISTS*/`school` /*!40100 DEFAULT CHARACTER SET utf8 */;
    
    USE `school`;
    
    /*Table structure for table `grade` */
    
    DROP TABLE IF EXISTS `grade`;
    
    CREATE TABLE `grade` (
      `GradeID` INT(11) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
      `GradeName` VARCHAR(50) NOT NULL COMMENT '年级名称',
      PRIMARY KEY (`GradeID`)
    ) ENGINE=INNODB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
    
    /*Data for the table `grade` */
    
    INSERT  INTO `grade`(`GradeID`,`GradeName`) VALUES (1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');
    
    /*Table structure for table `result` */
    
    DROP TABLE IF EXISTS `result`;
    
    CREATE TABLE `result` (
      `StudentNo` INT(4) NOT NULL COMMENT '学号',
      `SubjectNo` INT(4) NOT NULL COMMENT '课程编号',
      `ExamDate` DATETIME NOT NULL COMMENT '考试日期',
      `StudentResult` INT(4) NOT NULL COMMENT '考试成绩',
      KEY `SubjectNo` (`SubjectNo`)
    ) ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    /*Data for the table `result` */
    
    INSERT  INTO `result`(`StudentNo`,`SubjectNo`,`ExamDate`,`StudentResult`) VALUES (1000,1,'2013-11-11 16:00:00',94),(1000,2,'2012-11-10 10:00:00',75),(1000,3,'2011-12-19 10:00:00',76),(1000,4,'2010-11-18 11:00:00',93),(1000,5,'2013-11-11 14:00:00',97),(1000,6,'2012-09-13 15:00:00',87),(1000,7,'2011-10-16 16:00:00',79),(1000,8,'2010-11-11 16:00:00',74),(1000,9,'2013-11-21 10:00:00',69),(1000,10,'2012-11-11 12:00:00',78),(1000,11,'2011-11-11 14:00:00',66),(1000,12,'2010-11-11 15:00:00',82),(1000,13,'2013-11-11 14:00:00',94),(1000,14,'2012-11-11 15:00:00',98),(1000,15,'2011-12-11 10:00:00',70),(1000,16,'2010-09-11 10:00:00',74),(1001,1,'2013-11-11 16:00:00',76),(1001,2,'2012-11-10 10:00:00',93),(1001,3,'2011-12-19 10:00:00',65),(1001,4,'2010-11-18 11:00:00',71),(1001,5,'2013-11-11 14:00:00',98),(1001,6,'2012-09-13 15:00:00',74),(1001,7,'2011-10-16 16:00:00',85),(1001,8,'2010-11-11 16:00:00',69),(1001,9,'2013-11-21 10:00:00',63),(1001,10,'2012-11-11 12:00:00',70),(1001,11,'2011-11-11 14:00:00',62),(1001,12,'2010-11-11 15:00:00',90),(1001,13,'2013-11-11 14:00:00',97),(1001,14,'2012-11-11 15:00:00',89),(1001,15,'2011-12-11 10:00:00',72),(1001,16,'2010-09-11 10:00:00',90),(1002,1,'2013-11-11 16:00:00',61),(1002,2,'2012-11-10 10:00:00',80),(1002,3,'2011-12-19 10:00:00',89),(1002,4,'2010-11-18 11:00:00',88),(1002,5,'2013-11-11 14:00:00',82),(1002,6,'2012-09-13 15:00:00',91),(1002,7,'2011-10-16 16:00:00',63),(1002,8,'2010-11-11 16:00:00',84),(1002,9,'2013-11-21 10:00:00',60),(1002,10,'2012-11-11 12:00:00',71),(1002,11,'2011-11-11 14:00:00',93),(1002,12,'2010-11-11 15:00:00',96),(1002,13,'2013-11-11 14:00:00',83),(1002,14,'2012-11-11 15:00:00',69),(1002,15,'2011-12-11 10:00:00',89),(1002,16,'2010-09-11 10:00:00',83),(1003,1,'2013-11-11 16:00:00',91),(1003,2,'2012-11-10 10:00:00',75),(1003,3,'2011-12-19 10:00:00',65),(1003,4,'2010-11-18 11:00:00',63),(1003,5,'2013-11-11 14:00:00',90),(1003,6,'2012-09-13 15:00:00',96),(1003,7,'2011-10-16 16:00:00',97),(1003,8,'2010-11-11 16:00:00',77),(1003,9,'2013-11-21 10:00:00',62),(1003,10,'2012-11-11 12:00:00',81),(1003,11,'2011-11-11 14:00:00',76),(1003,12,'2010-11-11 15:00:00',61),(1003,13,'2013-11-11 14:00:00',93),(1003,14,'2012-11-11 15:00:00',79),(1003,15,'2011-12-11 10:00:00',78),(1003,16,'2010-09-11 10:00:00',96),(1004,1,'2013-11-11 16:00:00',84),(1004,2,'2012-11-10 10:00:00',79),(1004,3,'2011-12-19 10:00:00',76),(1004,4,'2010-11-18 11:00:00',78),(1004,5,'2013-11-11 14:00:00',81),(1004,6,'2012-09-13 15:00:00',90),(1004,7,'2011-10-16 16:00:00',63),(1004,8,'2010-11-11 16:00:00',89),(1004,9,'2013-11-21 10:00:00',67),(1004,10,'2012-11-11 12:00:00',100),(1004,11,'2011-11-11 14:00:00',94),(1004,12,'2010-11-11 15:00:00',65),(1004,13,'2013-11-11 14:00:00',86),(1004,14,'2012-11-11 15:00:00',77),(1004,15,'2011-12-11 10:00:00',82),(1004,16,'2010-09-11 10:00:00',87),(1005,1,'2013-11-11 16:00:00',82),(1005,2,'2012-11-10 10:00:00',92),(1005,3,'2011-12-19 10:00:00',80),(1005,4,'2010-11-18 11:00:00',92),(1005,5,'2013-11-11 14:00:00',97),(1005,6,'2012-09-13 15:00:00',72),(1005,7,'2011-10-16 16:00:00',84),(1005,8,'2010-11-11 16:00:00',79),(1005,9,'2013-11-21 10:00:00',76),(1005,10,'2012-11-11 12:00:00',87),(1005,11,'2011-11-11 14:00:00',65),(1005,12,'2010-11-11 15:00:00',67),(1005,13,'2013-11-11 14:00:00',63),(1005,14,'2012-11-11 15:00:00',64),(1005,15,'2011-12-11 10:00:00',99),(1005,16,'2010-09-11 10:00:00',97),(1006,1,'2013-11-11 16:00:00',82),(1006,2,'2012-11-10 10:00:00',73),(1006,3,'2011-12-19 10:00:00',79),(1006,4,'2010-11-18 11:00:00',63),(1006,5,'2013-11-11 14:00:00',97),(1006,6,'2012-09-13 15:00:00',83),(1006,7,'2011-10-16 16:00:00',78),(1006,8,'2010-11-11 16:00:00',88),(1006,9,'2013-11-21 10:00:00',89),(1006,10,'2012-11-11 12:00:00',82),(1006,11,'2011-11-11 14:00:00',70),(1006,12,'2010-11-11 15:00:00',69),(1006,13,'2013-11-11 14:00:00',64),(1006,14,'2012-11-11 15:00:00',80),(1006,15,'2011-12-11 10:00:00',90),(1006,16,'2010-09-11 10:00:00',85),(1007,1,'2013-11-11 16:00:00',87),(1007,2,'2012-11-10 10:00:00',63),(1007,3,'2011-12-19 10:00:00',70),(1007,4,'2010-11-18 11:00:00',74),(1007,5,'2013-11-11 14:00:00',79),(1007,6,'2012-09-13 15:00:00',83),(1007,7,'2011-10-16 16:00:00',86),(1007,8,'2010-11-11 16:00:00',76),(1007,9,'2013-11-21 10:00:00',65),(1007,10,'2012-11-11 12:00:00',87),(1007,11,'2011-11-11 14:00:00',69),(1007,12,'2010-11-11 15:00:00',69),(1007,13,'2013-11-11 14:00:00',90),(1007,14,'2012-11-11 15:00:00',84),(1007,15,'2011-12-11 10:00:00',95),(1007,16,'2010-09-11 10:00:00',92),(1008,1,'2013-11-11 16:00:00',96),(1008,2,'2012-11-10 10:00:00',62),(1008,3,'2011-12-19 10:00:00',97),(1008,4,'2010-11-18 11:00:00',84),(1008,5,'2013-11-11 14:00:00',86),(1008,6,'2012-09-13 15:00:00',72),(1008,7,'2011-10-16 16:00:00',67),(1008,8,'2010-11-11 16:00:00',83),(1008,9,'2013-11-21 10:00:00',86),(1008,10,'2012-11-11 12:00:00',60),(1008,11,'2011-11-11 14:00:00',61),(1008,12,'2010-11-11 15:00:00',68),(1008,13,'2013-11-11 14:00:00',99),(1008,14,'2012-11-11 15:00:00',77),(1008,15,'2011-12-11 10:00:00',73),(1008,16,'2010-09-11 10:00:00',78),(1009,1,'2013-11-11 16:00:00',67),(1009,2,'2012-11-10 10:00:00',70),(1009,3,'2011-12-19 10:00:00',75),(1009,4,'2010-11-18 11:00:00',92),(1009,5,'2013-11-11 14:00:00',76),(1009,6,'2012-09-13 15:00:00',90),(1009,7,'2011-10-16 16:00:00',62),(1009,8,'2010-11-11 16:00:00',68),(1009,9,'2013-11-21 10:00:00',70),(1009,10,'2012-11-11 12:00:00',83),(1009,11,'2011-11-11 14:00:00',88),(1009,12,'2010-11-11 15:00:00',65),(1009,13,'2013-11-11 14:00:00',91),(1009,14,'2012-11-11 15:00:00',99),(1009,15,'2011-12-11 10:00:00',65),(1009,16,'2010-09-11 10:00:00',83),(1010,1,'2013-11-11 16:00:00',83),(1010,2,'2012-11-10 10:00:00',87),(1010,3,'2011-12-19 10:00:00',89),(1010,4,'2010-11-18 11:00:00',99),(1010,5,'2013-11-11 14:00:00',91),(1010,6,'2012-09-13 15:00:00',96),(1010,7,'2011-10-16 16:00:00',72),(1010,8,'2010-11-11 16:00:00',72),(1010,9,'2013-11-21 10:00:00',98),(1010,10,'2012-11-11 12:00:00',73),(1010,11,'2011-11-11 14:00:00',68),(1010,12,'2010-11-11 15:00:00',62),(1010,13,'2013-11-11 14:00:00',67),(1010,14,'2012-11-11 15:00:00',69),(1010,15,'2011-12-11 10:00:00',71),(1010,16,'2010-09-11 10:00:00',66),(1011,1,'2013-11-11 16:00:00',62),(1011,2,'2012-11-10 10:00:00',72),(1011,3,'2011-12-19 10:00:00',96),(1011,4,'2010-11-18 11:00:00',64),(1011,5,'2013-11-11 14:00:00',89),(1011,6,'2012-09-13 15:00:00',91),(1011,7,'2011-10-16 16:00:00',95),(1011,8,'2010-11-11 16:00:00',96),(1011,9,'2013-11-21 10:00:00',89),(1011,10,'2012-11-11 12:00:00',73),(1011,11,'2011-11-11 14:00:00',82),(1011,12,'2010-11-11 15:00:00',98),(1011,13,'2013-11-11 14:00:00',66),(1011,14,'2012-11-11 15:00:00',69),(1011,15,'2011-12-11 10:00:00',91),(1011,16,'2010-09-11 10:00:00',69),(1012,1,'2013-11-11 16:00:00',86),(1012,2,'2012-11-10 10:00:00',66),(1012,3,'2011-12-19 10:00:00',97),(1012,4,'2010-11-18 11:00:00',69),(1012,5,'2013-11-11 14:00:00',70),(1012,6,'2012-09-13 15:00:00',74),(1012,7,'2011-10-16 16:00:00',91),(1012,8,'2010-11-11 16:00:00',97),(1012,9,'2013-11-21 10:00:00',84),(1012,10,'2012-11-11 12:00:00',82),(1012,11,'2011-11-11 14:00:00',90),(1012,12,'2010-11-11 15:00:00',91),(1012,13,'2013-11-11 14:00:00',91),(1012,14,'2012-11-11 15:00:00',97),(1012,15,'2011-12-11 10:00:00',85),(1012,16,'2010-09-11 10:00:00',90),(1013,1,'2013-11-11 16:00:00',73),(1013,2,'2012-11-10 10:00:00',69),(1013,3,'2011-12-19 10:00:00',91),(1013,4,'2010-11-18 11:00:00',72),(1013,5,'2013-11-11 14:00:00',76),(1013,6,'2012-09-13 15:00:00',87),(1013,7,'2011-10-16 16:00:00',61),(1013,8,'2010-11-11 16:00:00',77),(1013,9,'2013-11-21 10:00:00',83),(1013,10,'2012-11-11 12:00:00',99),(1013,11,'2011-11-11 14:00:00',91),(1013,12,'2010-11-11 15:00:00',84),(1013,13,'2013-11-11 14:00:00',98),(1013,14,'2012-11-11 15:00:00',74),(1013,15,'2011-12-11 10:00:00',92),(1013,16,'2010-09-11 10:00:00',90),(1014,1,'2013-11-11 16:00:00',64),(1014,2,'2012-11-10 10:00:00',81),(1014,3,'2011-12-19 10:00:00',79),(1014,4,'2010-11-18 11:00:00',74),(1014,5,'2013-11-11 14:00:00',65),(1014,6,'2012-09-13 15:00:00',88),(1014,7,'2011-10-16 16:00:00',86),(1014,8,'2010-11-11 16:00:00',77),(1014,9,'2013-11-21 10:00:00',86),(1014,10,'2012-11-11 12:00:00',85),(1014,11,'2011-11-11 14:00:00',86),(1014,12,'2010-11-11 15:00:00',75),(1014,13,'2013-11-11 14:00:00',89),(1014,14,'2012-11-11 15:00:00',79),(1014,15,'2011-12-11 10:00:00',73),(1014,16,'2010-09-11 10:00:00',68),(1015,1,'2013-11-11 16:00:00',99),(1015,2,'2012-11-10 10:00:00',60),(1015,3,'2011-12-19 10:00:00',60),(1015,4,'2010-11-18 11:00:00',75),(1015,5,'2013-11-11 14:00:00',78),(1015,6,'2012-09-13 15:00:00',78),(1015,7,'2011-10-16 16:00:00',84),(1015,8,'2010-11-11 16:00:00',95),(1015,9,'2013-11-21 10:00:00',93),(1015,10,'2012-11-11 12:00:00',79),(1015,11,'2011-11-11 14:00:00',74),(1015,12,'2010-11-11 15:00:00',65),(1015,13,'2013-11-11 14:00:00',63),(1015,14,'2012-11-11 15:00:00',74),(1015,15,'2011-12-11 10:00:00',67),(1015,16,'2010-09-11 10:00:00',65),(1016,1,'2013-11-11 16:00:00',97),(1016,2,'2012-11-10 10:00:00',90),(1016,3,'2011-12-19 10:00:00',77),(1016,4,'2010-11-18 11:00:00',75),(1016,5,'2013-11-11 14:00:00',75),(1016,6,'2012-09-13 15:00:00',97),(1016,7,'2011-10-16 16:00:00',96),(1016,8,'2010-11-11 16:00:00',92),(1016,9,'2013-11-21 10:00:00',62),(1016,10,'2012-11-11 12:00:00',83),(1016,11,'2011-11-11 14:00:00',98),(1016,12,'2010-11-11 15:00:00',94),(1016,13,'2013-11-11 14:00:00',62),(1016,14,'2012-11-11 15:00:00',97),(1016,15,'2011-12-11 10:00:00',76),(1016,16,'2010-09-11 10:00:00',82),(1017,1,'2013-11-11 16:00:00',100),(1017,2,'2012-11-10 10:00:00',88),(1017,3,'2011-12-19 10:00:00',86),(1017,4,'2010-11-18 11:00:00',73),(1017,5,'2013-11-11 14:00:00',96),(1017,6,'2012-09-13 15:00:00',64),(1017,7,'2011-10-16 16:00:00',81),(1017,8,'2010-11-11 16:00:00',66),(1017,9,'2013-11-21 10:00:00',76),(1017,10,'2012-11-11 12:00:00',95),(1017,11,'2011-11-11 14:00:00',73),(1017,12,'2010-11-11 15:00:00',82),(1017,13,'2013-11-11 14:00:00',85),(1017,14,'2012-11-11 15:00:00',68),(1017,15,'2011-12-11 10:00:00',99),(1017,16,'2010-09-11 10:00:00',76);
    
    /*Table structure for table `student` */
    
    DROP TABLE IF EXISTS `student`;
    
    CREATE TABLE `student` (
      `StudentNo` INT(4) NOT NULL COMMENT '学号',
      `LoginPwd` VARCHAR(20) DEFAULT NULL,
      `StudentName` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
      `Sex` TINYINT(1) DEFAULT NULL COMMENT '性别,取值0或1',
      `GradeId` INT(11) DEFAULT NULL COMMENT '年级编号',
      `Phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空,即可选输入',
      `Address` VARCHAR(255) NOT NULL COMMENT '地址,允许为空,即可选输入',
      `BornDate` DATETIME DEFAULT NULL COMMENT '出生时间',
      `Email` VARCHAR(50) NOT NULL COMMENT '邮箱账号,允许为空,即可选输入',
      `IdentityCard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
      PRIMARY KEY (`StudentNo`),
      UNIQUE KEY `IdentityCard` (`IdentityCard`),
      KEY `Email` (`Email`)
    ) ENGINE=MYISAM DEFAULT CHARSET=utf8;
    
    /*Data for the table `student` */
    
    INSERT  INTO `student`(`StudentNo`,`LoginPwd`,`StudentName`,`Sex`,`GradeId`,`Phone`,`Address`,`BornDate`,`Email`,`IdentityCard`) VALUES (1000,'111111','郭靖',1,1,'13500000001','北京海淀区中关村大街1号','1986-12-11 00:00:00','test1@bdqn.cn','450323198612111234'),(1001,'123456','李文才',1,2,'13500000002','河南洛阳','1981-12-31 00:00:00','test1@bdqn.cn','450323198112311234'),(1002,'111111','李斯文',1,1,'13500000003','天津市和平区','1986-11-30 00:00:00','test1@bdqn.cn','450323198611301234'),(1003,'123456','武松',1,3,'13500000004','上海卢湾区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612314234'),(1004,'123456','张三',1,4,'13500000005','北京市通州','1989-12-31 00:00:00','test1@bdqn.cn','450323198612311244'),(1005,'123456','张秋丽 ',2,1,'13500000006','广西桂林市灵川','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311214'),(1006,'123456','肖梅',2,4,'13500000007','地址不详','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311134'),(1007,'111111','欧阳峻峰',1,1,'13500000008','北京东城区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311133'),(1008,'111111','梅超风',1,1,'13500000009','河南洛阳','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311221'),(1009,'123456','刘毅',1,2,'13500000011','安徽','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311231'),(1010,'111111','大凡',1,1,'13500000012','河南洛阳','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311044'),(1011,'111111','奥丹斯',1,1,'13500000013','北京海淀区中关村大街*号','1984-12-31 00:00:00','test1@bdqn.cn','450323198412311234'),(1012,'123456','多伦',2,3,'13500000014','广西南宁中央大街','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311334'),(1013,'123456','李梅',2,1,'13500000015','上海卢湾区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311534'),(1014,'123456','张得',2,4,'13500000016','北京海淀区中关村大街*号','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311264'),(1015,'123456','李东方',1,4,'13500000017','广西桂林市灵川','1976-12-31 00:00:00','test1@bdqn.cn','450323197612311234'),(1016,'111111','刘奋斗',1,1,'13500000018','上海卢湾区','1986-12-31 00:00:00','test1@bdqn.cn','450323198612311251'),(1017,'123456','可可',2,3,'13500000019','北京长安街1号','1981-09-10 00:00:00','test1@bdqn.cn','450323198109108311'),(10066,'','Tom',1,1,'13500000000','','0000-00-00 00:00:00','email@22.com','33123123123123123');
    
    /*Table structure for table `subject` */
    
    DROP TABLE IF EXISTS `subject`;
    
    CREATE TABLE `subject` (
      `SubjectNo` INT(11) NOT NULL AUTO_INCREMENT COMMENT '课程编号',
      `SubjectName` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
      `ClassHour` INT(4) DEFAULT NULL COMMENT '学时',
      `GradeID` INT(4) DEFAULT NULL COMMENT '年级编号',
      PRIMARY KEY (`SubjectNo`)
    ) ENGINE=INNODB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
    
    /*Data for the table `subject` */
    
    INSERT  INTO `subject`(`SubjectNo`,`SubjectName`,`ClassHour`,`GradeID`) VALUES (1,'高等数学-1',110,1),(2,'高等数学-2',110,2),(3,'高等数学-3',100,3),(4,'高等数学-4',130,4),(5,'C语言-1',110,1),(6,'C语言-2',110,2),(7,'C语言-3',100,3),(8,'C语言-4',130,4),(9,'JAVA第一学年',110,1),(10,'JAVA第二学年',110,2),(11,'JAVA第三学年',100,3),(12,'JAVA第四学年',130,4),(13,'数据库结构-1',110,1),(14,'数据库结构-2',110,2),(15,'数据库结构-3',100,3),(16,'数据库结构-4',130,4),(17,'C#基础',130,1);
    
    /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
    /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
    /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
    /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
    

    10.2 指定查询字段

    10.2.1 查询全部

    语法:

    select 字段, ... from 表
    

    有时候,列名字不是那么见名知意,就起别名 AS
    字段名 as 别名
    表名 as 别名
    案例:

    -- 查询全波的学生 select 字段 from 表
    SELECT * FROM student;
    
    -- 查询指定字段
    SELECT `StudentNo`,`StudentName` FROM student
    
    -- 别名,给结果起一个名字 as
    -- 可以给字段起别名 也可以给表起别名
    SELECT `StudentNo` AS 学号, StudentName AS 学生姓名 FROM student AS s;
    
    -- 函数 Concat(a, b) 拼接字符串
    SELECT CONCAT('姓名:', StudentName) AS 新名字 FROM student;
    

    10.2.2 去重

    查询全部的考试成绩:

    select * from result;
    

    查询有哪些同学参加了考试:

    SELECT `StudentNo` FROM result;
    

    发现重复数据,去重distinct:

    SELECT DISTINCT `StudentNo` FROM result;
    

    作用:去除select查询出来的结果中重复的数据,重复的数据只显示一条

    使用数据库可以做的一些事情:

    select version();-- 查询版本系统(函数)
    select 100+3-2 as 计算结果; -- 用来计算(表达式)
    select @@auto_increment_increment --查询自增的步长(变量) v8.0不可用
    
    -- 学员考试成绩+1分查看
    select `StudentNo`,`StudentResult` + 1 as `提分后` from result;
    

    数据库中的表达式: 文本值,列,null,函数,计算表达式,系统变量……
    select 表达式 from 表;

    10.3 where条件子句

    作用:检索数据中符合条件的值
    where输入一个布尔值

    运算符 语法 描述
    and && a and b a && b 逻辑与
    or || a or b a||b 逻辑或
    Not ! not a !a 逻辑非
    尽量使用英文符号

    10.3.1 !模糊查询

    运算符 语法 描述
    is null a is null 如果操作符为NULL,结果为真
    is not null a is not null 如果操作符部位null,结果为真
    between a between b and c 若a在b和c之间,则结果为真
    like a like b SQL匹配,如果a匹配b,则结果为真
    in a in (a1,a2,...) 假设a在a1,或者a2...其中的某一个值中,结果为真
    1. 案例 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 '%三%';
        
    2. 案例 in(具体的一个或多个值 不能用%和_)
      • 查询1001,1002,1003号学员
        select StudentNo,StudentName from student where StudentNo in (1001,1002,1003);
        
      • 查询在安徽的学生
        select StudentNo,StudentName from student where `Address` in '安徽';
        
    3. 案例null not null
      • 查询地址为空的学生 null
        select StudentNo,StudentName from student where `Address` = '' or is null;
        
      • 查询有出生日期的同学
        select StudentNo,StudentName from student where Borndate is not null;
        

    10.4 联表查询

    10.4.1 join

    图10.4.1
    图10.4.2,七种join
    初学比较复杂,推荐链接SQL的各种连接Join详解

    10.4.2 自连接

    自己的表和自己的表连接,核心:
    一张表拆为两张一样的表即可
    父类:

    categoryid categoryName
    2 信息技术
    3 信息开发
    5 美术开发

    子类:

    pid categoryid categoryName
    3 4 数据库
    2 8 办公信息
    3 6 web开发
    5 7 ps技术

    操作:查询父类对应的子类关系

    父类 子类
    信息技术 办公信息
    软件开发 数据库
    软件开发 web开发
    美术设计 ps技术

    附上表:

    CREATE TABLE `category`(
    `categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',
    `pid` INT(10) NOT NULL COMMENT '父id',
    `categoryName` VARCHAR(50) NOT NULL COMMENT '主题名字',
    PRIMARY KEY(`categoryid`)
    )ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET = utf8;
    
    INSERT INTO `category`(`categoryid`,`pid`,`categoryName`)
    VALUES('2','1','信息技术'),
    ('3','1','软件开发'),
    ('4','3','数据库'),
    ('5','1','美术设计'),
    ('6','3','web开发'),
    ('7','5','ps技术'),
    ('8','2','办公信息');
    

    查询:

    SELECT a.`categoryName` AS '父栏目',
    b.`categoryName` AS '子栏目' 
    FROM `category` AS a, `category` AS b
    WHERE a.`pid` = b.`categoryid`;
    

    10.5 分页和排序

    分页 limit
    语法 limit 起始值,页面的大小
    排序 order by
        升序 asc
        降序 desc
    
    /*============== 分页 ================
    语法 : SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
    好处 : (用户体验,网络传输,查询压力)
    
    推导: 
        第一页 : limit 0,5
        第二页 : limit 5,5
        第三页 : limit 10,5
        ......
        第N页 : limit (pageNo-1)*pageSzie,pageSzie
        [pageNo:页码,pageSize:单页面显示条数]
        
    */
    -- 每页显示5条数据
    SELECT s.studentno,studentname,subjectname,StudentResult
    FROM student s
    INNER JOIN result r
    ON r.studentno = s.studentno
    INNER JOIN `subject` sub
    ON r.subjectno = sub.subjectno
    WHERE subjectname='数据库结构-1'
    ORDER BY StudentResult DESC , studentno
    LIMIT 0,5
    
    #查询 JAVA第一学年 课程成绩前10名并且分数大于80的学生信息(学号,姓名,课程名,分数)
    SELECT s.studentno,studentname,subjectname,StudentResult
    FROM student s
    INNER JOIN result r
    ON r.studentno = s.studentno
    INNER JOIN `subject` sub
    ON r.subjectno = sub.subjectno
    WHERE subjectname='JAVA第一学年'
    ORDER BY StudentResult DESC
    LIMIT 0,10
    

    10.6 子查询

    where(这个值是计算出来的)

    本质: 在where语句中嵌套一个子查询语句

    SELECT studentNo,subjectNo,studentResult
    FROM result r
    WHERE `SubjectNo` = (
    	SELECT subjectNo FROM `subject`
    	WHERE `SubjectName` = '数据库结构-1'
    )
    ORDER BY studentResult DESC
    LIMIT 0,10
    
    SELECT DISTINCT s.studentNo,studentName
    FROM student s
    INNER JOIN result r
    ON s.`StudentNo` = r.`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'
    	)
    )
    

    10.7 分组

    group by

    -- 查询不同课程的大于80的科目的平均分 
    -- 核心: 根据不同的课程分组
    SELECT subjectName,AVG(studentResult) AS 平均分,
    	MAX(studentResult) AS 最高分,MIN(studentResult) AS 最低分
    FROM result AS r
    INNER JOIN `subject` sub
    ON r.`SubjectNo` = sub.`SubjectNo`
    GROUP BY r.subjectNo
    HAVING 平均分 >= 80	
    

    五、MySQL函数

    官网:https://dev.mysql.com/doc/refman/8.0/en/func-op-summary-ref.html

    11.常用函数

    -- 数学运算
    SELECT ABS(-8) 
    SELECT CEILING(9.4)  -- 向上取整
    SELECT FLOOR(9.4)    -- 向下取整
    SELECT RAND() 	     -- 返回一个0~1之间的随机数
    SELECT SIGN(-09)       -- 判断一个数的符号 0-0 负数返回-1 正数返回1
    
    -- 字符串
    SELECT CHAR_LENGTH('即使再小的帆也能远航') -- 字符串长度
    SELECT CONCAT('我','爱','你')		   -- 拼接字符串
    SELECT INSERT('我爱helloworld',1,2,'超级热爱') -- 插入,替换 [a,b],从1开始 
    					       -- 会被换成‘超级热爱helloworld’
    					       -- 可以把此处2换成100之类会将所有删除换成‘超级热爱’
    SELECT LOWER('LKJsdfa')			-- 小写字母
    SELECT UPPER('jdsflkLL')		-- 大写字母
    SELECT INSTR('asdfsdaf','s')		-- 返回第一次出现的字串的索引
    SELECT REPLACE('坚持就能成功','坚持','努力') -- 替换出现的指定字符串
    SELECT SUBSTR('努力就能成功',4)		-- 返回指定的子字符串(源字符串,截取位置 [,截取长度])
    SELECT REVERSE('努力就能成功')		-- 反转
    
    -- 查询姓李的的同学
    SELECT * FROM student
    WHERE studentName LIKE '李%'
    
    -- 时间和日期函数(记住)
    SELECT CURRENT_DATE()		-- 当前日期
    SELECT CURDATE()		-- 获取当期日期
    SELECT NOW()			-- 获取当前的时间
    SELECT LOCALTIME()		-- 本地时间
    SELECT SYSDATE()		-- 系统时间
    
    SELECT YEAR(NOW())
    SELECT MINUTE(NOW())
    
    -- 系统
    SELECT SYSTEM_USER()
    SELECT USER()
    SELECT VERSION()	
    

    12.聚合函数(常用)

    函数名称 描述
    count() 计数
    sum() 求和
    avg() 平均值
    max() 最大值
    min() 最小值
    ... ...
    -- 查询不同课程的大于80的科目的平均分 
    -- 核心: 根据不同的课程分组
    SELECT subjectName,AVG(studentResult) AS 平均分,
    	MAX(studentResult) AS 最高分,MIN(studentResult) AS 最低分
    FROM result AS r
    INNER JOIN `subject` sub
    ON r.`SubjectNo` = sub.`SubjectNo`
    GROUP BY r.subjectNo
    HAVING 平均分 >= 80	
    

    13.数据库级别的MD5加密(扩展)

    md5不可逆,具体的值的md5值是一样的

    CREATE TABLE testmd5(
    	id INT(4) NOT NULL,
    	`name` VARCHAR(100) NOT NULL,
    	pwd VARCHAR(100) NOT NULL,
    	PRIMARY KEY(`id`)
    )ENGINE=INNODB DEFAULT CHARSET = utf8
    
    -- 明文密码
    INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456')
    -- 加密
    UPDATE testmd5 SET pwd = MD5(pwd) WHERE id = 1
    -- 插入时候加密
    insert into testmd5 values(4,'xiaoming',md5('123456'))
    -- 如何检校:将用户传递进来的密码,进行md5加密,然后对比加密后的值
    select * from testmd5 where `name`='小明' and pwd=md5('123456')
    

    六、事务

    要么都成功,要么都失败

    ——————

    1、SQL执行 A给B转账 A1000 --> 200 B 200

    2、SQL执行 B收到A的钱 A800 --> B 400

    ——————

    将一组SQL放在一个批次中去执行~

    事务原则:ACID原则 原子性 一致性 隔离性 持久性 (脏读、幻读、……)

    https://blog.csdn.net/dengjili/article/details/82468576

    原子性(Atomicity)
    原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。

    一致性(Consistency)
    事务前后数据的完整性必须保持一致。

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

    持久性(Durability)
    持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响

    mysql是默认开启事务自动提交的

    set autocommit = 0 -- 关闭
    set autocommit = 1 -- 开启(默认)
    
    /* 使用set语句来改变自动提交模式 */
    SET autocommit = 0;   /*关闭*/
    SET autocommit = 1;   /*开启*/
    
    /* 注意
        1.MySQL中默认是自动提交
        2.使用事务时应先关闭自动提交
    */
    
    /*开始一个事务,标记事务的起始点*/
    START TRANSACTION   
    
    /*提交一个事务给数据库*/
    COMMIT
    
    /*将事务回滚,数据回到本次事务的初始状态*/
    ROLLBACK
    
    /*还原MySQL数据库的自动提交*/
    SET autocommit =1;
    
    
    -- 保存点
        SAVEPOINT 保存点名称 -- 设置一个事务保存点
        ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
        RELEASE SAVEPOINT 保存点名称 -- 删除保存点
    

    img

    模拟场景

    SET autocommit = 0;
    -- 转账
    CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci 
    USE shop 
    
    CREATE TABLE account(
    	`id` INT(3) NOT NULL AUTO_INCREMENT,
    	`name` VARCHAR(30) NOT NULL,
    	`money` DECIMAL(9,2) NOT NULL,
    	PRIMARY KEY(`id`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8;
    
    INSERT INTO account(`name`,`money`)VALUES('a',2000.00),('b',10000.0);
    
    -- 模拟转账:事务
    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;	--恢复默认值
    

    七、索引

    索引是帮助mysql高效获取数据的数据结构

    作用 :

    • 提高查询速度
    • 确保数据的唯一性
    • 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
    • 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
    • 全文检索字段进行搜索优化.

    分类 :

    • 主键索引 (Primary Key)

      • 唯一标识,主键不可重复,只能有一个列作为主键
    • 唯一索引 (Unique)

      • 不允许具有索引值相同的行,唯一索引可以重复,多个列都可表示为唯一索引
    • 常规索引 (Index)

      • 默认的,index / key关键字来设置
    • 全文索引 (FullText)

      • 在特定的数据库引擎下才有,MyISAM,现在很多都有了
      • 快速定位数据

    1.主键索引

    主键 : 某一个属性组能唯一标识一条记录

    特点 :

    • 最常见的索引类型
    • 确保数据记录的唯一性
    • 确定特定数据记录在数据库中的位置

    2.唯一索引

    作用 : 避免同一个表中某数据列中的值重复

    与主键索引的区别

    • 主键索引只能有一个

    • 唯一索引可能有多个

      img

    3.常规索引

    作用 : 快速定位特定数据

    注意 :

    • index 和 key 关键字都可以设置常规索引

    • 应加在查询找条件的字段

    • 不宜添加太多常规索引,影响数据的插入,删除和修改操作

      img

    4.全文索引

    作用 : 快速定位特定数据

    注意 :

    • 只能用于MyISAM类型的数据表
    • 只能用于CHAR , VARCHAR , TEXT数据列类型
    • 适合大型数据集

    5.开始学习索引

    创建表:

    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用户表';
    

    创建一个函数:

    SET GLOBAL log_bin_trust_function_creators=TRUE;
    
    -- 插入100万条数据
    DELIMITER $$ -- 写函数之前必须要写,标志
    CREATE FUNCTION mock_data()
    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),
    				CONCAT(i,'@qq.com'),
    				CONCAT('18',FLOOR(RAND()*999999999-100000000)),
    				FLOOR(RAND()*2),
    				UUID(),
    				FLOOR(RAND()*2)
    				);
    		-- 在上方插入语句
    		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'
    

    增加索引

    -- id_表名_字段名
    CREATE INDEX 索引名 ON 表(字段);
    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'
    
    /*
    #方法一:创建表时
          CREATE TABLE 表名 (
                    字段名1  数据类型 [完整性约束条件…],
                    字段名2  数据类型 [完整性约束条件…],
                    [UNIQUE | FULLTEXT | SPATIAL ]   INDEX | KEY
                    [索引名]  (字段名[(长度)]  [ASC |DESC]) 
                    );
    
    
    #方法二:CREATE在已存在的表上创建索引
            CREATE  [UNIQUE | FULLTEXT | SPATIAL ]  INDEX  索引名 
                         ON 表名 (字段名[(长度)]  [ASC |DESC]) ;
    
    
    #方法三:ALTER TABLE在已存在的表上创建索引
            ALTER TABLE 表名 ADD  [UNIQUE | FULLTEXT | SPATIAL ] INDEX
                                 索引名 (字段名[(长度)]  [ASC |DESC]) ;
                                 
                                 
    #删除索引:DROP INDEX 索引名 ON 表名字;
    #删除主键索引: ALTER TABLE 表名 DROP PRIMARY KEY;
    
    
    #显示索引信息: SHOW INDEX FROM student;
    */
    
    /*增加全文索引*/
    ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `studentname` (`StudentName`); 
    
    /*EXPLAIN : 分析SQL语句执行性能*/
    EXPLAIN SELECT * FROM student WHERE studentno='1000';
    
    /*使用全文索引*/
    EXPLAIN SELECT *FROM student WHERE MATCH(studentname) AGAINST('love');
    

    6.索引原则

    • 索引不是越多越好
    • 不要对进程变动数据加索引
    • 小数据量的表不需要加索引
    • 索引一般加再常用来查询的字段上!

    索引的数据结构

    MySQL索引背后的数据结构及算法原理

    八、权限管理和备份

    1.用户管理

    可视化界面

    image-20200306121007411

    sql命令操作

    用户表:mysql.user

    本质:对这张表增删改查

    -- 创建用户
    CREATE USER 用户名 IDENTIFIED BY '密码';
    CREATE USER test IDENTIFIED BY '123456' ;
    
    -- 修改密码
    SET PASSWORD = PASSWORD('111111');
    /*注:在mysql8.0以上版本,
     update mysql.user set password='newpassword' where user='root';
     和
     update mysql.user set password=PASSWORD('newpassword') where User='root';
     这两条命令已经不起作用了。*/
     ALTER USER test IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '111111';
     
     -- 重命名
     RENAME USER 原来名字 TO 新名字;
     RENAME USER test TO test2;
    
    -- 用户授权 all privileges 全部的权限,库.表
    -- all privileges 除了给别人授权,其他都能干
    GRANT ALL PRIVILEGES ON *.* TO test2;
    
    -- 查看权限
    SHOW GRANTS FOR test2;
    SHOW GRANTS FOR root@localhost;
    
    -- 撤销权限 revoke 哪些权限,在哪个库撤销,给谁撤销
    REVOKE ALL PRIVILEGES ON *.* FROM test2;
    
    -- 删除用户
    DROP USER test2;
    

    2.MySQL备份

    • 保证重要的数据不丢失
    • 数据转移 A------>B

    MySQL数据库备份的方式:

    • 直接拷贝

    • 使用类似与SQLyog这种可视化工具中手动导出

      • 在想要导出的表或者库中,右键,选择备份或导出:

        image-20200306175927038

      • image-20200306180039330

    • 使用命令行导出 mysqldump

      • # mysqldump -h 主机 -u 用户名 -p 密码 数据库 表1 表2 表3 > 物理磁盘位置/文件名
        mysqldump -h localhost -u root -p qq123456 school student >D:/a.sql
        
        #在MySQL8中
        mysqldump -h localhost -u root -p school student >D:/a.sql
        #回车后会请求输入密码,之后再执行
        
    • 用命令行导入

      • 在登录的情况下

        source d:/a.sql
        
        
      • 注意,要使用符合数据要求的数据库

        show databases;查看数据库
        #如果 mydb 不存在,先创建 mydb
        create database mydb;
        #再选中 mydb
        use mydb;
        
      • 或者:

        mysql -u 用户名 -p 库名< 备份文件
        

    九、规范数据库设计

    1.为什么需要设计

    当数据库比较复杂的时候,我们就需要设计了

    糟糕的数据库设计

    • 数据冗余,浪费空间
    • 数据库插入和删除都会麻烦、异常【屏蔽使用物理外键
    • 程序的性能差

    良好的数据库设计

    • 节省内存空间
    • 保证数据库的完整性
    • 方便开发系统

    软件开发中,关于数据库的设计

    • 分析需求:分析业务和需要处理的数据库的需求
    • 概要设计:设计关系图E-R图

    设计数据库的步骤:(比如个人博客

    • 收集信息,分析需求
      • 用户表(用户登陆注销,用户个人信息,写博客,//创建分类)
      • 分类表(文章分类,谁创建的)
      • 文章表(文章的信息)
      • 评论表
      • 友链表(友链信息)
      • //自定义表(系统信息,某个关键的字,或者一些主字段)key:value
    • 标识实体之间的关系(把需求落地到每个字段)
      • 写博客:user-->blog
      • 创建分类:user-->category
      • 关注:user-->user
      • 友链:links
      • 评论:user-user-blog

    2.三大范式

    为什么需要数据规范化

    • 信息重复
    • 更新异常
    • 插入异常
      • 无法正常显示信息
    • 删除异常
      • 丢失有效信息

    三大范式

    三大范式推荐阅读

    目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

    第一范式(1NF)

    原子性:保证每一列不可再分

    第二范式(2NF)

    前提:满足第一范式

    每张表只描述一件事情

    第三范式(3NF)

    前提:满足第一范式和第二范式

    第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

    (规范数据库的设计)

    规范性和性能的问题

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

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

    十、!JDBC(重点)

    1.数据库驱动

    驱动:比如声卡、显卡,数据库也要驱动

    image-20200307131521396

    程序会通过数据库驱动和数据库打交道

    2.JDBC

    sun公司为了简化开发人员对数据库的统一操作,提供了一个java操作数据库的规范,俗称JDBC

    规范的实现由具体厂商操作

    对于开发人员来说,只需要掌握JDBC的接口的操作即可

    没有什么是加一层是解决不了的,如果有,再加一层

    image-20200307131926601

    java.sql

    javax.sql

    还需要导入一个数据库驱动包

    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. 创建一个Maven项目

    2. 导入数据库驱动依赖

       <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
       </dependency>
      
    3. 编写测试代码

      mysql错误:java.sql.SQLException: The server time zone value '�й���׼ʱ��' is unrecognized or represents

      package com.huangdekai.javaWebLearn;
      // 第一个JDBC程序
      
      import java.sql.*;
      
      public class jdbcFirstDemo {
          public static void main(String[] args) throws ClassNotFoundException, SQLException {
              //1.加载驱动
              Class.forName("com.mysql.jdbc.Driver");
              
              //2.用户信息和url
              //教程中只有useUnicode=true&characterEncoding=utf8&useSSL=true
              //出现了上述连接的mysql错误,在url里添加了serverTimezone=UTC
              String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
              String username = "root";
              String password = "qq123456";
              
              //3.连接成功,数据库对象 Connection代表数据库
              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"));
                  System.out.println("name="+resultSet.getObject("name"));
                  System.out.println("password="+resultSet.getObject("password"));
                  System.out.println("email="+resultSet.getObject("email"));
                  System.out.println("birthday="+resultSet.getObject("birthday"));
              }
              
              //6.释放连接
              resultSet.close();
              statement.close();
              connection.close();
          }
      }
      
      

    步骤总结:

    1. 加载驱动Class.forname("com.mysql.jdbc.Driver");

      现在似乎推荐用Class.forname("com.mysql.cj.jdbc.Driver");

      上述程序可互换

    2. 连接数据库DriverManager

    3. 获得执行sql的对象 Statement

    4. 获得返回的结果集

    5. 释放连接

    DriverManager

    //DriverManager.registerDriver(new com.sql.jdbc.Driver());
    Class.forName("com.sql.jdbc.Driver");//固定写法,加载驱动
    Connection connection = DriverManager.getConnection(url,username,password);
    
    // connection 代表数据库
    // 数据库设置自动提交
    // 事务提交
    // 事务回滚
    connection.rollback();
    connection.commit();
    connection.setAutoCommit();
    

    URL

    String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC";
    // mysql	----	3306
    /*
    	jdbc:mysql://主机地址:端口号/数据库名?参数1&参数2&参数3
    	协议://主机端口:端口号
    */
    
    // oralce	----	1521
    /*
    	jdbc:oracle:thin@localhost:1521:sid
    */
    

    Statment 执行SQL的对象

    prepareStatement执行SQL的对象

    String sql = "select * from users";//编写SQL
    
    statement.executeQuery();//查询操作返回ResultSet
    statement.execute();    //执行任何SQL,因此效率慢点
    statement.executeUpdate();//更新、插入、删除,都是用这个,返回受影响的行数
    

    ResultSet 查询的结果集:封装了所有的查询结果

    获得指定的数据类型

    resultSet.getObject();//在不知道列类型的情况下使用
    resultSet.getString();
    resultSet.getInt();
    resultSet.getFloat();
    resultSet.getDate();
    ...
    

    遍历,指针

    resultSet.beforeFirst();//移动到最前面
    resultSet.afterLast();//移动到最后面
    resultSet.next();//移动到下一个数据
    resultSet.previous();//移动到前一行
    resultSet.absolute(row);//移动到指定行
    

    释放资源

    resultSet.close();
    statement.close();
    connection.close();
    

    4.statement对象

    jdbc中的statement对象用于向数据库发送SQL语句,想完成对数据库的增删改查,只需要通过这个对象向数据库发送增删改查语句即可。

    statement对象的executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)

    Statement.executeQuery方法用于向数据库发送查询语句,executeQuery方法返回代表查询结果的ResultSet对象

    CRUD操作-create

    使用executeUpdate(String sql)方法完成数据添加操作,示例操作:

    Statement st = conn.createStatement();
    String sql = "insert into user(...) values(...)";
    int num = st.excuteUpdate(sql);
    if(num>0){
        System.out.println("插入成功");
    }
    

    CRUD操作-delete

    使用executeUpdate(String sql)方法完成数据删除操作,示例操作:

    Statement st = conn.createStatement();
    String sql = "delete from user where id=1";
    int num = st.excuteUpdate(sql);
    if(num>0){
        System.out.println("修改成功");
    }
    

    CRUD操作-update

    Statement st = conn.createStatement();
    String sql = "update user set `name`='' where `name`=''";
    int num = st.excuteUpdate(sql);
    if(num>0){
        System.out.println("删除成功");
    }
    

    CRUD操作-read

    使用executeQuery(String sql)方法完成数值查询操作,示例操作:

    Statement st = conn.createStatement();
    String sql = "select * from user where id = 1";
    ResultSet rs = st.excuteQuery(sql);
    while(rs.next()){
        //根据获取列的数据类型,分别调用rs的相应方法映射到java对象中
    }
    

    代码实现

    1. 准备

      1. 路径

        image-20200308091859120

      2. db.properties内容

        driver=com.mysql.jdbc.Driver
        url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
        username = root
        password = qq123456
        
    2. 提取工具类

      package com.huangdekai.javaWebLearn.utils;
      
      import java.io.IOException;
      import java.io.InputStream;
      import java.sql.*;
      import java.util.Properties;
      
      public class JdbcUtils {
      
          private static String driver = null;
          private static String url = null;
          private static String username = null;
          private static String password = null;
      
      
          static {
              try {
                  InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
                  Properties properties = new Properties();
                  properties.load(in);
      
                  driver = properties.getProperty("driver");
                  url = properties.getProperty("url");
                  username = properties.getProperty("username");
                  password = properties.getProperty("password");
      
                  //1.驱动只用加载一次
                  Class.forName(driver);
      
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          //获取连接
          public static Connection getConnection() throws SQLException {
              return DriverManager.getConnection(url,username,password);
          }
      
          //释放连接资源
          public static void release(Connection connection, Statement statement, ResultSet resultSet){
              if (resultSet != null){
                  try {
                      resultSet.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
              if (statement != null){
                  try {
                      statement.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
              if (connection != null){
                  try {
                      connection.close();
                  } catch (SQLException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
      
    3. 编写增删改的方法executeUpdate

    package com.huangdekai.javaWebLearn;
    
    import static org.junit.Assert.assertTrue;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    /**
     * Unit test for simple App.
     */
    public class AppTest 
    {
        @Test
        public void TestInsert(){
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
                statement = connection.createStatement();
                String sql = "insert into users(`id`,`name`,`password`,`email`,`birthday`) " +
                        "values " +
                        "(4,'bilibili','123122','bilibili@qq.com','1970-01-01')," +
                        "(5,'danlidanli','122342','danlidanlli@qq.com','1970-01-01')" ;
                int i = statement.executeUpdate(sql);
                if (i>0){
                    System.out.println("插入成功");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                JdbcUtils.release(connection,statement,resultSet);
            }
        }
    
        @Test
        public void TestDelete(){
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
                statement = connection.createStatement();
                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);
            }
        }
    
        @Test
        public void TestUpdate(){
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
                statement = connection.createStatement();
                String sql = "update users set `name`='duzhuan2' where `id` = 2" ;
                int i = statement.executeUpdate(sql);
                if (i>0){
                    System.out.println("更新成功");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                JdbcUtils.release(connection,statement,resultSet);
            }
        }
    }
    
    
    1. 查询executeQurey
    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class TestExecuteQurey {
        @Test
        public void testExecuteQurey(){
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
            try {
                connection = JdbcUtils.getConnection();
    
                statement = connection.createStatement();
    
                String sql = "select * from users";
    
                resultSet = statement.executeQuery(sql);
    
                while (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();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,statement,resultSet);
            }
        }
    }
    
    

    sql注入的问题

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

    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class SQLDI {
        public static void main(String[] args) {
            //login("duzhuan","123456");//正常输入
            login(" 'or '1=1","' or'1=1");
            // select * from users where `name` = '' or '1=1' and `password` =''or'1=1'
        }
    
        // 登陆业务
        public static void login(String username,String password){
            Connection connection = null;
            Statement statement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
                statement = connection.createStatement();
    
                String sql = "select * from users where `name`='"+username+"' and  `password`='"+password+"'";
                resultSet = statement.executeQuery(sql);
                while (resultSet.next()){
                    System.out.println(resultSet.getString("name"));
                    System.out.println(resultSet.getString("password"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,statement,resultSet);
            }
        }
    }
    
    

    5.PreparedStatement对象

    PreparedStatement 可以防止SQL注入,效率更好

    目录结构

    image-20200308214559097

    增删改

    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    import org.junit.Test;
    
    import javax.swing.text.Utilities;
    import java.sql.*;
    import java.util.Date;
    
    public class TestPreparedStatment {
        @Test
        public void testInsert(){
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                 connection = JdbcUtils.getConnection();
    
                //区别
                //使用?占位符
                String sql = "insert into " +
                         "users(`id`,`name`,`password`,`email`,`birthday`) " +
                         "value(?,?,?,?,?)";//占位符
                preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
    
                //手动给参数赋值
                preparedStatement.setInt(1,4); //id赋值
                preparedStatement.setString(2,"杜撰");
                preparedStatement.setString(3,"aa123456");
                preparedStatement.setString(4,"123123@qq.com");
                //注意:sql.Date     java      java.sal.Date()
                //      util.Date   数据库     new Date().getTime()获得时间戳
                preparedStatement.setDate(5, new java.sql.Date(new Date().getTime()));
    
                //执行
                int i = preparedStatement.executeUpdate();
                if (i>0){
                    System.out.println("插入成功");
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,preparedStatement,resultSet);
            }
        }
    
        @Test
        public void testDelete(){
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
    
                //区别
                //使用?占位符
                String sql = "Delete from users where id = ?";//占位符
                preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
    
                //手动给参数赋值
                preparedStatement.setInt(1,4);
    
                //执行
                int i = preparedStatement.executeUpdate();
                if (i>0){
                    System.out.println("删除成功");
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,preparedStatement,resultSet);
            }
        }
    
        @Test
        public void testUpdate(){
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
    
                //区别
                //使用?占位符
                String sql = "update users set `id` = 0 where id = ?";//占位符
                preparedStatement = connection.prepareStatement(sql);//预编译SQL,先写SQL,然后不执行
    
                //手动给参数赋值
                preparedStatement.setInt(1,4);
    
                //执行
                int i = preparedStatement.executeUpdate();
                if (i>0){
                    System.out.println("修改成功");
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,preparedStatement,resultSet);
            }
        }
    }
    

    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestPreparedStatementQuery {
        @Test
        public void testPrepareStatementQuery() throws SQLException {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
                String sql = "select * from users where id = ?";
                preparedStatement = connection.prepareStatement(sql);
    
                preparedStatement.setInt(1,0);//传递参数
    
                resultSet = preparedStatement.executeQuery();
    
                if (resultSet.next()){
                    System.out.println("name = "+resultSet.getString("name"));
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
    
    

    防止SQL注入

    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    
    import java.sql.*;
    
    public class SQLDIPreparedStatement {
        public static void main(String[] args) {
            //login("duzhuan","123456");//正常输入
            login("'' or 1=1","'' or 1=1");
            // select * from users where `name` = '' or '1=1' and `password` =''or'1=1'
        }
    
        // 登陆业务
        public static void login(String username,String password){
            Connection connection = null;
            PreparedStatement statement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils.getConnection();
    
                //PreparedStatement防止SQL注入的本质,把传递进来的参数当作字符
                //假设其中存在转义字符,引号会被直接转义
                String sql = "select * from users where `name`= ? and  `password`= ?";
    
                statement = connection.prepareStatement(sql);
    
                statement.setString(1,username);
                statement.setString(2,password);
    
                resultSet = statement.executeQuery();
                while (resultSet.next()){
                    System.out.println(resultSet.getString("name"));
                    System.out.println(resultSet.getString("password"));
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,statement,resultSet);
            }
        }
    }
    
    

    6.使用IDEA连接数据库

    image-20200308215144126

    image-20200308215311722

    image-20200308222411184

    可能出现的问题的解决方法链接:

    连接成功后可以选择数据库:

    image-20200308222840121

    7.事务

    要么都成功,要么都失败

    ACID原则

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

    一致性:总数不变

    隔离性多个进程互不干扰

    持久性:一旦提交不可逆,持久化到数据库中

    隔离性的问题:

    脏读:一个事务读取到另一个没有提交的事务

    不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变

    虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致

    代码实现

    1. 开启事务connection.setAutoCOmmit(false)
    2. 一组业务执行完毕,提交事务
    3. 可以在catch语句中显式定义回滚语句,但是默认失败就会回滚
    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestTransaction1
    {
        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'";
                preparedStatement = connection.prepareStatement(sql1);
                preparedStatement.executeUpdate();
    
                //int x  = 1/0;//报错
    
                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) {
                    ex.printStackTrace();
                }
                e.printStackTrace();
            } finally {
                JdbcUtils.release(connection,preparedStatement,resultSet);
            }
        }
    }
    
    

    8.数据库连接池

    池化技术----执行完毕----释放

    连接 -- 释放 十分浪费系统资源

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

    常用连接数:假设10个

    最小连接数:5、10、100 按常用连接数来 按以上假设,假设设10个

    ​ 假设还有5个资源

    最大连接数:业务最高承载上线,按照以上假设,是15个

    ​ 设有100个,排队等待

    等待超时:100ms

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

    开源数据源实现

    DBCP

    C3P0

    Druid:阿里巴巴

    使用了这些数据库连接池之后,我们在项目开发中就不需要连接数据库的代码了

    DBCP

    pom.xml添加依赖

    
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    
    

    dbcpconfig.properties

    #连接设置   这里的名字,是DBCP数据源中定义好的
    driverClassName = com.mysql.jdbc.Driver
    url = jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=UTC
    username = root
    password = qq123456
    
    #下面的东西可以默认不设置
    
    #初始化连接
    initialSize = 10
    
    #最大连接数量
    maxActive = 50
    
    #最大空闲连接
    maxIdle = 20
    
    #最小连接数量
    minIdle = 5
    
    #超时等待时间以毫秒为单位 60000ms/10000 = 60s
    maxWait = 60000
    
    #JDBC驱动建立连接时附带的连接属性的格式必须为【属性名=property;】
    #注意:"user"与"password"两个属性会被明显传递,因此这里不需要包含他们
    connectionProperties=useUnicode=true;characterEncoding=UTF8;serverTimezone=UTC
    
    #指定由连接池所创建的连接的自动提交(auto-commit)状态
    defaultAutoCommit=true
    
    # driver default指定由连接池所创建的连接的只读(read-only)状态
    # 如果没有设置该值,则"setReadOnly"方法将不被调用,(某些驱动不支持只读模式,如:Informix)
    defaultReadOnly =
    
    # driver default指定由连接池所创建的连接的事务级别(TransactionIsolation)
    # 可用值为下列之一:(详情见javadoc)NONE,READ_UNCOMMITTED,REPEATABLE_READ,SERIALIZABLF...
    defaultTransactionIsolation=READ_UNCOMMITTED
    

    工具类JdbcUtils_DBCP

    package com.huangdekai.javaWebLearn.utils;
    
    import org.apache.commons.dbcp.BasicDataSource;
    import org.apache.commons.dbcp.BasicDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    public class JdbcUtils_DBCP {
    
        private static DataSource dataSource = null;
    
        static{
            try {
                InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
                Properties properties = new Properties();
                properties.load(in);
    
                //创建数据源  工厂模式 --》 创建对象
                dataSource = BasicDataSourceFactory.createDataSource(properties);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        //获取连接
        public static Connection getConnection() throws SQLException {
            return dataSource.getConnection();//从数据源中获取连接
        }
    
        //释放连接资源
        public static void release(Connection connection, Statement statement, ResultSet resultSet){
            if (resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    

    测试:

    package com.huangdekai.javaWebLearn;
    
    import com.huangdekai.javaWebLearn.utils.JdbcUtils;
    import com.huangdekai.javaWebLearn.utils.JdbcUtils_DBCP;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class TestDBCP {
        @Test
        public void testPrepareStatementQuery() throws SQLException {
            Connection connection = null;
            PreparedStatement preparedStatement = null;
            ResultSet resultSet = null;
    
            try {
                connection = JdbcUtils_DBCP.getConnection();
                String sql = "select * from users where id = ?";
                preparedStatement = connection.prepareStatement(sql);
    
                preparedStatement.setInt(1,0);//传递参数
    
                resultSet = preparedStatement.executeQuery();
    
                if (resultSet.next()){
                    System.out.println("name = "+resultSet.getString("name"));
                }
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                JdbcUtils_DBCP.release(connection,preparedStatement,null);
            }
        }
    
    }
    
    

    C3P0

    依赖:

        <dependency>
          <groupId>com.mchange</groupId>
          <artifactId>c3p0</artifactId>
          <version>0.9.5.2</version>
        </dependency>
    

    .....

    结论

    无论使用什么数据源,本质是一样的,DataSource接口不会变,方法就不会变

  • 相关阅读:
    String驻留带来的危害
    Go语言的堆栈分析
    SecureCRT使用技巧
    Javascript中相同Function使用多个名称
    记录Office Add-in开发经验
    Silverlight和WPF中DataContractJsonSerializer对时间的处理差异
    ASP.NET MVC项目实践技巧
    有点担心Node.js的未来了
    回首经典的SQL Server 2005
    duilib关于学习Demo中的QQ
  • 原文地址:https://www.cnblogs.com/duzhuan/p/13675374.html
Copyright © 2011-2022 走看看