MySQL——数据库

news2024/10/25 2:00:30

什么是数据库

  • 数据库(DB , DataBase)
  • 概念:数据仓库,软件安装在操作系统(window,linux,max,...)之上
  • 学习数据库最重要的就是学习SQL语句
  • 存储500万以下的数据,若是500万以上就要优化索引,不然查询速度比较慢
  • 作用:存储数据,管理数据

数据库分类

关系型数据库:(SQL)

  • MySQL,Oracle,Sql Server,DB2,SQLlite
  • 通过表和表之间,行和列之间的关系进行数据的存储

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

  • Redis,MongDB
  • 非关系型数据库,对象存储,通过对象自身的属性来决定

DBMS(数据库管理系统)

  • 数据库的管理软件,科学有效的管理我们的数据、维护和获取数据
  • MySQL本质上是一个数据库管理系统
  • 跟DB的区别就在于:DB仅仅只存储数据,DBMS是用来管理和获取数据

MySQL简介

  • MySQL是一个关系型数据库管理系统
  • 前世:瑞典MySQL AB公司
  • 今生:属于Oracle旗下产品
  • MySQL是最好的RDBMS(关系型数据库管理系统)应用软件之一
  • 开源的数据库软件
  • 体积小、速度快、总体成本低
  • 适用于大中小型网站,MySQL能够实现集群

如何卸载MySQL

sc delete mysql

执行以上命令可以清空服务

如何新建数据库

  • 字符集:utf8mb4
  • 排序规则:utf8mb4_bin

我这边使用的是Navicat,Navicat->工具->历史日志里面可以查看操作记录

每一个在navicat中的执行操作,本质上就是一个SQL语句

创建表

输入id、name、age的信息,养成写注释的习惯;id、name、age都属于重要的信息,因此要设置非空;id是主键,设置key;类型、长度都要根据实际情况进行设置

设置完后再点击保存,输入表的名称,就创建好表了

查看表

右键->打开表

添加多条数据(记得保存)

连接数据库

命令行连接

// 连接数据库

mysql -uroot -p123456

// 修改密码

