zoukankan      html  css  js  c++  java
  • MySQL数据库基本知识学习笔记

    MySQL数据库基本知识

    1、初始MySQL

    1.1 数据库分类

    关系型数据库:(SQL)

    • MySQL,Oracle,SQL Sever......
    • 通过表和表之间,行和列之间的关系进行数据的存储

    非关系性数据库:(NoSQL)

    • Redis......
    • 非关系性数据库,对象存储,通过对象的自身属性来决定。(例:键值对)

    1.2 命令行操作数据库

    use 数据库名;   --切换数据库
    show databases;   --查看所有的数据库
    show tables;   --查看数据库中的表
    describe 表名;   --查看表中信息
    exit;   --退出
    

    2、操作数据库

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

    mySql中不区分大小写

    2.1 操作数据库

    1、创建数据库

    creat database [if not exists] 数据库名;
    

    2、删除数据库

    drop database [if exists] 数据库名;
    

    3、使用数据库

    use 数据库名;
    --如果数据库名、表名或字段名为特殊字段,用``
    use `数据库名`;
    

    2.2 数据库的列类型

    数值

    • tinyint 十分小的数据 1个字节
    • smallint 较小的数据 2个字节
    • mediumint 中等大小的数据 3个字节
    • int 标准的整数 4个字节
    • bigint 较大的数据 8个字节
    • float 浮点数 4个字节
    • double 浮点数 8个字节
    • decimal 字符串形式的浮点数 不会有精度损失

    字符串

    • char 字符串 0~255
    • varchar 可变字符串 0~65535 常用 等价于String
    • tinytext 微型文本 2^8-1
    • text 文本串 2^16-1

    时间日期

    • data YYYY-MM-DD,日期格式
    • time HH:mm:ss,时间格式
    • datetime YYYY-MM-DD HH:mm:ss 最常用的时间格式
    • timestamp 时间戳,1970.01.01 00:00到现在的毫秒数

    null

    • 没有值,未知

    2.3 数据库的字段属性(重点)

    Unsingied:

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

    zerofill:

    • 0填充
    • 不足的位数,使用0来填充

    自增:

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

    非空:

    Null not null:

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

    默认:

    • 设置默认的值
    • sex,默认设置为:男,如果不指定该列的值,就用默认的值。

    2.4 创建数据库

    /*所有的表名、字段名建议用``(注:``是tab键上的那个键)包裹起来
    注意每一个括号以及逗号等都是英文格式的
    最后一个字段后不写逗号*/
    
    CREATE TABLE IF NOT EXISTS `student`(
    `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
    `name` VARCHAR(10) NOT NULL DEFAULT '匿名' COMMENT '姓名',
    `sex` VARCHAR(3) NOT NULL DEFAULT '男' COMMENT '性别',
    `password` VARCHAR(20) NOT NULL DEFAULT '000000' COMMENT '密码',
    `bith` DATETIME DEFAULT NULL COMMENT '出生日期',
    `address` VARCHAR(50) DEFAULT NULL COMMENT '家庭住址',
    `email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY(`id`)
    )ENGINE = INNODB DEFAULT CHARSET = utf8
    

    查看创建数据库的语句

    show create database 数据库名  --- 查看创建数据库的语句
    

    查看创建表的语句

    show create table 表名   -- 查看创建表的语句
    

    显示表的结构

    desc 表名
    

    2.5 数据表的类型

    -- 关于数据库引擎
    /*
    INNODB  默认使用
    MYISAM  早些年使用
    */
    
    MYISAM INNODB
    事务支持 不支持 支持
    数据行锁定 不支持 支持
    外键 不支持 支持
    全文索引 支持 不支持
    表空间大小 较小 较大,约为2倍

    常规使用操作:

    • MYISAM:节约空间,速度较快
    • INNADB:安全性高,事务处理,多表多用户操作

    在物理空间存在的位置

    所有的数据库文件都存在data目录下,一个文件夹对应一个数据库

    本质还是文件的存储

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

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

    设置数据表的字符集编码

    charset = utf8
    

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

    在my.ini中配置默认的编码

    character-set-server = utf8
    

    修改

    -- 修改表名:ALTER TABLE 旧表名 RENAME 新表名
    ALTER TABLE student RENAME teacher
    -- 增加表的字段:ALTER TABLE 表名 ADD 字段 列属性
    ALTER TABLE teacher ADD city VARCHAR(10)
    
    -- 修改表的字段(重命名,修改约束)
    ALTER TABLE teacher MODIFY city INT(10)    -- 修改约束
    ALTER TABLE teacher CHANGE city city1 VARCHAR(10)  -- 字段重命名
    
    -- ALTER TABLE 表名 DROP 字段名
    ALTER TABLE teacher DROP city1
    

    删除

    -- 删除表(如果存在则删除)
    ALTER TABLE IF EXISTS teacher
    

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

    注意点:

    • ``字段名,使用这个包裹
    • 注释 -- /**/
    • SQL关键字不区分大小写,建议小写
    • 所有符号全部是英文的

    3、MySQL数据管理

    3.1 外键(了解即可)

    方式一:在创建表的时候,增加约束(麻烦,比较复杂)

    CREATE TABLE `grade`(
    `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
    `gradename` VARCHAR(10) NOT NULL COMMENT '年级名字',
    PRIMARY KEY(`gradeid`)
    )ENGINE = INNODB DEFAULT CHARSET = utf8
    
    -- 学生表的gradeid字段,要去引用年级表的gradeid
    -- 定义外键key
    -- 给这个外键添加约束(执行引用)references引用
    
    CREATE TABLE IF NOT EXISTS `student`(
    `id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
    `name` VARCHAR(10) NOT NULL DEFAULT '匿名' COMMENT '姓名',
    `sex` VARCHAR(3) NOT NULL DEFAULT '男' COMMENT '性别',
    `gradeid` INT(10) NOT NULL COMMENT '学生年级',
    `password` VARCHAR(20) NOT NULL DEFAULT '000000' COMMENT '密码',
    `bith` DATETIME DEFAULT NULL COMMENT '出生日期',
    `address` VARCHAR(50) 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
    

    删除有外键关系的表的时候,必须先删除引用到自己的表(从表),再删除自己这张表(主表)。(例:欲先删除grade表,必须先删除student表)

    创建好数据库后,再添加外键约束

    -- 在创建表的时候没有添加外键约束的情况下
    ALTER TABLE `student` ADD CONSTRAINT `FK_gradeid`
    FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`);
    -- 公式:ALTER TABLE `表名` ADD CONSTRAINT `约束名` FOREIGN KEY (`作为外键的列`) REFERENCES `被引用的表`(`被引用表中被引用的列`);
    

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

    最佳实践

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

    3.2 DML语言(完全记住)

    数据库的意义:数据存储,数据管理

    DML语言:数据库操作语言

    • insert
    • update
    • delete

    3.3 插入

    insert

    -- 公式:INSERT INTO `表名`(`字段名1`,`字段名2`,`字段名3`...) VALUES('值1','值2','值3'...)
    INSERT INTO `grade`(`gradename`) VALUES('大四')
    -- 由于主键的自增,可以不写(但如果不写表的字段,它就会一一匹配)
    INSERT INTO `grade` VALUES('大三')
    -- 注意:添加数据的时候,字段名和值要一一对应
    
    -- 添加多个值
    INSERT INTO `grade`(`gradename`) VALUES('大三'),('大二'),('大一')
    
    INSERT INTO `student`(`name`,`sex`,`gradeid`,`password`) VALUES('张三','男','5','123456')
    

    语法:INSERT INTO 表名(字段名1,字段名2,字段名3...) VALUES('值1','值2','值3'...)

    注意事项:

    • 字段和字段之间使用英文逗号隔开
    • 字段是可以省略的,但是后面的值必须要一一对应
    • 可以同时插入多条数据,VALUES后面的值,需要用逗号隔开即可VALUES(),()

    3.4 修改

    update

    -- 修改student表中的姓名,带了条件
    UPDATE `student` SET `name`='haha' WHERE `name`='张三';
    -- 修改student表中的姓名,没有带条件,就会将表中所有的姓名改为haha
    UPDATE `student` SET `name`='haha';
    UPDATE `student` SET `name`='haha',`sex`='女' WHERE `name`='张三';
    -- 语法:
    --   UPDATE 表名 SET 字段名='值2',字段名2='值2' WHERE 条件
    

    条件:where 子句 运算符,在某个区间内修改......

    操作符会返回布尔值

    操作符 含义 范围 结果
    = 等于 5=6 false
    <>或!= 不等于 5<>6 true
    >
    <
    >=
    <=
    between...and... 在某个范围内 [1,5]
    AND &&
    OR ||
    -- 通过多个条件定位数据,无上限
    UPDATE `student` SET `name`='haha',`sex`='女' WHERE `name`='张三' AND `sex`='男';
    

    语法:UPDATE 表名 SET 字段名='值2',字段名2='值2' WHERE 条件

    注意:

    • 字段尽量都带上``
    • 条件,筛选的条件,如果没有指定,则会修改所有的列
    • 多个设置的属性之间,使用英文逗号隔开

    3.5 删除

    delete命令

    语法:delete from 表名 [where 条件]

    -- 删除数据,会全部删除,避免这样写,否则……删库跑路
    DELETE FROM `student`;
    -- 删除指定数据
    DELETE FROM `student` WHERE `id`=1;
    

    TRUNCATE 命令

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

    -- 清空student表
    TRUNCATE `student`
    

    delete和TRUNCATE的区别

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

    测试:

    -- 先新建一张表并插入数据
    -- 测试表
    CREATE TABLE IF NOT EXISTS `test`(
    `id` INT(4) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(10) NOT NULL,
    PRIMARY KEY(`id`)
    )ENGINE=INNODB DEFAULT CHARSET=utf8
    
    INSERT INTO `test`(`name`) VALUES('张三'),('李四'),('王五')
    

    此时用delete删除

    DELETE FROM `test`
    

    此时自增量没有清零

    然后再插入数据用TRUNCATE

    TRUNCATE TABLE `test`
    

    可以看到此时自动增量清零从1重新开始

    DELETE删除的问题,重启数据库

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

    4、DQL查询数据(最重点)

    4.1 DQL

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

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

    select完整语法

    SELECT[ALL|DISTINCT]
    {*|talbe.*|[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}];
    

    4.2 指定字段查询

    当前以及之后会用到的三张表的建表及导入一部分测试数据的SQL语句如下:

    -- 创建一个学生信息表
    create table `student` (
    	`studentId` int (4),
    	`studentName` varchar (30),
    	`sex` varchar (9),
    	`gradeid` int (10),
    	`password` varchar (60),
    	`bith` datetime ,
    	`address` varchar (150),
    	`email` varchar (150)
    ); 
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('1','张三','男','5','123456','1950-06-07 00:00:00','浙江巴拉巴拉',NULL);
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('2','lili','女','5','456789','1840-03-09 00:00:00','上海巴拉巴拉',NULL);
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('3','Lv','男','5','456789',NULL,'',NULL);
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('4','李四','男','4','000000','1990-03-15 00:00:00','北京巴拉巴拉',NULL);
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('5','王五','男','6','000000',NULL,'上海巴拉巴拉',NULL);
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('6','辣妹','女','9','000000',NULL,'四川',NULL);
    insert into `student` (`studentId`, `studentName`, `sex`, `gradeid`, `password`, `bith`, `address`, `email`) values('7','Lvvvvv','男','6','000000',NULL,NULL,NULL);
    
    -- 创建一个学生成绩表
    create table `result` (
    	`studentId` int (10),
    	`subjectId` int (10),
    	`results` int (4)
    ); 
    insert into `result` (`studentId`, `subjectId`, `results`) values('1','101','60');
    insert into `result` (`studentId`, `subjectId`, `results`) values('2','101','65');
    insert into `result` (`studentId`, `subjectId`, `results`) values('3','101','70');
    insert into `result` (`studentId`, `subjectId`, `results`) values('4','101','80');
    insert into `result` (`studentId`, `subjectId`, `results`) values('5','101','50');
    insert into `result` (`studentId`, `subjectId`, `results`) values('6','101','90');
    insert into `result` (`studentId`, `subjectId`, `results`) values('1','102','75');
    insert into `result` (`studentId`, `subjectId`, `results`) values('2','102','45');
    insert into `result` (`studentId`, `subjectId`, `results`) values('3','102','90');
    insert into `result` (`studentId`, `subjectId`, `results`) values('4','102','95');
    insert into `result` (`studentId`, `subjectId`, `results`) values('5','102','85');
    insert into `result` (`studentId`, `subjectId`, `results`) values('6','102','95');
    insert into `result` (`studentId`, `subjectId`, `results`) values('1','103','85');
    insert into `result` (`studentId`, `subjectId`, `results`) values('2','103','65');
    insert into `result` (`studentId`, `subjectId`, `results`) values('4','103','78');
    insert into `result` (`studentId`, `subjectId`, `results`) values('5','103','95');
    
    -- 创建一个科目表
    create table `subjects` (
    	`subjectId` int (10),
    	`subjectName` varchar (60)
    ); 
    insert into `subjects` (`subjectId`, `subjectName`) values('101','语文');
    insert into `subjects` (`subjectId`, `subjectName`) values('102','数学');
    insert into `subjects` (`subjectId`, `subjectName`) values('103','英语');
    

    注:后续的练习如果个人练习,对照着表练,字段名不要写错即可,如果参考我以下代码,由于后期字段名有所更改:以下一直到4.4联表查询之间的 id-->studentId,name-->studentName,subject-->subjectId

    -- 查询student表中的所有信息
    SELECT * FROM `student`
    
    -- 查询指定字段
    SELECT `id`,`name` FROM `student`
    
    -- 别名,给结果起一个名字。用AS可以给字段起别名,也可以给表起
    SELECT `id` AS 学号,`name` AS 姓名 FROM `student`
    
    -- 函数 Concat(a,b),拼接字符串,将a和b拼接起来
    SELECT CONCAT('姓名:',`name`) AS 学生姓名 FROM `student`
    

    语法:SELECT 字段...... FROM 表名

    有的时候,列名字不是读者不懂,就可以起别名: 字段名 AS 别名 表名 AS 别名

    去重 distinct

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

    SELECT `id` FROM `result`  -- 这样查询出来的数据有大量重复
    SELECT DISTINCT `id` FROM `result`  -- 用DISTINCT去除重复
    

    语法:SELECT DISTINCT 字段名 FROM 表名

    数据库的列(表达式)

    SELECT VERSION()  -- 查询系统版本 (函数)
    SELECT 100*3-1 AS 计算结果   -- 用来计算 (表达式)
    SELECT @@auto_increment_increment   -- 查询自增的步长 (变量)
    
    -- 让所有学生的id加一
    SELECT `id`+1 AS 加一后,`name` FROM `student`
    

    数据库中的表达式:文本值、列,NULL,函数,计算表达式,系统变量......

    select 表达式 from 表

    4.3 where条件子句

    作用:检索数据中符合条件的值

    逻辑运算符

    运算符 语法 描述
    and && a and b a&&b 逻辑与
    or || a or b a||b 逻辑或
    Not ! not a !=a 逻辑非
    SELECT `id`,`name` FROM `result`;
    
    -- And,查询60分~100分之间的学生
    SELECT `id`,`name` FROM `result`WHERE `results`>60 AND `results`<100;
    
    -- or,查询成绩等于60或59的学生
    SELECT `id`,`name` FROM `result`WHERE `results`=60 OR `results`=59;
    
    -- not,查询成绩小于60分的学生
    SELECT `id`,`name` FROM `result` WHERE NOT `results`>60;
    

    模糊查询:比较运算符

    运算符 语法 描述
    is null a is null 如果操作符为null,结果为真
    is not null a is not null 如果操作符为not null 结果为真
    between a between b and c 若a在b和c之间,则结果为真
    like a like b 如果a匹配b,则结果为真
    in a in (a1,a2....) 假设a在a1或者a2...则结果为真
    -- like
    -- 查询姓张的同学
    -- like结合 %(代表0到任意个字符) _(一个字符)
    SELECT `id`,`name`,`sex` FROM `student` WHERE `name` LIKE '张%'
    
    -- 查询姓张的但名字只有一个字的
    SELECT `id`,`name`,`sex` FROM `student` WHERE `name` LIKE '张_'
    
    -- 查询名字中间有辉字的
    SELECT `id`,`name`,`sex` FROM `student` WHERE `name` LIKE '%辉%'
    
    -- ==========in(具体的一个或多个值)===========
    SELECT `id`,`name`,`sex` FROM `student` WHERE `address` IN ('四川','上海巴拉巴拉')
    
    -- =========null   not null===========
    -- 查询地址为空的,null或者空字符串''
    SELECT `id`,`name`,`sex` FROM `student` WHERE `address`='' OR `address` IS NULL
    
    -- 查询有出生日期的 不为空not null
     SELECT `id`,`name`,`sex` FROM `student` WHERE `bith` IS NOT NULL
    

    4.4 连表查询

    -- ================ 联表查询 JOIN ====================
    /*
    思路:
    1、分析需求,分析查询的字段来自哪些表,(连接查询)
    2、确定使用哪种连接查询?
    3、判断交叉点(这两个表中有哪些数据是相同的)
    */
    -- 查询参加了考试的同学(学号,姓名,科目id,分数)
    -- ======= INNER JOIN ========
    SELECT s.`id`,`name`,`subject`,`results`
    FROM `student` AS s INNER JOIN `result` AS r
    WHERE s.id = r.id
    -- INNER JOIN查出来的是两个表都有的
    
    -- ======= LEFT JOIN ========
    -- where可以用on,as在一定条件下可以省略,这里可以省略
    SELECT s.`id`,`name`,`subject`,`results`
    FROM `student` s LEFT JOIN `result` r
    ON s.id = r.id
    -- LEFT JOIN查询,只要左表即student表有的即使右边的表即result表没有的也会显示出来
    
    -- ======= RIGHT JOIN ========
    SELECT s.`id`,`name`,`subject`,`results`
    FROM `student` s RIGHT JOIN `result` r
    ON s.id = r.id
    -- RIGHT JOIN查询,只要右表有的即使左表没有的也会显示出来
    
    -- join 连接的表 on(判断的条件) 连接查询
    -- where 等值查询
    
    操作 描述
    Inner join 如果表中至少有一个匹配,就返回行
    left join 会从左表中返回所有的值,即使右表中没有
    right join 会从右表中返回所有的值,即使左表中没有
    -- 三表查询
    -- 查询参加了考试的学生,增加一个科目名字段
    SELECT s.`studentId`,`studentName`,`subjectId`,`subjectName`,`results`
    FROM `student` s RIGHT JOIN `result` r
    ON s.id = r.id
    INNER JOIN `subjects` sub
    ON r.`subject`=sub.`subjectId`
    
    -- 我要从哪几个表去查 select......
    -- 从哪几个表中查from 表  XXX JOIN 连接的表 on 交叉条件
    -- 假设存在一种多表查询,慢慢来,一个一个来,像我上面的三表查询一样
    

    自连接

    自己的表和自己的表连接,核心:一张表拆成两张一样的表

    当自己的父id和对方的子id相匹配,说明自己是对方的儿子,自己属于对方的范围

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

    4.5 分页和排序

    排序

    -- ================= 分页 limit 和排序 order by ======================
    
    -- 排序:升序ASC   降序:DESC
    SELECT s.`studentId`,`studentName`,`subjectName`,`results`
    FROM `student` s INNER JOIN `result` r
    ON s.`studentId` = r.`studentId`
    INNER JOIN `subjects` sub
    ON r.`subjectId` = sub.`subjectId`
    WHERE `subjectName` = '语文'
    ORDER BY `results` DESC
    

    分页

    -- 分页
    -- 语法:LIMIT 起始值,每页显示的数据条数
    SELECT s.`studentId`,`studentName`,`subjectName`,`results`
    FROM `student` s INNER JOIN `result` r
    ON s.`studentId` = r.`studentId`
    INNER JOIN `subjects` sub
    ON r.`subjectId` = sub.`subjectId`
    ORDER BY `results` DESC
    LIMIT 0,5
    
    -- 第一页 limit 0,5   (1-1)*5
    -- 第二页 limit 5,5    (2-1)*5
    -- 第三页 limit 10,5    (3-1)*5
    -- 第N页 limit (n-1)*pageSize,5    (n-1)*pageSize,pageSize
    -- 【pageSize:页面大小】
    -- 【(n-1)*pageSize:起始值】
    -- 【n:当前页】
    -- 【数据总数、页面大小 = 总页数】
    

    语法:limit(查询起始值下标,pageSize)

    4.6 子查询

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

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

    -- 查询所有考的语文的同学的学号、科目名、成绩,降序排列
    -- 方式一
    SELECT `studentId`,`subjectName`,`results`
    FROM `result` r
    INNER JOIN `subjects` sub
    ON r.`subjectId` = sub.`subjectId`
    WHERE `subjectName`='语文'
    ORDER BY `results` DESC
    
    -- 方式二,子查询
    -- 1.先从subject表中查出语文的`subjectId`传给第二步
    SELECT `subjectId` FROM `subjects` WHERE `subjectName`='语文'
    -- 2.从成绩表中查出考了语文的同学的id传给第三步
    SELECT `studentId`,`subjectId`,`results` FROM `result` 
    WHERE `subjectId` = 
    (SELECT `subjectId` FROM `subjects` 
    WHERE `subjectName`='语文')
    ORDER BY `results` DESC
    
    -- 子查询:查询考了语文的前三名同学的学号、姓名
    SELECT `studentId`,`studentName` FROM `student` 
    WHERE `studentId` IN (SELECT `studentId` FROM `result` WHERE `subjectId` = (
    SELECT `subjectId` FROM `subjects` WHERE `subjectName` = '语文')
    ORDER BY `results` DESC
    )LIMIT 0,3
    
    -- 查询考了语文的前三名的学号、姓名
    SELECT s.`studentId`,`studentName` FROM `student` s
    INNER JOIN `result` r
    ON s.`studentId` = r.`studentId`
    WHERE `subjectId` = (
    SELECT `subjectId` FROM `subjects` WHERE `subjectName` = '语文'
    ) ORDER BY `results`
    LIMIT 0,3
    
    

    4.7 分组过滤

    -- 查询所有科目的平均分,最高分,最低分
    -- 核心:根据科目分类
    SELECT `studentId`,`subjectName`,AVG(`results`) AS 平均分,MAX(`results`) AS 最高分,MIN(`results`) AS 最低分
    FROM `result` r INNER JOIN `subjects` sub
    ON r.`subjectId`=sub.`subjectId`
    GROUP BY r.`subjectId`
    HAVING 平均分>=80
    

    5、MySQL函数

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

    5.1 常用函数

    常用函数(了解即可,时间日期需记住)

    -- ========================== 常用函数 =================================
    -- 数学运算
    SELECT ABS(-8)   -- 绝对值
    SELECT CEILING(9.4)   -- 向上取整
    SELECT FLOOR(9.4)   -- 向下取整
    SELECT RAND()   -- 返回一个0~1之间的随机数
    SELECT SIGN(-10)   -- 判断一个数的符号 0-0 负数返回-1 正数返回1
    
    -- 字符串函数
    SELECT CHAR_LENGTH('hello everyone')   -- 字符串长度
    SELECT CONCAT('i','love','you')   -- 拼接字符串
    SELECT INSERT('我爱编程',1,2,'超级热爱')  -- 查询,从指定位置开始替换指定长度的字符串
    SELECT LOWER('LV')  -- 大写转小写
    SELECT UPPER('lv')   -- 小写转大写
    SELECT INSTR('i love you','o')   -- 返回第一次出现的子串的索引
    SELECT REPLACE ('坚持就能成功','坚持','努努力')   -- 用字符串替换指定字符串
    SELECT SUBSTR('坚持就能成功',1,3)   -- 返回指定的字符串(源字符串,开始截取的位置,截取的长度)
    
    -- 查询姓张的同学,将张改为章
    SELECT REPLACE(`studentName` ,'张','章') FROM `student`
    WHERE `studentName` LIKE '张%'
    
    -- 时间和日期函数(记住)
    SELECT CURRENT_DATE()  -- 获取当前日期
    SELECT NOW()   -- 获取当前的时间
    SELECT LOCALTIME()   -- 获取本地时间
    SELECT SYSDATE()   -- 系统时间
    SELECT YEAR(NOW())
    SELECT MONTH(NOW())
    SELECT DAY(NOW())
    -- ......
    
    -- 系统
    SELECT SYSTEM_USER()
    SELECT USER()
    SELECT VERSION()
    

    5.2 聚合函数

    函数名称 描述
    COUNT() 计数
    SUM() 求和
    AVG() 平均值
    MAX() 最大值
    MIN() 最小值
    ...... ......
    -- =========聚合函数============
    SELECT COUNT(`bith`) FROM `student`;   -- Count(字段),会忽略所有的null值
    SELECT COUNT(*) FROM `student`;   -- Count(*) 不会忽略null值,相当于统计所有行
    SELECT COUNT(1) FROM `student`;   -- Count(1) 不会忽略null值,相当于将所有行都设为1,统计1的个数
    -- Count(0)统计所有为null值的行
    /* 执行效率上
    若列名为主键,则count(列名)快于count(1),不为主键则count(1)更快
    如果多个列且没有主键,count(1)快于count(*)
    如果表只有一个字段,count(*)最优
    */
    

    5.3 数据库级别MD5加密(扩展)

    什么是MD5?

    主要增强算法复杂度和不可逆性。

    MD5不可逆,具体的值的MD5都是一样的

    -- ==========测试MD5 加密=============
    
    CREATE TABLE `testmd5`(
    `id` INT(4) NOT NULL,
    `name` VARCHAR(50) NOT NULL,
    `pwd` VARCHAR(50) NOT NULL,
    PRIMARY KEY(`id`)
    )ENGINE = INNODB DEFAULT CHARSET = utf8
    
    INSERT INTO `testmd5` VALUES('1','张三','123456'),('2','李四','111111'),('3','王五','654332')
    
    -- 加密
    UPDATE `testmd5` SET `pwd`=MD5(pwd) WHERE `id`=1;
    UPDATE `testmd5` SET `pwd`=MD5(pwd)
    
    -- 插入的时候加密
    INSERT INTO `testmd5` VALUES(4,'小明',MD5('123456'))
    
    -- 如何校验:将用户传递进来的密码,进行MD5加密,然后对比加密后的值
    SELECT * FROM `testmd5` WHERE `name`='小明' AND pwd=MD5('123456')
    

    6、事务

    要么都成功要么都失败


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

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


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

    事务原则:ACID原则 原子性、一致性、隔离性、持久性

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

    原子性(Atomicity)
    要么都成功,要么都失败
    一致性(Consistency)
    事务前后数据的完整性必须保持一致。
    隔离性(Isolation
    事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
    持久性(Durability)
    事务一旦提交则不可逆

    隔离所导致的问题

    脏读:

    指一个事务读取了另外一个事务未提交的数据。

    不可重复读:

    在一个事务内读取表中的某一行数据,多次读取结果不同。

    虚读(幻读):

    是指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。

    -- ==================== 事务 ========================
    -- MySQL 是默认开启事务自动提交的
    SET autocommit = 0  -- 关闭
    SET autocommit = 1  -- 开启(默认)
    
    -- 手动处理事务
    SET autommit = 0   -- 关闭自动提交
    
    -- 事务开启
    START TRANSACTION  -- 标记一个事务的开始,从这个之后的SQL都在同一个事务内
    
    -- 提交:持久化(成功)
    COMMIT
    -- 回滚:回到原来的样子(失败)
    ROLLBACK
    
    -- 事务结束
    SET autocommit = 1   -- 开启自动提交
    
    SAVEPOINT 保存点名   -- 设置一个事务的保存点
    RELEASE SAVEPOINT 保存点名   -- 删除保存点
    

    模拟银行转钱场景

    -- ==================== 模拟事务 =======================
    -- 创建一个数据库
    CREATE DATABASE `bank` CHARACTER SET utf8 COLLATE utf8_general_ci;
    USE `bank`;
    
    -- 创建一张表
    CREATE TABLE `account`(
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(50) NOT NULL,
    `money` DECIMAL(9,2),  -- DECIMAL(9,2)表示存储9位数字,2位小数
    PRIMARY KEY (`id`)
    )ENGINE = INNODB DEFAULT CHARSET = utf8
    
    INSERT INTO `account`(`name`,`money`) VALUES ('张三',5000.00),('李四',10000.00);
    
    SET autocommit = 0;   -- 关闭自动提交
    
    START TRANSACTION;   -- 开启一个事务
    
    UPDATE `account` SET `money`=`money`-500 WHERE `name`='张三';
    UPDATE `account` SET `money`=`money`+500 WHERE `name`='李四';
    
    COMMIT  -- 成功则提交
    ROLLBACK   -- 失败则回滚
    
    SET autocommit = 1;   -- 结束开启自动提交
    

    7、索引

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

    提取句子主干,就可以得到索引的本质:索引是数据结构。

    7.1 索引的分类

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

    • 主键索引(PRIMARY KEY)
      • 唯一标示,主键不可重复,只能有一个列作为主键
    • 唯一索引(UNIQUE KEY)
      • 避免重复的列出现,唯一索引可以重复,多个列都可标识为唯一索引
    • 常规索引(KEY/INDEX)
      • 默认的,index/key关键字
    • 全文索引(FullText)
      • 在特定的数据库引擎下才有,MyISAM
      • 快速定位数据
    -- ==================索引===================
    -- 1.在创建表的时候给字段增加索引
    -- 2.创建完毕后,增加索引
    
    
    -- 显示所有索引信息
    SHOW INDEX FROM student
    
    -- 增加一个全文索引    (索引名)  列名
    ALTER TABLE learn.student ADD FULLTEXT INDEX `studentName`(`studentName`);
    
    
    -- EXPLAIN 分析SQL执行的情况
    EXPLAIN SELECT * FROM `student`;
    
    EXPLAIN SELECT * FROM `student` WHERE MATCH(`studentName`) AGAINST('张');
    

    7.3 索引测试

    小量数据索引不明显,需要大量的数据来支撑,想测试的下伙伴可以去搜一下,这里就不做过多的测试了。大概100万条数据不加索引查询数据的话,快的电脑用时1秒,然后加了索引之后用时0.001秒。

    7.4 索引原则

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

    8、权限管理和备份

    8.1 用户管理

    SQL yoga可视化管理

    SQL命令操作

    用户表:mysql.user

    本质:对这张表进行增删改查

    -- ====================权限管理==================
    -- 创建用户CREATE USER 用户名 IDENTIFIED BY '密码'
    CREATE USER Lv IDENTIFIED BY '123456'
    
    -- 修改密码(修改当前用户密码)
    SET PASSWORD = PASSWORD('123456')
    
    -- 修改指定用户密码
    SET PASSWORD FOR Lv = PASSWORD('123456')
    
    -- 重命名 
    RENAME USER Lv TO Lvvvv
    
    -- 用户授权
    GRANT ALL PRIVILEGES ON *.* TO Lvvvv
    
    -- 查询权限,如果是默认%可以不用写,localhost则要写@localhost
    SHOW GRANTS FOR Lvvvv@localhost
    
    -- 撤销权限
    REMOVE ALL PRIVILEGES ON *.* FROM Lvvvv
    
    -- 删除用户
    DROP USER Lvvvv
    

    8.2 MySQL 备份

    为什么要备份:

    • 保证重要的数据不丢失
    • 数据转移

    MySQL数据库备份的方式

    • 直接拷贝物理文件
    • 在sqlyog这样的可视化工具中导出
    • 使用命令行导出 mysqldump
    # mysqldump -h主机 -u用户名 -p密码 数据库名 表名 >目的磁盘位置
    mysqldump -hlocalhost -uroot -p123456 learn student >D:/a.sq
    #多张表
    # mysqldump -h主机 -u用户名 -p密码 数据库名 表1 表2 表3 >目的磁盘位置
    #导出数据库
    #mysqldump -h主机 -u用户名 -p密码 数据库名>目的磁盘位置
    
    #导入
    #在登陆的情况下
    #source D:/a.sql
    

    9、规范数据库设计

    9.1 为什么需要设计

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

    糟糕的数据库设计:

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

    良好的数据库设计:

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

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

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

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

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

    9.2 三大范式

    为什么需要规范化?

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

    三大范式

    第一范式(1NF)

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

    第二范式(2NF)

    前提:满足第一范式的前提下

    每张表只描述一件事情

    第三范式(3NF)

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

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

    (规范数据库的设计)

    规范性和性能的问题

    阿里里面规定关联查询的表不得超过三张

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

    10、JDBC

    10.1 数据库驱动

    应用程序不能直接操作数据库,因此,需要通过数据库驱动来操作数据库。

    10.2 JDBC

    sun公司为了简化开发人员(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,俗称JDBC,这些规范的实现有具体厂商去做。

    对于开发人员来说,只需要掌握JDBC即可。

    10.3 第一个JDBC程序

    创建测试数据库

    1. 建立一个数据库,在其中新建一张表并插入一些用来测试的数据,这里我就用上面的learn数据库下的student表。

    2. 导入数据库驱动

      数据库驱动可以去官网下载与自己数据库相关的版本

    3. 连接并操作数据库

    package com.kuang;
    
    import java.sql.*;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 9:18 2020/7/17
     */
    public class Test01 {
        public static void main(String[] args) throws ClassNotFoundException, SQLException {
            //1.加载驱动
            Class.forName("com.mysql.jdbc.Driver");  //固定写法
    
            //2.用户信息和url
            //useUnicode=true&characterEncoding=utf8&useSSL=true
            String url = "jdbc:mysql://localhost:3306/learn?useUnicode=true&characterEncoding=utf8&useSSL=true";
            String username = "root";
            String password = "123456";
            //3.连接成功,数据库对象
            Connection connection = DriverManager.getConnection(url, username, password);
    
            //4.执行SQL的对象
            Statement statement = connection.createStatement();
    
            //5.执行SQL的对象 去执行SQL 可能存在结果,查看返回结果
            String sql = "SELECT * FROM student";
    
            ResultSet resultSet = statement.executeQuery(sql);
    
            while (resultSet.next()){
                System.out.println("id="+resultSet.getObject("studentId"));
                System.out.println("name="+resultSet.getObject("studentName"));
                System.out.println("sex="+resultSet.getObject("sex"));
                System.out.println("===================================");
            }
            //6.释放连接
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    

    步骤总结:

    1、加载驱动

    2、连接数据库 DriverManager

    3、获得执行SQL的对象 statement

    4、获得返回的结果集

    5、释放连接

    DriverManager

    //3.连接成功,数据库对象
    Connection connection = DriverManager.getConnection(url, username, password);
    

    url

    String url = "jdbc:mysql://localhost:3306/learn?useUnicode=true&characterEncoding=utf8&useSSL=true";
    
    // 协议://主机地址:端口号/数据库名?参数1&参数2&参数3
    

    Statement 执行SQL对象 PreparedStatement

    statement.executeQuery();   //执行查询
    statement.execute();   //执行所有语句
    statement.executeUpdate();   //执行更新、插入、删除语句
    

    ResultSet 封装了结果集

    获取指定类型的数据

    resultSet.getObject();
    resultSet.getString();
    resultSet.getInt();
    resultSet.getDouble();
    resultSet.getDate();
    

    释放资源

    //6.释放连接
    resultSet.close();
    statement.close();
    connection.close();
    

    10.4 statement对象

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

    statement对象的executeUpdate方法,用于向数据库发送增、删、改的SQL语句,executeUpdate执行完后,会返回一个整数(即增删改语句导致了数据库收到影响的行数)

    statement.Query方法用于向数据库发送查询语句,executeQuery方法返回一个ResultSet结果集

    CRUD操作create

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

    Statement statement = connection.createStatement();
    String sql = "insert into student(...) values(...)";
    int num = statement.executeUpdate(sql)
    if(num>0){
        System.out.println("插入成功");
    }
    

    CRUD操作delete

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

    Statement statement = connection.createStatement();
    String sql = "delete from student where id=1";
    int num = statement.executeUpdate(sql)
    if(num>0){
        System.out.println("删除成功");
    }
    

    CRUD操作update

    使用executeUpdate(String sql)方法完成数据更新操作,示例如下 :

    Statement statement = connection.createStatement();
    String sql = "update student set name='莉莉' where id=3";
    int num = statement.executeUpdate(sql)
    if(num>0){
        System.out.println("修改成功");
    }
    

    CRUD操作read

    使用executeQuery(String sql)方法完成数据更新操作,示例如下 :

    Statement statement = connection.createStatement();
    String sql = "SELECT * FROM student";
    ResultSet resultSet = statement.executeQuery(sql);
     while (resultSet.next()){}
    

    代码实现

    1、先创建一个db.properies文件存放url等

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://localhost:3306/learn?useUnicode=true&characterEncoding=utf8&useSSL=true
    username=root
    password=123456
    

    2、写JDBCUtils工具类

    package com.kuang.utils;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 11:33 2020/7/17
     */
    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 conn, Statement st, ResultSet rs){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(st!=null){
                try {
                    st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    查询实现

    package com.kuang;
    
    import com.kuang.utils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 12:09 2020/7/17
     */
    public class QueryTest {
        public static void main(String[] args) {
    
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
    
            try {
                conn = JDBCUtils.getConnection();
                st = conn.createStatement();
    
                String sql = "SELECT * FROM `student`";
                rs = st.executeQuery(sql);
                while (rs.next()){
                    System.out.println("学号="+rs.getInt("studentId"));
                    System.out.println("姓名="+rs.getString("studentName"));
                    System.out.println("性别="+rs.getString("sex"));
                    System.out.println("年级="+rs.getString("gradeid"));
                    System.out.println("密码="+rs.getString("password"));
                    System.out.println("生日="+rs.getDate("bith"));
                    System.out.println("家庭住址="+rs.getString("address"));
                    System.out.println("=============================================");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                JDBCUtils.release(conn,st,rs);
            }
        }
    }
    
    

    插入实现(更新、删除与插入一样,只需要改SQL语句即可)

    package com.kuang;
    
    import com.kuang.utils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 11:47 2020/7/17
     */
    public class InsertTest {
        public static void main(String[] args) {
    
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
    
            try {
                conn = JDBCUtils.getConnection();  //获取数据库连接
                st = conn.createStatement();   //获取SQL的执行对象
                String sql = "INSERT INTO `student`(`studentId`,`studentName`,`sex`,`gradeid`,`password`,`bith`)" +
                        "VALUES(10,'婷婷','女','大四','123456','1998-03-15')";
    
                int i = st.executeUpdate(sql);
                if (i>0){
                    System.out.println("插入成功");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                JDBCUtils.release(conn,st,rs);
            }
        }
    }
    

    SQL注入的问题

    sql存在漏洞,会被攻击导致数据泄露(被读取全部内容)

    import com.kuang.utils.JDBCUtils;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 12:41 2020/7/17
     */
    public class SQLProblem {
        public static void main(String[] args) {
            login(" 'or' 1=1"," 'or' 1=1");
        }
    
        //登陆业务
        public static void login(String name, String password){
            Connection conn = null;
            Statement st = null;
            ResultSet rs = null;
    
            try {
                conn = JDBCUtils.getConnection();
                st = conn.createStatement();
    
                //SELECT * FROM `student` WHERE `studentName`='Lv' AND `password`='456789'
                //SELECT * FROM `student` WHERE `studentName`=' 'or' 1=1' AND `password`=' 'or' 1=1'
                String sql = "SELECT * FROM `student` WHERE `studentName`='"+name+"' AND `password`='"+password+"'";
                rs = st.executeQuery(sql);
                while (rs.next()){
                    System.out.println("姓名="+rs.getString("studentName"));
                    System.out.println("密码="+rs.getString("password"));
                    System.out.println("=============================================");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                JDBCUtils.release(conn,st,rs);
            }
        }
    }
    

    会被读取这张表中的全部用户信息,如下:

    10.5 PreparedStatement对象

    PreparedStatement 可以防止SQL注入,而且效率更高

    插入操作,其他对照着都能写出来,就不再阐述

    import com.kuang.utils.JDBCUtils;
    
    import java.sql.Connection;
    import java.util.Date;
    import java.sql.PreparedStatement;
    import java.sql.SQLException;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 15:18 2020/7/17
     */
    public class PreparedStatment {
        public static void main(String[] args) {
    
            Connection conn = null;
            PreparedStatement st = null;
    
            try {
                conn = JDBCUtils.getConnection();
                //区别
                // 使用?占位符来代替参数
                String sql = "INSERT INTO `student`(`studentId`,`studentName`,`sex`,`gradeid`,`password`,`bith`) VALUES(?,?,?,?,?,?)";
                st = conn.prepareStatement(sql); //预编译,先不执行
                st.setInt(1,15);
                st.setString(2,"阿豪");
                st.setString(3,"男");
                st.setString(4,"大三");
                st.setString(5,"159753");
                //new Date().getTime()   java的until包下的
                //new java.sql.Date()    数据库的时间类,要将java类型的转为SQL类型的
                st.setDate(6,new java.sql.Date(new Date().getTime()));
    
                int i = st.executeUpdate();
                if (i>0){
                    System.out.println("插入成功");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }finally {
                JDBCUtils.release(conn,st,null);
            }
        }
    }
    

    PreparedStatement防止注入的本质,把传递进来的参数当做字符,假设其中存在转义字符,比如说 ' 会被直接转义

    10.6 事务

    要么都成功,要么都失败

    ACID原则

    原子性:要么全部完成,要么都不完成

    一致性:总数不变

    隔离性:多个进程互不干扰

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

    隔离性的问题:

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

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

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

    代码实现

    1、开启事务conn.setAutoCommit(false);

    2、一组业务执行完毕,提交事务

    3、可以在catch语句中显式定义回滚语句,不定义默认失败也会回滚

    10.7 数据库连接池

    数据库连接--->执行完毕--->释放

    连接--->释放十分浪费资源

    package com.kuang.c3p0;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import java.sql.*;
    
    /**
     * @Author: Lv
     * @Description:
     * @Vision: 1.0
     * @Date: Created in 17:39 2020/7/17
     */
    public class c3p0_TestUtils {
    
        private static ComboPooledDataSource dateSource = null;
    
        static {
            try {
                //获取连接
                dateSource = new ComboPooledDataSource("MySQL");
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        //获取连接
        public static Connection getConnection() throws SQLException {
            return dateSource.getConnection();
        }
    
        //释放连接资源
        public static void release(Connection conn, Statement st, ResultSet rs){
            if(rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(st!=null){
                try {
                    st.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    结论

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

  • 相关阅读:
    启动时创建线程并传递数据
    C# 匿名方法 委托 Action委托 Delegate委托
    linq里的select和selectmany操作 投影运算
    C# 基础小知识之yield 关键字 语法糖
    在您的应用上运行性能测试
    loadrunner11有效的license
    30-hadoop-hbase-安装squirrel工具
    31-hadoop-hbase-mapreduce操作hbase
    29-hadoop-使用phtonenix工具&分页&数据导入
    28-hadoop-hbase入门小程序
  • 原文地址:https://www.cnblogs.com/Lv-orange/p/13417847.html
Copyright © 2011-2022 走看看