update mysql.user set authentication_string=password('123456) where user='root' and Host ='localhost';

// 刷新权限

flush privileges;

------------------------------------------------------------------------------

// 所有的语句都使用分号(;)结尾

// 查看所有的数据库

show databases;

// 切换数据库 use 数据库名

use school

.

// 查看数据库中所有的表

show tables;

.

// 查看表中的数据

desc student;

.

// 创建一个数据库

create database weston;

.

// 进行waston的一系列操作

.

// 退出连接

exit;

.

-- 单行注释

/* 多行注释 */

数据库XXX语言 (CRUD)增删改查

  • DDL——定义
  • DML——操作
  • DQL——查询
  • DCL——控制

操作数据库

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

MySQL的关键字不区分大小写

创建数据库

如果创建一个原本就有的数据库,就会报错

但是如果我们一开始并不知道是否存在这个数据库,又不想报错该怎么办?

这个时候就要使用以下代码

删除数据库

如果删除一个不存在的数据表,也会报错

如果同样不想报错,可以使用以下代码

 

使用数据库

以上两种样式都可以,加上``是因为不知道school是否是特殊字符

  • 如果你的数据库名或者表名或者字段名是一个特殊字符,就需要(`数据库名/表名/字段名`)
  • 例如你的字段名是user
  • 这个时候查询语句本应该是 SELECT USER FROM STUDENT;
  • 但是USER会高亮,并且查询不到你需要的信息
  • 这个时候SQL语句就需要改成,SELECT  `user`  FROM STUDENT;

查看数据库

数据库的列(数据)类型

数值

  • tinyint           十分小的数据            1个字节
  • smallint        较小的数据                2个字节
  • mediumint    中等大小的数据         3个字节
  • int                 标准的整数                4个字节        常用的
  • bigint            较大的数据                8个字节
  • float                浮点数                4个字节
  • double            浮点数                8个字节        (精度问题)
  • decimal          字符串形式的浮点数        金融计算的时候一般使用decimal

字符串

char                字符串固定大小的      0~255          

varchar            可变字符串                0~65535        常用的变量        对应String

tinytext              微型文本                   2^8 - 1

text                    文本串                      2^16 - 1         保存大文本        依旧对应String

时间日期

java.util.Data

  • date                YYYY-MM-DD        日期格式
  • time                HH:mm:ss               时间格式
  • datetime          YYYY-MM-DD HH:mm:ss        最常用的时间格式
  • timestamp        时间戳        1970.1.1到现在的毫秒数        较为常用
  • year                年份表示

null

  • 没有值,未知
  • 注意,不要使用NULL进行运算,因为怎么运行都为NULL

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

Unsigned(无符号)

无符号的整数

声明了该列不能声明为负数

zerofill(0填充)

0填充的

假设你数组长度为10,但只添加了一个数据,这个时候有后面9位就会用0来填充

自增

通常理解为自动在上一条记录的基础上 +1(默认)

通常用来设计唯一的主键  index,而且必须是整数类型

可以自定义设计主键自增的起始值和步长(在选项当中)

非空  NULL、NOT NULL 

假设设置为NOT NULL,如果不给他赋值,就会报错!

如果设置为NULL,如果不填写值,默认就是NULL!

默认

设置默认值

假设我设置sex(性别)这个字段的默认值为男,如果我不指定该列的值,则该列的值都是男

小结

  • UNSIGNED(无符号)勾选上就说明填充的数据不能是负数
  • ZEROFILL(0填充)勾选上就说明会用0补上没有填写上的位数,例如你定义了int类型且长度是5,这个时候你填充数据的时候只写了1,它就会帮你改写成00001;
  • NOT NULL(非空)勾选上就说明该列元素不能不填写 ->(除非你勾选上自增,且该列元素的属性是数值类型)
  • AUTO_INCREMENT(自增)勾选上就说明如果你没有填写该列数据,他就会在你上一行数据的基础上加1填充(都是整数),这种情况下是基于该列元素设置为NOT NULL
  • DEFAULT(默认)勾选上就可以设置该列元素的默认值,在新增字段的时候该列元素的值就是我们自己设置的默认值,可以修改

数据库中的每一个表都必须存在以下五个字段

  • id        主键
  • `version`        乐观锁                每一条记录都有自己对应的版本
  • is_delete        伪删除                这条记录是否被删除,我们并不希望这个数据真正的被删掉,我们就用这个标志位来判断,如果这个标志位为1的话,我们就认为它被删掉了,但是数据库中还存在
  • gmt_create        创建时间                这条记录的创建时间
  • gmt_update        修改时间                这条记录的修改时间

创建数据库表(重点)

注意点:

  • 表名和字段名最好都加上``,以免出现跟特殊字符一样的情况
  • 每个字段最好都设置默认值(DEFAULT '默认值',默认值可以是NULL,DEFAULT NULL),并给出注释(COMMENT '注释')
  • 但是要注意一点的就是在设置NOT NULL之后,默认值就不能设置成NULL了
  • DATETIME不需要设置长度 默认值的格式可以是 YYYY-MM-DD HH:mm:ss
  • PRIMARY KEY是用来设置主键的,一般不将它放在某一字段的后面,不够一目了然,所以放在建表语句中的最后一行,PRIMARY KEY(字段名) 
  • 建表之后可以加上引擎名和字符集 ENGINE=INNODB DEFAULT CHARSET=utf8

查看创建数据库的语句

SHOW CREATE DATABASE 数据库名;

查看创建数据表的语句

SHOW CREATE TABLE  数据表名;

显示数据表的结构

DESC 数据表名;

关于数据库引擎

INNODB   ——  默认使用

MYISAM   ——  早些年使用的

MYISAMINNODB
事务支持不支持支持,比如说两个sql语句一起执行,要么全成功要么全失败
数据行锁定不支持,只支持数据表锁定,适用于需要保证整个表的一致性,例如对整个表进行大批量的更新或者维护支持,其他事务能够访问表中的其他行,适用于高并发读写,降低锁的争用
外键约束不支持,无法实现数据库级别的表跟表的联系支持
全文索引支持以前不支持,现在支持
表空间的大小较小较大,约为MYISAM的两倍

常规使用操作:

MYIASM:节约空间,速度较快

INNODB:安全性高,能够进行事务的处理,有外键约束使得它能够多表多用户操作

MYSIAM和INNODB在物理空间存在的位置

  • 所有的数据库文件都存在data目录下,一个文件夹对应一个数据库
  • 本质上还是文件的存储

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

  • INNODB在数据库表中只有一个*.frm文件(但是mysql8之后都合并在*.ibd文件当中)以及上级目录下的ibdata1文件
  • MYISAM对应文件
    • *.frm      ——  表结构的定义文件
    • *.MYD   ——  数据文件(data)
    • *.MYI     ——  索引文件(index)

设置数据库的字符集编码

DEFAULT CHARSET=utf8

如果不进行字符集编码的设置的话,会是MySQL默认的字符集编码(Latin1,不支持中文)

设置字符集编码

一种是在创建数据表的时候进行设置

  1. 在建表的SQL语句的末尾加
  2. 在用可视化建表  右键->设计表->选项里面设置

另一种是在my.ini中配置默认的编码 

character-set-server=utf8

但一般来说,都需要采用第一种方法进行设置,不然你的数据库拿到其他电脑上可能就不适用了,降低了通用性

修改数据表(ALTER)

修改表名(RENAME AS)

ALTER TABLE 旧的数据表名 RENAME AS 新的数据表名;

增加表的字段(ADD)

ALTER TABLE 数据表名 ADD 新的字段名 数据约束;

修改表的字段(MODIFY、CHANGE)

修改字段的约束(MODIFY)

ALTER TABLE 数据表名 MODIFY 字段名 新的数据约束;

可以看到,已经修改成功了 

既能修改字段的名字,也能修改字段的约束(CHANGE)

但是使用CHANGE 就需要在重命名的同时加上字段的约束

ALTER TABLE 数据表名 CHANGE 旧的字段名 新的字段名 数据约束;

可以看到,在重命名字段的同时,数据约束也修改了 

删除表的字段

ALTER TABLE 数据表名 DROP 字段名;

删除表(DROP)

DROP TABLE 数据表名;  或者   DROP TABLE IF EXITS 数据表名;

MySQL数据管理

外键(了解)

第一种方式

CREATE TABLE IF NOT EXISTS `grade` (
	`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
	`gradename` VARCHAR(20) NOT NULL COMMENT '年级姓名',
	PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4

CREATE TABLE IF NOT EXISTS `student` (
	`id` INT(3) NOT NULL AUTO_INCREMENT COMMENT '学员id',
	`password` INT(10) NOT NULL DEFAULT 123456 COMMENT '密码',
	`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
	`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',
	`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
	`birthday` DATETIME DEFAULT '2003-09-08 21:00:00' COMMENT '出生日期',
	`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
	`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY(`id`),
	KEY `FK_gradeid` (`gradeid`),
	CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4

第二种方式

CREATE TABLE IF NOT EXISTS `grade` (
	`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年级id',
	`gradename` VARCHAR(20) NOT NULL COMMENT '年级姓名',
	PRIMARY KEY(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4

CREATE TABLE IF NOT EXISTS `student` (
	`id` INT(3) NOT NULL AUTO_INCREMENT COMMENT '学员id',
	`password` INT(10) NOT NULL DEFAULT 123456 COMMENT '密码',
	`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
	`sex` VARCHAR(2) NOT NULL DEFAULT '男' COMMENT '性别',
	`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
	`birthday` DATETIME DEFAULT '2003-09-08 21:00:00' COMMENT '出生日期',
	`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
	`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
	PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4

ALTER TABLE `student` 
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`);
  • 删除有外键关系的表的时候,必须先删除引用别人的表student(从表),再删除被引用的表grade(主表)
  • 以上的操作都是物理外键(数据库级别的外键),不建议使用。(避免数据库太多造成困扰,这里了解即可)

最佳实践

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

DML语言

DML语言:数据操作语言

insert

update

delete

添加(INSERT INTO)

INSERT INTO 数据表名 (字段1,字段2,字段3,...) values ('值1','值2','值3',...);

如果不写字段名,它就会一一匹配

例如:

INSERT INTO 数据表名 values ('值'); 
-- 假设这个表只有两个字段,并且这个值是赋值给第二个字段的
-- 默认就会编译成
INSERT INTO 数据表名 (字段1,字段2) values ('值',null);
-- 这个时候会发现值赋值给第一个字段,如果不符合该字段的数据约束,就会报错,并且也不能满足我们的需求

因此,一般写插入语句的时候,一定要保证数据和字段一一对应

插入多行数据
INSERT INTO 数据表名 (字段名) VALUES ('值1'),('值2'),...;

区别好插入多个字段的值和插入多行数据(一个字段的多个数据)的区别

插入一个字段的数据
INSERT INTO `grade` (`gradename`) VALUES ('大三');

这里之所以gradeid也有值,是因为我们刚开始建表的时候给该字段添加了自增选项,并且非空

插入一整行数据
INSERT INTO `grade` (`gradeid`,`gradename`) VALUES (1,'大一');
INSERT INTO `grade` (`gradeid`,`gradename`) VALUES (2,'大二');

插入一个字段的多个数据
INSERT into `grade` (`gradename`) VALUES ('大四'),('大五'),('大六');

插入多个字段的多个数据
INSERT INTO `grade` (`gradeid`,`gradename`) VALUES (11,'一年级'),(12,'二年级'),('13','三年级');

注意事项
  • 字段和字段之间使用英文逗号隔开
  • 可以同时插入多条数据,VALUES后面的括号需要使用英文逗号隔开
    • INSERT INTO 数据表名 (字段名) VALUES ('值1'),('值2');
  • 字段名是可以省略的,但后面的值必须要一一对应
    • INSERT INTO `grade` VALUES (21,'四年级'),(22,'五年级'),(23,'六年级');

修改(UPDATE)

UPDATE 数据表名 SET 字段名='新的值' WHERE 条件判断; 
初始表格

修改指定条件的某一字段的数据
UPDATE `student` set `name`='lhj' WHERE id=1;

不指定条件的修改某一字段的数据
UPDATE `student` SET `name`='fjq';

指定条件的修改多个字段的值
UPDATE `student` SET `name`='lhj',`address`='shantou' WHERE id=1;

组合条件的修改字段的值
UPDATE `student` SET `name`='zhangsan' WHERE id<>1 AND sex='男';

操作符
操作符含义范围结果
=等于5 = 6false
<>或!=不等于5 <> 6 (5 != 6)true
>大于5 > 6false
<小于5 < 6true
>=大于等于5 >= 6false
<=小于等于5 <= 6true
BETWEEN...AND...在某个范围内例如判断1是否在[2, 5]之间false

AND

我和你 &&5>1 AND 1>2false
OR我或你  | |5>1 OR 1>2true

注意事项
  • 字段名:字段名最好带上``,避免关键字
  • 条件:筛选的条件,如果没有指定条件,就会修改该字段下所有的值
  • 值:是一个具体的值,也可以是一个变量
    • 例如:CURRENT_TIME
    • UPDATE `student` SET `birthday`=CURRENT_DATE WHERE id=2;

  • 多个设置的属性之间,使用英文逗号隔开
UPDATE 数据表名 SET 字段名1='新的值1',字段名2='新的值2',... WHERE 条件;

删除(DELETE FROM)

DELETE FROM 数据表名 WHERE 条件;
原先的表格

删除指定的数据
DELETE FROM `student` WHERE id = 1;

删除整张表的数据
DELETE FROM `student`;

TRUNCATE命令
TRUNCATE `student`;

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

使用delete删除数据后再进行添加数据,自增列的计数器并不会归零

使用truncate删除数据后再进行添加数据,自增列的计数器会归零

DELETE删除后重启数据库
  • INNODB 自增列会从1开始 (因为自增字段是存储在内存中的,断电即失,不过MySQL 8.0修复了这个问题,此时自增字段保存在redo log中,重启后不会重置)
  • MYISAM 自增列依旧从上一个自增量开始(因为自增字段存储在文件中,不会因为重启而丢失数据)

DQL查询数据(重点)(SELECT)

  • 所有的查询操作都用它  SELECT
  • 简单的查询,发杂的查询都能做
  • 数据库中最核心的语言

查询全部字段

SELECT * FROM 数据表名;

查询指定字段

查询单个字段

SELECT 字段名 FROM 数据表名;

查询多个字段

SELECT 字段名1,字段名2 FROM 数据表名;

可以看到,数据虽然查询出来了,但是表头还是我们定义的字段名

因此就有一个新的玩法:别名        给结果起一个名字(AS)

别名(AS)

可以给字段起别名,也可以给数据表起别名

SELECT 字段名1 AS 别名1,字段名2 AS 别名2 FROM 数据表名 AS 数据表的别名;

 

CONCAT(a , b)  —— 拼接字符串的函数

SELECT CONCAT('要拼接的字符串' , 字段名) AS 别名 FROM 数据表名;

去重(DISTINCT)

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

SELECT DISTINCT 字段名1 AS 别名1,字段名2 AS 别名2,... FROM 数据表名;

可以看到,虽然查询到了数据,但有很多重复的数据,但是我们不需要重复数据

因此,可以加上DISTINCT关键字

可以看到,重复数据只保留了一条

查询系统版本        ——        函数

SELECT VERSION();

用来计算        ——        表达式

SELECT 120*2-1 AS 计算结果;

查询自增的步长        ——        变量

SELECT @@auto_increment_increment;

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

SELECT 表达式 FROM 数据表;

WHERE条件子句

检索数据中符合条件的值

检索的条件由一个或多个表达式组成        结果返回的都是一个布尔值

逻辑运算符

运算符语法描述
and        &&a and b        a && b逻辑与,两个都为真,结果为真
or            | |a or b        a | | b逻辑或,其中一个为真,结果为真
not           !not a             ! a逻辑非,真为假,假为真


不指定条件的查询

查询成绩在45到60之间的学生学号以及分数

以上这三种方法运行出来的结果都是一样的

查询学号不等于1000的学生学号以及成绩

以上两种方式运行的结果都是一样的,要注意的是NOT 紧跟在WHERE的后面

查询学号不等于1000和1001的学生学号以及成绩

查询成绩在45到60之间且学号不等于1000的学生学号以及分数

模糊查询:比较运算符

运算符语法描述
IS NULLa is null如果操作符为NULL,结果为真
IS NOT NULLa is not null如果操作符为NOT NULL,结果为真
BETWEEN...AND...a between b and c如果a在b和c之间,结果为真
Likea like bSQL匹配,如果a匹配b,结果为真
Ina in (a1,a2,a3,...)如果a在a1,或者a2...其中的某一个值中,结果为真

LIKE 比较运算符

占位符
  • %表示0个到任意个字符
  • _表示1个字符
查询姓张的同学(%)

查询姓张的同学,且姓之后只有一个字(_)

查询名字中间有伟的同学

IN 比较运算符

IN( )         括号里面是具体的一个或多个值,不能使用占位符

查询学号为1000和1001的学生

查询在广东汕头的同学

IS NULL、IS NOT NULL

查询地址为空的同学(IS NULL 也是判定系统设置为NULL的数据)

查询地址不为空的同学(这种前提是设置了该字段可以为空并且该数据系统设置成NULL)

联表查询

分析需求,分析查询的字段来自那些表(连接查询)

确定使用哪种连接查询?(7种)

确定交叉点(这两个表当中有哪个字段是相同的)

例如:判断的条件:学生表中的 studentNo  =  成绩表中的 studentNo

前情提要:

student表

result表

subject表

grade表

查询参加了考试的同学(学号,姓名,科目编号,分数)

查询缺考的同学 (学号,姓名,科目编号,分数)

查询同学的相关信息(学号,姓名,科目编号,科目名称,分数)

查询学生的学号,姓名,年级名称

查询科目所属的年级(科目名称,年纪名称)

查询参加了高等数学-4考试的学生信息(学号,姓名,科目,分数)

操作描述
INNER JOIN交集,两边都有
LEFT JOIN即使右表中没有匹配,也会从左表中返回所有的值,只不过没有匹配的那一行返回的右表字段的值是NULL
RIGHT JOIN即使左表中没有匹配,也会从右表中返回所有的值,只不过没有匹配的那一行返回的右表字段的值是NULL

JOIN的七种连接icon-default.png?t=O83Ahttps://cloud.tencent.com/developer/article/1778572

需要注意的是相同的字段要定义好是哪个表(在SELECT 后面的,不是ON后面的)的,如果是内连接就无需在意,如果是左连接这个字段名就需要用左表.字段名,如果是右连接就需要右表.字段名,全连接和全不连接都需要注意,因为都包含左连接和右连接

内连接(INNER JOIN)

左连接(LEFT JOIN)

右连接(RIGHT JOIN)

左独有

右独有

全连接

全不连接

自连接

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

原先的表

这一张表其实是由两个表糅合在一起的,这个时候就要把他当作两张表在看

父类

categoryidcategoryName
2信息技术
3软件开发
5美术设计

子类

pidcategoryidcategoryName
34数据库
28办公信息
36web开发
57PS技术

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

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

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

排序

升序ASC        降序DESC
ORDER BY 字段名 ASC/DESC;

查询参加了高等数学-3考试的学生的学号,姓名,科目名称,分数,并且按照分数降序排列

升序

分页

缓解数据库压力,给人的体验更好

一般图片才会使用瀑布流,不过还是要根据实际情况

LIMIT 查询起始下标(当前页),页面的大小;

--第n页
LIMIT 页面的大小*(n-1),页面的大小;

数据总数/页面的大小 = 总页数

查询分数大于50的前五名的学生信息(学号,姓名,课程名称,分数)

子查询

WHERE 一个计算出来的值;

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

注意:子查询返回的只能是1个值,不能是多行值

查询高等数学-3的所有考试结果(学号,科目编号,成绩)降序排列

查询高等数学-3分数不少于50分的学生的学号和姓名

分组和过滤(GROUP BY 和 HAVING)

-- 查询不同课程的平均分,最低分,最高分,平均分大于60分
-- 核心:根据不同的课程分组
SELECT subjectname,AVG(studentresult),MAX(studentresult),MIN(studentresult)
FROM result AS r
INNER JOIN `subject` AS s
ON r.subjectno = s.subjectno
GROUP BY subjectname -- 通过什么字段来分组
HAVING AVG(studentresult) > 60;

MySQL函数

常用函数

-- 数学运算
SELECT ABS(-8); -- 绝对值 返回8
SELECT CEILING(9.4); -- 向上取整 返回10
SELECT FLOOR(9.4); -- 向下取整 返回9
SELECT RAND(); -- 返回一个0-1之间的随机数
SELECT SIGN(); -- 判断一个数的符号 如果输入0,返回0;输入正数返回1,输入负数返回-1

-- 字符串函数
SELECT CHAR_LENGTH('即使再小的帆也能远航'); -- 字符串长度 返回10
SELECT CONCAT('我','爱','JAVA'); -- 拼接字符串 返回我爱JAVA
SELECT INSERT('我爱编程helloworld',1,2,'超级热爱'); -- 插入替换,从第一个字符开始,替换2个字符,返回 超级热爱编程helloworld
SELECT LOWER('ShanTou'); -- 转成小写字母 返回shantou
SELECT UPPER('ShanTou'); -- 转成大写字母 返回SHANTOU
SELECT INSTR('ShanTou','h'); -- 返回第一次出现的子串的索引 返回2
SELECT REPLACE('坚持就能成功','坚持','努力'); -- 替换出现的指定字符串 返回努力就能成功
SELECT SUBSTRING('坚持就能成功',3,2); -- 返回指定的子字符串 返回 就能
SELECT REVERSE('坚持就能成功'); -- 反转 返回 功成能就持坚

-- 查询姓周的同学  并把张换成章
SELECT REPLACE(studentname,'张','章') FROM `student`
WHERE studentname like '张%'; 

-- 时间和日期函数
SELECT CURRENT_DATE(); -- 获取当前日期
SELECT CURDATE(); -- 获取当前日期
SELECT NOW(); -- 获取当前时间
SELECT LOCALTIME(); -- 本地时间
SELECT SYSDATE(); -- 系统时间

SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT HOUR(NOW());
SELECT MINUTE(NOW());
SELECT SECOND(NOW());

-- 系统
SELECT SYSTEM_USER();
SELECT USER();
SELECT VERSION();

聚合函数

函数名称描述
COUNT()计数
SUM()求和
AVG()平均值
MAX()最大值
MIN()最小值
......
-- 聚合函数
-- 都能够统计表中的数据(想查询一个表中有多少个记录,就使用这个count())
SELECT COUNT(borndate) FROM student; -- count(字段),会忽略所有的null值
SELECT COUNT(*) FROM student; -- count(*) 不会忽略null值  本质:计算行数,把所有的列都走一遍
SELECT COUNT(1) FROM student; -- count(1) 不会忽略null值  本质:计算行数,一行只走一个列


SELECT SUM(studentresult) AS 总和 FROM result;
SELECT AVG(studentresult) AS 平均分 FROM result;
SELECT MAX(studentresult) AS 最高分 FROM result;
SELECT MIN(studentresult) AS 最低分 FROM result;

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

什么是MD5

  • MD5又称信息摘要算法,主要增强算法复杂度和不可逆转
  • 具体的值的MD5是一样的

MD5破解网站的原理

  • 背后有一个字典,字典包含了MD5加密前后的值
  • 假设你输入一个加密后的值,且在字典中能找到对应的加密前的值,就能进行破解
  • 但是密码稍微复杂一点就破解不了
-- ======测试MD5 加密======

CREATE TABLE `testmd5` (
	id INT(10) NOT NULL,
	name VARCHAR(20) NOT NULL,
	pwd VARCHAR(50) NOT NULL,
	PRIMARY KEY(id)
)ENGINE=INNODB DEFAULT CHARSET=utf8mb4

-- 明文密码
INSERT INTO `testmd5` (id,name,pwd) VALUES (1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456');

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

-- 插入的时候加密
INSERT INTO `testmd5` (id,name,pwd) VALUES (4,'小明',MD5('123456'));

事务

什么是事务

要么都成功,要么都失败

----------------------

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

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

-----------------------

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

事务原则:

ACID原则(原子性、一致性、隔离性、持久性)  有可能产生脏读、幻读、不可重复读...

原子性(Atomicity)详解

原子性(Atomicity)的定义与重要性

原子性(Atomicity),作为事务处理的基本特性之一,确保了事务中的操作要么全部完成,要么全部不执行。在执行多步操作的事务中,如果任何一步失败,整个事务将被回滚到开始状态,就像这个事务从未被执行过一样。

事务原子性示例

在一个银行转账事务中,假设需要从账户A转移资金到账户B。

这个事务包含两个步骤:

  • 步骤1: 从账户A扣除相应金额
  • 步骤2: 向账户B添加相应金额。

原子性确保了这两个操作要么同时成功,要么同时失败。如果在扣除金额后,向账户B添加金额时发生错误,整个事务将被回滚,账户A的金额将被恢复。

一致性(Consistency)详解

一致性的具体含义

一致性在数据库事务管理中指的是事务将数据库从一个一致的状态转移到另一个一致的状态。这意味着事务执行的结果必须符合所有预定义的规则和约束,包括数据库的内部规则(如主键、外键约束、唯一性约束等)以及应用层面的业务规则。

一致性确保了数据的准确性和有效性,防止了数据冲突和逻辑错误。

一致性示例

在银行转账的场景中,假设初始时用户A和用户B分别用100美元,用户A需要向用户B转100美元。

这个操作涉及两个步骤:从用户A的账户扣除100美元,向用户B的账户增加100美元。

一致性确保了在整个事务过程中,两个账户的总金额保持不变。如果事务在任何步骤中失败,系统将回滚事务,确保账户金额的一致性不被破坏。

持久性(Durability)详解

持久性的定义和意义

持久性(Durability)指的是一旦事务被提交,它对数据库的修改应该是永久性的,即使发生系统崩溃或其他故障。

持久性确保了数据的可靠性和稳定性,是数据库管理系统(DBMS)的核心特性之一。对于任何关键业务来说,数据的持久性是不可或缺的,因为它保证了数据的安全性和一致性,即使在系统遇到故障时也能够保持数据不丢失。

隔离性(Isolation)

隔离性(Isolation)的定义

隔离性(Isolation)确保并发执行的事务是隔离的,即一个事务的执行不会被其他事务干扰

这个特性是通过事务隔离级别来实现的,不同的隔离级别能够解决不同的并发事务中的问题,但同时也会在性能和一致性之间做出权衡。

隔离所导致的一些问题

脏读:

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

不可重复读:

在一个事务内部读取表中某一行的数据,多次读取结果不同(这个不一定是错误,只不过某些场合不对)

虚读(幻读):

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

执行事务

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

-- 关闭事务
SET autocommit = 0;
-- 开启事务(默认)
SET autocommit = 1;

-- 手动处理事务
-- 第一步:关闭自动提交
SET autocommit = 0;

-- 事务开启
STRT TRANSACTION; -- 标记一个事务的开始,从这个之后的 SQL 都在同一个事务中

INSERT xxx;
INSERT xxx;

-- 提交:持久化  (成功就提交)
COMMIT;

-- 回滚:回到原来的样子  (失败就回滚)
ROLLBACK;

-- 事务结束
-- 最后一步:开启自动提交
SET autocommit = 1;

-- 设置一个事务的保存点
SAVEPOINT 保存点名;

-- 回滚到保存点
ROLLBACK TO SAVEPOINT 保存点名;

-- 撤销保存点
RELEASE SAVEPOINT 保存点名;

模拟转账

-- 模拟转账
-- 关闭自动提交
SET autocommit = 0;
-- 开启事务
START TRANSACTION;
-- 编写一组事务
UPDATE account SET money = money - 500 WHERE name = 'A';
UPDATE account SET money = money + 500 WHERE name = 'B';

-- 提交
COMMIT;

-- 回滚
ROLLBACK;

-- 开启自动提交
SET autocommit = 1;

首先,要关闭自动提交

-- 关闭自动提交
SET autocommit = 0;

当我们运行事务中的代码后(不执行提交)

这个时候不执行提交,而是执行回滚

但是若是执行力提交

再执行回滚,数据并不会恢复,因为执行了提交就已经吧数据持久化了

最后就是要记得恢复自动提交

-- 开启自动提交
SET autocommit = 1;

索引

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构

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

索引的分类

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

  • 主键索引(PRIMARY KEY)
    • 唯一的标识,主键不可重复,一张表只能有一个主键,但是可以由多个字段做一个主键
  • 唯一索引(UNIQUE KEY)
    • 避免重复的列出现,多个列都可以标识为唯一索引
  • 常规索引(KEY或者INDEX)
    • 默认的,可以用index、key关键字来设置
  • 全文索引(FULLTEXT)
    • 在特定的数据引擎下才有,以前只有MyISAM支持,现在其他有的也支持
    • 快速定位数据
    • 但是全文索引在数据量比较小的情况下是没有用的
添加primary key(主键索引)
alter table 表名 add primary key(列名);
添加unique(唯一索引)
alter table 表名 add unique(列名);
添加index(普通索引)
alter table 表名 add index 索引名 (列名);
添加fulltext(全文索引)
alter table 表名 add fulltext (列名);
添加多列索引
alter table 表名 add index 索引名 (列名1,列名2.......);
删除索引
使用 DROP INDEX 语句

语法格式

DROP INDEX 索引名 ON 表名;

语法说明如下:
<索引名>:要删除的索引名。
<表名>:指定该索引所在的表名。

使用 ALTER TABLE 语句

删除表中的主键

ALTER TABLE 表名 DROP PRIMARY KEY;

删除名称为 index_name 的索引

ALTER TABLE 表名 DROP INDEX 索引名;

删除外键

ALTER TABLE 表名 DROP FOREIGN KEY 索引名;

注意:如果删除的列是索引的组成部分,那么在删除该列时,也会将该列从索引中删除;如果组成索引的所有列都被删除,那么整个索引将被删除。

先设置money为全文索引,在设置name为唯一索引

ALTER TABLE `account` ADD UNIQUE `money` (`money`);
DROP INDEX `NAME` ON `account`;

ALTER TABLE `account` ADD FULLTEXT `NAME`(`name`);
DROP INDEX `NAME` ON `account`;

接着查看索引信息

-- 显示所有的索引信息
SHOW INDEX FROM `account`;

测试索引

插入100万条数据

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 NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT = 'app用户表'

-- 插入100万条数据
DELIMITER $$  -- 写函数之前必须要写,当作标志
CREATE FUNCTION mock_data()
RETURNS INT DETERMINISTIC
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),'232332@qq.com',CONCAT('18',FLOOR(RAND()*((999999999-100000000)+100000000))),FLOOR(RAND()*2),UUID(),FLOOR(RAND()*100));
		SET i = i + 1;
	END WHILE;
	RETURN i;
END;
SELECT mock_data();

分析没有索引和有索引的区别

SELECT * FROM app_user WHERE `name`='用户9999'; 
EXPLAIN SELECT * FROM app_user WHERE `name`='用户9999'; 

-- 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';

没加索引前

加了索引后

索引在小数据量的时候,用处不大;但是在大数据的时候,区别十分明显

索引原则

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

权限管理和备份

用户管理

Navicat 可视化管理

点击用户

点击新建用户

在常规处输入相关信息

在服务器权限处授予全部权限

最后点击保存即可

SQL命令操作

用户表:mysql下的user表

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

原先的user表

 创建用户

-- 创建用户  CREATE USER 用户名 IDENTIFIED BY '密码';
CREATE USER lhj IDENTIFIED BY '123456';

修改密码

-- 修改密码(修改当前用户密码)
SET PASSWORD = '123456';

-- 修改密码(修改指定用户密码)
SET PASSWORD FOR lhj = '123456';

用户重命名

-- 重命名  RENAME USER 旧名字 TO 新名字;
RENAME USER lhj TO lhj2;

用户授权

-- 用户授权
-- ALL PRIVILEGES 除了给别人授权,其他都能干
GRANT ALL PRIVILEGES ON *.* TO lhj2;

查询权限

-- 查询权限 SHOW GRANTS FOR 用户;
SHOW GRANTS FOR lhj2;
SHOW GRANTS FOR root@localhost;

撤销权限

-- 撤销权限 REVOKE 哪些权限 在哪个库撤销 给谁撤销
REVOKE ALL PRIVILEGES ON *.* FROM lhj2;

删除用户

-- 删除用户
DROP USER lhj2;

MySQL备份

为什么要备份?

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

MySQL数据库备份的方式

  • 直接拷贝物理文件
  • 在 Navicat 这种可视化工具中手动导出
    • 在想要导出的库或者是表上,右键,选择转储SQL文件
  • 使用命令行( win+r 输入 cmd )导出  mysqldump  命令行使用
    • # 导出一张表
      # mysqldump -h主机 -u用户名 -p密码 数据库名 数据表名 >物理磁盘位置/文件名
      mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
      
      # 导出多张表
      # mysqldump -h主机 -u用户名 -p密码 数据库名 数据表名1 数据表名2 >物理磁盘位置/文件名
      mysqldump -hlocalhost -uroot -p123456 school student result >D:/b.sql
      
      # 导出数据库
      # mysqldump -h主机 -u用户名 -p密码 数据库名 >物理磁盘位置/文件名
      mysqldump -hlocalhost -uroot -p123456 school >D:/c.sql

MySQL数据库导入的方式

# 第一步:登录MySQL mysql -u用户名 -p密码
mysql -uroot -p123456;
 
# 第二步:选定要导入的位置 use 数据库名;
use school;

# 第三步:导入sql文件 source 物理磁盘位置/文件名;
source D:/a.sql;

# 另外一种方法 mysql -u用户名 -p密码 数据库名 < 物理磁盘位置/文件名;
mysql -uroot -p123456 school < 物理磁盘位置/文件名;
C:\Users\罗弘杰>mysql -uroot -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 8.0.31 MySQL Community Server - GPL

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> use school;
Database changed
mysql> source D:/a.sql
Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected, 4 warnings (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

规范数据库设计

为什么需要设计

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

区别

糟糕的数据库设计:
  • 数据冗余,浪费空间
  • 数据库插入和删除都会麻烦,甚至会产生异常【屏蔽使用物理外键】
  • 程序的性能差

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

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

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

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

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

三大范式

为什么需要数据规范化

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

第一范式(1NF)

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


属性不可再分,即表中的每个列都不可以再进行拆分。

如下学生信息表(student):

id、name(姓名)、sex_code(性别代号)、sex_desc(性别描述)、contact(联系方式)

primary key(id)

如果在查询学生表时经常用到学生的电话号,则应该将联系方式(contact)这一列分为电话号(phone)和地址(address)两列,这样才符合第一范式。


 

第二范式(2NF)

前提:必须满足第一范式

每张表只描述一件事情

在满足1NF的前提下,表中不存在部分依赖,非主键列要完全依赖于主键。(主要是说在联合主键的情况下,非主键列不能只依赖于主键的一部分)

如下学生成绩表(score):

stu_id(学生id)、kc_id(课程id)、score(分数)、kc_name(课程名)

primary key(stu_id, kc_id)

表中主键为stu_id和kc_id组成的联合主键。满足1NF;非主键列score完全依赖于主键,stu_id和kc_id两个值才能决定score的值;而kc_name只依赖于kc_id,与stu_id没有依赖关系,它不完全依赖于主键,只依赖于主键的一部分,不符合2NF。

修改使表满足2NF后:

成绩表(score)   primary key(stu_id)

课程表(kc)   primary key(kc_id)

将原来的成绩表(score)拆分为成绩表(score)和课程表(kc),而且两个表都符合2NF。

第三范式(3NF)

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

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

在满足2NF的前提下,不存在传递依赖。(A -> B, B -> C, A->C)

如下学生信息表(student):

primary key(id)

表中sex_desc依赖于sex_code,而sex_code依赖于id(主键),从而推出sex_desc依赖于id(主键);sex_desc不直接依赖于主键,而是通过依赖于非主键列而依赖于主键,属于传递依赖,不符合3NF。

修改表使满足3NF后:

学生表(student)   primary key(id)

性别代码表(sexcode)   primary key(sex_code)

将原来的student表进行拆分后,两个表都满足3NF。

(规范数据库的设计)

规范性和性能的问题

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

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

JDBC

数据库驱动

我们的程序会通过数据库驱动,和数据库打交道

JDBC

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

这些规范的实现由具体的厂商去做

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

java.sql

javax.sql

还需要导入一个数据库驱动包 mysql-connector-java-版本.jar

第一个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、创建一个普通项目

2、导入数据库驱动

3、编写测试代码

package com.ling.lesson01;

import java.sql.*;

// 我的第一个JDBC程序
public class JdbcFirstDemo {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        // 1. 加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver"); // 固定写法,再在驱动

        // 2. 用户信息和url
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&&useSSL=true";
        String username = "root";
        String password = "123456";

        // 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("pwd=" + resultSet.getObject("PASSWORD"));
            System.out.println("email=" + resultSet.getObject("email"));
            System.out.println("birth=" + resultSet.getObject("birthday"));
            System.out.println("=============================");
        }
        // 6. 释放连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

步骤总结:

1、加载驱动

2、连接数据库 DriverManager

3、获得执行sql的对象 Statement

4、获得返回的结果集

5、释放连接

DriverManager

// 之前的写法  但这种相当于注册了两次
DriverManager registerDriver(new com.mysql.cj.jdbc.Driver());

// 现在的写法
Class.forName("com.mysql.cj.jdb.Driver");

URL

// 协议://主机地址:端口号/数据库名?参数1&参数2&参数3
// mysql端口号默认是3306
// oracl端口号默认是1521  jdbc:oracle:thin:@localhost:1521:sid
// 可以把jdbc:mysql想成http
String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

Connection

// connection代表数据库
// 数据库设置自动提交
connection.setAutoCommit();
// 事务提交
connection.commit();
// 事务回滚
connection.rollback();

Statement 

Statement 和 PrepareStatement 都是执行SQL的对象

// 执行所有的sql
statement.execute();

// 执行查询  返回ResultSet
statement.executeQuery();

// 执行更新、插入、删除  返回一个受影响的行数
statement.executeUpdate();

ResultSet

查询的结果集,封装了所有的查询结果

获得指定的数据类型

// 在不是到列的类型的时候使用
resultSet.getObject();

// 如果知道列的类型就使用指定的类型
resultSet.getString();
resultSet.getInt();
resultSet.geFloat();
resultSet.getDouble();

遍历(指针)

// 指针移动到最前面
resultSet.beforeFirst();

// 指针移动到最后面
resultSet.afterLast();

// 指针移动到写一个数据
resultSet.next();

// 移动到前一行
resultSet.previous();

// 移动到指定行
resultSet.absolute(row);

释放资源

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

statement对象

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

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

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

CRUD——create

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

Statement statement = connection.createstatement();
String sql = "insert into user(...) 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 user 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 user set name = '' where name = '' ";
int num = statement.executeUpdate(sql);
if(num > 0) {
    System.out.println("修改成功");
}

代码实现

1、提取工具类

package com.ling.lesson02.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 resourceAsStream = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(resourceAsStream);

            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            // 1. 驱动只用加载一次
            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    // 获取连接
    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) {
                throw new RuntimeException(e);
            }
        }
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

2、编写增删改的方法executeUpdate

package com.ling.lesson02.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestInsert {
    public static void main(String[] args) {

        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql = "INSERT INTO `users`(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (4,'lhj','123456','2479433253@qq,com','2003-09-08')";
            int i = st.executeUpdate(sql);
            if (i > 0) {
                System.out.println("插入成功");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}
package com.ling.lesson02.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestDelete {
    public static void main(String[] args) {

        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql = "DELETE FROM users where id = 1";
            int i = st.executeUpdate(sql);
            if (i > 0){
                System.out.println("删除成功");
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}
package com.ling.lesson02.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestUpdate {
    public static void main(String[] args) {

        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils.getConnection();
            st = conn.createStatement();
            String sql = "UPDATE users SET NAME = 'fjq' WHERE id = 4";
            int i = st.executeUpdate(sql);
            if (i > 0){
                System.out.println("修改成功");
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

3、查询executeQuery

package com.ling.lesson02.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TestSelect {
    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 users";
            rs = st.executeQuery(sql);
            while (rs.next()) {
                System.out.println("id=" + rs.getInt("id"));
                System.out.println("name=" + rs.getString("NAME"));
                System.out.println("password=" + rs.getString("PASSWORD"));
                System.out.println("email=" + rs.getString("email"));
                System.out.println("birthday=" + rs.getDate("birthday"));
                System.out.println("==========================");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils.release(conn,st,rs);
        }
    }
}

SQL注入的问题

SQL存在抖动,会被攻击导致数据泄露   SQL会被拼接    用到or

package com.ling.lesson02;

import com.ling.lesson02.utils.JdbcUtils1;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQL注入 {
    public static void main(String[] args) throws SQLException {

        // 正常登录
        //login("lhj","123456");

        // SQL注入
        login("'or'1=1","'or'1=1");
    }

    // 登录业务
    public static void login(String username,String password) {
        Connection conn = null;
        Statement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils1.getConnection();
            st = conn.createStatement();
            String sql = "SELECT * FROM users WHERE NAME = '" + username +"' AND PASSWORD = '" + password + "'";
            rs = st.executeQuery(sql);
            while (rs.next()) {
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("PASSWORD"));
                System.out.println("===============================");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils1.release(conn, st, rs);
        }
    }
}

PrepareStatement

PrepareStatement 可以防止SQL注入并且效率更高

1、新增

package com.ling.lesson03;

import com.ling.lesson02.utils.JdbcUtils1;

import java.sql.*;

public class TestInsert {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils1.getConnection();
            String sql = "insert into users(id,NAME,PASSWORD,email,birthday) values (?,?,?,?,?)";
            // 预编译
            st = conn.prepareStatement(sql);

            // 设置值
            st.setInt(1,5);
            st.setString(2,"hwd");
            st.setString(3,"123456");
            st.setString(4,"132213@qq.com");
            st.setDate(5,new Date(new java.util.Date().getTime()));

            // 对象执行sql
            int i = st.executeUpdate();
            if (i > 0) {
                System.out.println("插入成功");
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils1.release(conn,st,null);
        }
    }
}

2、删除

package com.ling.lesson03;

import com.ling.lesson02.utils.JdbcUtils1;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class TestDelete {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils1.getConnection();
            String sql = "delete from users where id = ?";
            st = conn.prepareStatement(sql);

            st.setInt(1,5);

            int i = st.executeUpdate();
            if (i > 0) {
                System.out.println("删除成功");
            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils1.release(conn,st,null);
        }
    }
}

3、更新

package com.ling.lesson03;

import com.ling.lesson02.utils.JdbcUtils1;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.IdentityHashMap;

public class TestUpdate {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;

        try {
            conn = JdbcUtils1.getConnection();
            String sql = "update users set NAME=? where id=?;";
            st = conn.prepareStatement(sql);

            st.setString(1,"zxy");
            st.setInt(2,5);

            int i = st.executeUpdate();
            if (i > 0) {
                System.out.println("修改成功");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils1.release(conn,st,null);
        }
    }
}

4、查询

package com.ling.lesson03;

import com.ling.lesson02.utils.JdbcUtils1;
import com.ling.lesson02.utils.JdbcUtils3;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestSelect {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils3.getConnection();
            String sql = "SELECT * FROM users WHERE PASSWORD = ?";
            st = conn.prepareStatement(sql);

            st.setString(1,"123456");

            rs = st.executeQuery();

            while (rs.next()) {
                System.out.println("name=" + rs.getString("NAME"));
                System.out.println("===================");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils3.release(conn,st,rs);
        }
    }
}

5、防止SQL注入

package com.ling.lesson03;

import com.ling.lesson02.utils.JdbcUtils1;

import java.sql.*;

public class SQL注入 {
    public static void main(String[] args) throws SQLException {

        // 正常登录
        //login("lhj","123456");

        // SQL注入
        login("'or'1=1","'or'1=1");
    }

    // 登录业务
    public static void login(String username,String password) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils1.getConnection();
            // PreparedStatement 防止SQL注入的本质:把传递进来的参数当作字符
            // 假设其中存在转义字符,就直接互虐,比如说引号(')会被直接转移
            String sql = "SELECT * FROM users WHERE NAME = ? AND PASSWORD = ?";
            st = conn.prepareStatement(sql);

            st.setString(1,username);
            st.setString(2,password);

            rs = st.executeQuery();
            while (rs.next()) {
                System.out.println(rs.getString("NAME"));
                System.out.println(rs.getString("PASSWORD"));
                System.out.println("===============================");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            JdbcUtils1.release(conn, st, rs);
        }
    }
}

使用IDEA连接数据库

 接下来就是输入相关信息,测试连接后应用

这个时候数据库默认是没有具体的数据库的,这个时候可以选择去添加

勾选想要添加的数据库进行应用 

双击表格即可查看表的内容,并可以看到对应的SQL信息

更新数据一定要点击提交,不然不会更新成功

如何编写SQL

事务

要么都成功,要么都失败

ACID原则

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

一致性:总数不变,最终一致性,符合逻辑

隔离性:多个事务互不干扰

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

隔离性的问题:

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

不可重复读:在同一个事务内重复读取表中的数据,表数据发生了改变,这个时候就不知道用原来的数据还是新的数据

幻读(虚读):在一个事务内读取到了别的事物插入的数据

代码实现

1、开启事务

conn.setAutoCommit(false);

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

3、可以在catch语句中定义回滚语句,但默认事务失败就会回滚

package com.ling.lesson04;

import com.ling.lesson02.utils.JdbcUtils3;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TestTransaction {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;

        try {
            conn = JdbcUtils3.getConnection();
            // 关闭数据库的自动提交,会自动开启事务
            conn.setAutoCommit(false);
            String sql1 = "UPDATE account set money = money - 100 WHERE name = 'A'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            int x = 1/0; // 报错,如果没有这个错误,这个事务就会正常执行->提交

            String sql2 = "UPDATE account set money = money + 100 WHERE name = 'B'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();

            // 业务完毕,提交事务
            conn.commit();
            System.out.println("操作成功");

        } catch (SQLException e) {
            try {
                conn.rollback(); // 如果失败则回滚事务
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }
            throw new RuntimeException(e);
        } finally {
            JdbcUtils3.release(conn, st, rs);
        }
    }
}

数据库连接池

数据库连接 --> 执行完毕 --> 释放    (连接到释放十分浪费系统资源)

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

最小连接数:按照需求,一般常用连接数是多少,最小连接数就是多少

最大连接数:业务最高承载上限

等待超时:如果超出就报异常

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

开源数据源实现

DBCP

C3P0

Druid:阿里巴巴

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

DBCP

需要用到的 jar 包

commons-dbcp2-2.12.0.jar

commons-pool2-2.12.0.jar

commons-logging-1.3.4.jar

dbcp-config.properties

#????
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true
username=root
password=123456

#<!-- ????? -->
initialSize=10

#??????
maxActive=50

#<!-- ?????? -->
maxIdle=20

#<!-- ?????? -->
minIdle=5

#<!-- ???????????? 6000??/1000??60? -->
maxWait=60000
#JDBC?????????????????????????????=property;?
#???"user" ? "password" ????????????????????????
connectionProperties=useUnicode=true;characterEncoding=UTF8

#??????????????????auto-commit????
defaultAutoCommit=true

#driver default ????????????????read-only????
#???????????setReadOnly?????????????????????????Informix?
defaultReadOnly=

#driver default ??????????????????TransactionIsolation??
#??????????????javadoc??NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED
package com.ling.lesson05.utils;

import org.apache.commons.dbcp2.BasicDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils_DBCP {

    private static DataSource dataSource = null;

    static {
        try {
            InputStream resourceAsStream = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcp-config.properties");
            Properties properties = new Properties();
            properties.load(resourceAsStream);

            // 创建数据源  工厂模式 --> 创建对象
            dataSource = BasicDataSourceFactory.createDataSource(properties);

        } catch (IOException | SQLException e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void release(Connection conn, Statement st, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
 
C3P0

需要导入的 jar 包

c3p0-0.9.5.5.jar

mchange-commons-java-0.2.19.jar

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!--
    c3p0的缺省(默认)配置
    如果在代码中"ComboPooledDataSource ds=new ComboPooledDataSource();"这样写就表示使用的是c3p0的缺省(默认)-->
    <default-config>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true&amp;serverTimezone=UTC</property>
        <property name="user">root</property>
        <property name="password">123456</property>

        <property name="acquiredIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </default-config>
</c3p0-config>
package com.ling.lesson05.utils;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcUtils_C3P0 {
    private static ComboPooledDataSource dataSource = null;

    static {

        dataSource = new ComboPooledDataSource();

    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void release(Connection conn, Statement st, ResultSet rs) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (st != null) {
            try {
                st.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

结论

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2222870.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTML5_标签_各类表格的实现

目录 1. 表格标签 1.1 表格的主要作用 1.2 表格的基本语法 1.3 表头单元格标签 1.4 表格属性 案例分析 先制作表格的结构. 后书写表格属性. 代码示例: 1.5 表格结构标签 1.6 合并单元格 合并单元格方式&#xff1a; 目标单元格&#xff1a;(写合并代码) 合并单元…

蓝桥杯——搜索

搜索 DFS基础回溯 回溯法简介&#xff1a; 回溯法一般使用DFS&#xff08;深度优先搜索&#xff09;实现&#xff0c;DFS是一种遍历或搜索图、树或图像等数据结构的算法&#xff0c;当然这个图、树未必要存储下来&#xff08;隐式处理就是回溯法&#xff09;&#xff0c;常见…

shell脚本语法详解

目录 shell语法基础 指定shell解析器 注释 运行 变量 定义变量 引用变量 清除变量值 从键盘获取值 输入单值 添加输入提示语 读取多值 ​编辑 定义只读变量 环境变量 设置环境变量与查看环境变量 特殊变量 三种引号的作用与区别 小括号与大括号 参数传递 位…

【HuggingFace 如何上传数据集 (2) 】国内网络-稳定上传图片、文本等各种格式的数据

【HuggingFace 下载】diffusers 中的特定模型下载&#xff0c;access token 使用方法总结【HuggingFace 下载中断】Git LFS 如何下载指定文件、单个文件夹&#xff1f;【HuggingFace 如何上传数据集】快速上传图片、文本等各种格式的数据 上文的方法因为是 https 协议&#xf…

CORS预检请求配置流程图 srpingboot和uniapp

首先要会判断预检请求 还是简单请求 简单请求 预检请求 #mermaid-svg-1R9nYRa7P9Pll4AK {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-1R9nYRa7P9Pll4AK .error-icon{fill:#552222;}#mermaid-svg-1R9nYRa7P9Pll4…

JAVA Maven 的安装与配置

一、下载地址 官方网站&#xff1a;Maven – Download Apache Maven 我这里是3.8.6版本 二、安装步骤 maven安装之前要先安装jdk&#xff0c;请确保你的系统已经安装了jdk环境。 1.将下载好的 Maven 进行解压 apache-maven-3.6.8-bin.zip 2.配置本地仓库:修改 conf/settin…

HDU RSA

翻译成中文后&#xff1a; 思路&#xff1a;由题易得&#xff0c;d * e y * f ( n ) 1 ,且gcd ( e , f ( n ) ) 1,所以用扩展欧几里得求出 d &#xff0c;但要保证 d 是非负的&#xff0c;最有用快速幂求出每个字符即可。 #include<bits/stdc.h> using namespace std;…

【Web前端概述】

HTML 是用来描述网页的一种语言&#xff0c;全称是 Hyper-Text Markup Language&#xff0c;即超文本标记语言。我们浏览网页时看到的文字、按钮、图片、视频等元素&#xff0c;它们都是通过 HTML 书写并通过浏览器来呈现的。 一、HTML简史 1991年10月&#xff1a;一个非正式…

第 6 章 Kafka-Eagle 监控 和 Kafka-Kraft 模式

Kafka-Eagle 框架可以监控 Kafka 集群的整体运行情况&#xff0c;在生产环境中经常使用。 6.1 MySQL 环境准备 Kafka-Eagle 的安装依赖于 MySQL &#xff0c; MySQL 主要用来存储可视化展示的数据。如果集 群中之前安装过 MySQL 可以跨过该步。 6.2 Kafka 环境准备 …

ELK日志分析系统部署

ELK日志分析系统 ELK指的是ElasticsearchLogstashKibana这种架构的缩写。 ELK是一种日志分析平台&#xff0c;在很早之前我们经常使用Shell三剑客&#xff08;一般泛指grep、sed、awk&#xff09;来进行日志分析&#xff0c;这种方式虽然也可以应对多种场景&#xff0c;但是当…

多线程初阶(七):单例模式指令重排序

目录 1. 单例模式 1.1 饿汉模式 1.2 懒汉模式 2. 懒汉模式下的问题 2.1 线程安全问题 2.2 如何解决 --- 加锁 2.3 加锁引入的新问题 --- 性能问题 2.4 指令重排序问题 2.4.1 指令重排序 2.4.2 指令重排序引发的问题 1. 单例模式 单例模式, 是设计模式中最典型的一种模…

CTFHUB技能树之SQL——MySQL结构

开启靶场&#xff0c;打开链接&#xff1a; 先判断一下是哪种类型的SQL注入&#xff1a; 1 and 11# 正常回显 1 and 12# 回显错误&#xff0c;说明是整数型注入 判断一下字段数&#xff1a; 1 order by 2# 正常回显 1 order by 3# 回显错误&#xff0c;说明字段数是2列 知道…

未来医疗:大语言模型如何改变临床实践、研究和教育|文献精析·24-10-23

小罗碎碎念 这篇文章探讨了大型语言模型在医学领域的潜在应用和挑战&#xff0c;并讨论了它们在临床实践、医学研究和医学教育中的未来发展。 姓名单位名称&#xff08;中文&#xff09;Jan Clusmann德国德累斯顿工业大学埃尔朗根弗雷斯尼乌斯中心数字化健康研究所Jakob Nikola…

html 轮播图效果

轮播效果&#xff1a; 1、鼠标没有移入到banner,自动轮播 2、鼠标移入&#xff1a;取消自动轮播、移除开始自动轮播 3、点击指示点开始轮播到对应位置 4、点击前一个后一个按钮&#xff0c;轮播到上一个下一个图片 注意 最后一个图片无缝滚动&#xff0c;就是先克隆第一个图片…

动态量化:大模型在端侧CPU快速推理方案

作为一款高性能的推理引擎框架&#xff0c;MNN高度关注Transformer模型在移动端的部署并持续探索优化大模型在端侧的推理方案。本文介绍权重量化的模型在MNN CPU后端的推理方案&#xff1a;动态量化。动态量化指在运行时对浮点型feature map数据进行8bit量化&#xff0c;然后与…

(gersemi) CMake 格式化工具

文章目录 &#x1f9ee;介绍&#x1f9ee;安装&#x1f9ee;使用&#x1f5f3;️模式 modes&#x1f5f3;️样式配置 config ⭐END&#x1f31f;help&#x1f31f;交流方式 &#x1f9ee;介绍 BlankSpruce/gersemi: A formatter to make your CMake code the real treasure A f…

Leetcode 最长公共前缀

java solution class Solution {public String longestCommonPrefix(String[] strs) {if(strs null || strs.length 0) {return "";}//用第一个字符串作为模板,利用indexOf()方法匹配,由右至左逐渐缩短第一个字符串的长度String prefix strs[0];for(int i 1; i …

【Java】反射概述与详解

目录 引言 一、概述 二、获取Class对象 三、反射获取构造方法 代码示例&#xff1a; 四、反射获取成员变量 代码示例&#xff1a; 五、反射获取成员方法 代码示例&#xff1a; 结语 引言 Java中的反射&#xff08;Reflection&#xff09;是一种强大的机制&#…

热门的四款PDF合并工具大比拼!!!

在现代的数字化办公环境中&#xff0c;PDF文件已经成为了一种重要的文件格式&#xff0c;用于保存和共享各种类型的文档。然而&#xff0c;有时候我们需要将多个PDF文件合并成一个文件&#xff0c;这时候就离不开好用的PDF合并工具了。选择一个好的PDF合并工具是一个长期的投资…

Python基于OpenCV的实时疲劳检测

2.检测方法 1&#xff09;方法 与用于计算眨眼的传统图像处理方法不同&#xff0c;该方法通常涉及以下几种组合&#xff1a; 1、眼睛定位。 2、阈值找到眼睛的白色。 3、确定眼睛的“白色”区域是否消失了一段时间&#xff08;表示眨眼&#xff09;。 相反&#xff0c;眼睛长…