数据库(DB,database)
概念:数据仓库,安装在操作系统上的一款软件
作用:存储管理数据
分类:
DBMS(数据库管理系统):
下载安装MySQL数据库
下载安装数据库可视化工具Navicat
连接数据库(命令行):
数据库一些命令:
--注:每个sql语句结束都要用分号结尾 flush privilege; --刷新权限 show databases; --查看所有数据库 use 数据库名; --使用数据库 Database changed show tables; --查看数据库中所有的表 describe student; --查看表的信息 create database test_db; --创建数据库
操作数据库》操作数据库中的表》操作表中的信息
操作数据库:
操作数据库:
CREATE DATABASE [if not exists] shcool;
删除数据库:
drop database [if exists] lpjsql;
使用数据库:
use db_yq;
查看数据库:
show DATABASES;
操作数据库表:
数据库列的类型:
数值:
tinyint --十分小的整数|1个字节 smallint --较小的整数|2个字节 mediumint --中等大小的整数|3个字节 int --标准的整数|4个字节|常用 bigint --较大的整数|8个字节 float --单精度浮点数|4个字节 double --多精度浮点数|8个字节 decimal --字符串形式的浮点数|用于金融计算
字符串:
char --固定大小的字符串|0~255 varchar --可变长字符串|0~65535|常用 tinytext --微型文本|0~2^8-1 text --文本串|0~2^16-1|保存大文本
时间和日期:
date --YYYY-MM-DD|日期 time --HH:mm:ss|时间 datetime --YYYY-MM-DD HH:mm:ss|最常用的时间格式 timestamp --时间戳|1970.1.1到现在的毫秒数|较为常用 year --年份
null:
--没有值,未知,注意不要使用null进行运算,因为结果一定为null
数据库的字段属性(重点):
拓展:做项目时,每个表设计时都应该具有的五个字段:
注:在数据库中int的长度并不影响数据的存储精度,长度只是和显示有关
创建数据库表:
create table if not exists ‘studnet’ ( `id` int(4) not null auto_increment COMMENT '学号', `name` VARCHAR(20) not NULL DEFAULT '匿名' COMMENT '姓名', `psd` VARCHAR(20) not NULL DEFAULT '123456' COMMENT '密码', `sex` VARCHAR(2) not NULL DEFAULT '男' COMMENT '性别', `birthda` datetime DEFAULT null COMMENT '出生日期', `address` VARCHAR(100) DEFAULT null COMMENT '家庭住址', `email` VARCHAR(18) DEFAULT null COMMENT '邮箱', PRIMARY key(`id`) ); show create table studnet; --查看表的创建语句 desc studnet;--查看表的结构 --注:use 数据库之后,相关操作比如创建表是在该数据库下创建
数据表的类型:
数据引擎:
MyISAM | InnoDB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间大小 | 较小 | 较大,约为倍 |
常规使用操作:
物理存储位置:所有数据库文件都存在data目录下,本质上还是文件存储
MySQL引擎在物理上文件的区别而:
.MySQL(server)创建并管理的数据库文件:
.frm文件:存储数据表的框架结构,文件名与表名相同,每个表对应一个同名frm文件,与操作系统和存储引擎无关,即不管MySQL运行在何种操作系统上,使用何种存储引擎,都有这个文件。
除了必有的.frm文件,根据MySQL所使用的存储引擎的不同(MySQL常用的两个存储引擎是MyISAM和InnoDB),存储引擎会创建各自不同的数据库文件。
MyISAM数据库表文件:
InnoDB数据库文件(即InnoDB文件集,ib-file set):
数据库表的字符集编码:不设置的话会使用默认的编码
修改删除表:
修改表:
ALTER table studnet RENAME as student --修改表名 --增加表的字段 ALTER TABLE test1 add age int(10) not null COMMENT '年龄' --修改约束和字段类型,不能重命名 ALTER TABLE test1 MODIFY age VARCHAR(11); --不能单独修改字段类型和约束,但是可以在重命名时设置字段类型约束 ALTER TABLE test1 CHANGE age age1 int(2); --删除表的字段 ALTER TABLE test1 drop age;
删除表:
drop table if exists test1;
注:所有的删除或者创建操作尽量加上判断条件
外键(了解):数据库中直接设立外键都是数据库级别的外键,不建议使用(避免数据库过多造成困扰)。
DML语言(掌握):
insert:
--方法一:直接插入一整条记录 insert into 表名 values(全部列值,且一一对应); --方法二:对应列插入值 insert into 表名(字段1,字段2...) values(字段值1,字段值2,...); --一次性插入多个记录 INSERT into 表名(字段1,字段2...) VALUES (字段值1,字段值2,...),(字段值1,字段值2,...),...;
update:
update 表名 set 字段名=字段值[,字段名=字段值,...] [where ...] --注1:如果没有条件限定,会直接修改全部记录的对应字段值 --注2:字段值不仅可以是常量,也可以是变量,比如常用的时间函数
delete:
delete from 表名;--删除整个表所有数据 delete from 表名 where ...;--删除指定数据 --补充 --完全清空一个数据库表,表的结构和索引约束不会变 truncate table 表名; --两种方式的区别 --相同点:都能删除数据且不会删除表 --不同点: --truncate:自增会归零 --delete:不影响自增 --拓展:delete 删除数据时,如果重启数据库,那么 --InnoDB:自增列会从1开始(存在内存中的,断电即失) --MySAM:继续从上一个自增量开始(存在文件中的,不会丢失)
DQL语言(查询数据):
别名:字段名 as 新名字;表名 as 新名字;或者直接:字段名 新名字;表名 新名字;
拼接字符串:Concat(a,b,c,...)
SELECT CONCAT('名字:',number,'寝室') as '寝室号' , CONCAT('楼:',building_name) as '所属楼层' from room;
去重:distinct(将查询中的重复结果只显示一条)
SELECT DISTINCT room_id FROM student;
特殊作用:
SELECT VERSION();--查询版本号 SELECT 123*223;--查询计算结果
注:数据库中的表达式:文本值,列,null,函数,计算表达式,系统变量,而
select 表达式 from 表
where条件语句:
常用运算符:
逻辑运算符:
运算符 | 含义 |
---|---|
AND 或者 && | 逻辑与,含义为“并且”。当所有操作数均为非零值且不为 null 时,返回值为 1;当一个或多个操作数为 0 时,返回值为 0;其余情况返回值为 null |
OR 或者 || | 逻辑或,含义为“或者”。当所有操作数均不为 null 且任意一个操作数为非零时,返回值为 1,否则为 0;当有操作数为 null,且存在另一个操作数为非零时,返回值为 1,否则为 null;当所有操作数均为 null 时,返回值为 null |
NOT 或者 ! | 逻辑非,含义为“取反”。当操作数为 0 时,返回值为 1;当操作数为非零时,返回值为 0;当操作数为 null 时,返回值为 null |
比较运算符:
运 算 符 | 含 义 |
---|---|
= | 等于 |
<=> | 安全等于,可以比较 null |
<> 或 != | 不等于 |
>= | 大于等于 |
<= | 小于等于 |
> | 大于 |
< | 小于 |
算术运算符:
运 算 符 | 含 义 |
---|---|
+ | 加法运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算,返回商 |
% | 求余运算,返回余数 |
模糊查询:
运算符 | 含义 |
---|---|
IS NULL | 判断一个值是否为 null |
IS NOT NULL | 判断一个值是否不为 null |
BETWEEN AND | 在什么和什么之间 |
LIKE | 匹配 |
in | a in (a1,a2,a3,...),如果a在a1,a2,a3之间存在,那么为真 |
注1:like与%(0~任意个字符)和_(一个字符)结合使用,且不一定要是字符类型才可以使用,数字类型也可以加上引号使用
select id from student where id like '%2%';
注2:in()必须指定的是确定的值,使用%或者_不行,确定值的表达式也可以
select id from student where id in (7,8,9,10,1+11);
联表查询:
两种连接表的查询:
联表查询:
inner join:内连接,特点是查询出来的结果是两个表都有的部分
--如a表有1,2,3,4,b表有2,3,4,5,那么查询的结果包含2,3,4 SELECT s.room_id,r.id,s.name,r.building_name from student s INNER JOIN room r on s.room_id=r.id;
left join:
左连接:
--如a表有1,2,3,4,b表有2,3,4,5,那么查询的结果包含1,2,3,4 SELECT s.room_id,r.id,s.name,r.building_name from student s LEFT JOIN room r on s.room_id=r.id;
左外连接:
--如a表有1,2,3,4,b表有2,3,4,5,那么查询的结果包含1 SELECT s.room_id,r.id,s.name,r.building_name from student s LEFT JOIN room r on s.room_id=r.id where r.building_name is null;
right join:
右连接:
--如a表有1,2,3,4,b表有2,3,4,5,那么查询的结果包含2,3,4,5 SELECT s.room_id,r.id,s.name,r.building_name from student s RIGHT JOIN room r on s.room_id=r.id
右外连接:
--如a表有1,2,3,4,b表有2,3,4,5,那么查询的结果包含5 SELECT s.room_id,r.id,s.name,r.building_name from student s RIGHT JOIN room r on s.room_id=r.id where s.room_id is null;
全连接(mysql不支持全连接)
三个及以上的多表查询:
select r.*,s.`寝室人数`,e.* from room r left join (SELECT count(*) as '寝室人数',room_id as id from student GROUP BY room_id) as s on r.id=s.id RIGHT JOIN `repair` e on r.id=e.room_id --注:直接先两表查询,然后接着两表查询的结果后面再连接表
联表查询+子查询;
select r.*,s.`寝室人数` from room r left join (SELECT count(*) as '寝室人数',room_id as id from student GROUP BY room_id) as s on r.id=s.id --注:在s.`寝室人数`处使用字符时应该使用`而不是引号
自连接(了解):将一张表看成两张表进行连接查询
分页和排序:
order by(排序):
desc(降序):
order by 字段 DESC
asc(升序):
order by 字段 ASC
limit(分页):
LIMIT 数据起始位置,页面数量
子查询:
select room.id,`repair`.`describe`,student.`name` from student,room,`repair` WHERE student.room_id=(SELECT id FROM room WHERE number=2624) and `repair`.room_id=(SELECT id FROM room WHERE number=2624) and room.number=2624
分组和过滤(当分组后还有条件时,可以使用having):
select room_id FROM student GROUP BY room_id having COUNT(*) = 2
注:(select ...)可以当做一个表,可以跟在from后面,也可以跟在连接查询后面,同时在查询的时候新生成的表都要设置别名。
参考网站:https://www.jb51.net/article/226393.htm
常用函数:
length(str)
:获取参数值的字节个数;
对于utf8
字符集来说,一个英文占1个字节;一个中文占3个字节;
对于gbk
字符集来说,一个英文占1个字节;一个中文占2个字节;
concat(str1,str2,…)
:拼接字符串;
upper(str)
:将字符中的所有字母变为大写;
lower(str)
:将字符中所有字母变为小写;
instr(str,要查找的子串)
:返回子串第一次出现的索引,如果找不到,返回0; 当查找的子串存在于字符串中:返回该子串在字符串中【第一次】出现的索引。当查找的子串不在字符串中:返回0。
trim(str)
:去掉字符串前后的空格; 该函数只能去掉字符串前后的空格,不能去掉字符串中间的空格。
lpad(str,len,填充字符)
:用指定的字符,实现对字符串左填充至指定长度;
rpad(str,len,填充字符)
:用指定的字符,实现对字符串右填充至指定长度
replace(str,子串,另一个字符串)
:将字符串str中的字串,替换为另一个字符串;
round(x,[保留的位数])
:四舍五入
ceil(x)
:向上取整
floor(x)
:向下取整
mod(被除数,除数)
:取余
now()
:返回系统当前的日期和时间;
curdate()
:只返回系统当前的日期,不包含时间;
curtime()
:只返回系统当前的时间,不包含日期;
获取日期和时间中年、月、日、时、分、秒;
获取年份:year();
获取月份:month();
获取日:day();
获取小时:hour();
获取分钟:minute();
获取秒数:second();
weekofyear()
:获取当前时刻所属的周数;
quarter()
:获取当前时刻所属的季度;
聚合函数:
注:
sum()函数和avg()函数对于字符串类型、日期/时间类型的计算都没有太大意义。因此,sum()函数和avg()函数,我们只用来对小数类型和整型进行求和
max()和min()中传入的是"整型/小数类型",计算的是数值的最大值
和最小值
。max()和min()中传入的是"日期类型",max()计算的最大值是离我们最近的那个日期
,min()计算的最小值是离我们最远的那个日期
,这个可以记一下。max()和min()中传入的是字符串类型
,max()计算的最大值是按照英文字母顺序显示的,min()计算的最小值也是按照英文字母顺序显示的,意义不太大。
当某个字段列中没有null值,则"count(列字段)=count()。"
当某个字段列中有null值,则"count(列字段)<count()。"
因此,假如你想统计的是整张表的行数,请用count(*)。
另可参考:https://blog.csdn.net/qq_41711758/article/details/116258290
拓展(MD5加密):
--数据库中使用MD5函数加密 INSERT into `repair` (id,`describe`,room_id) VALUES (15,md5('2624'),2)
什么是事务;
经典例子:
转账:
操作: 张三和李四各自的账号都是1000元;张三向李四转账100元
组成单元: 张三钱-100, 李四钱+100
操作成功: 张三钱900,李四钱1100
操作失败: 张三钱1000,李四钱1000
不可能发生: 张三钱900,李四钱1000;或者 战三钱1000,李四钱1100
事务特性:
数据库实现事务:
mysql是默认开启事务自动提交的
set autocommit =0; --关闭事务 set autocommit =1; --开启事务,默认
手动实现事务步骤:
--第一步:关闭事务 set autocommit =0; --第二步:开始一个事务 START TRANSACTION; --标记一个事务的开始,这个之后的sql语句都算一个事务 --第三步:sql语句执行 --第四步:提交或者回滚 commit --提交:持久化,事务成功 ROLLBACK --回滚:回到之前的状态,一旦被提交就持久化了无法回滚 --第五步:事务结束 set autocommit =1; --开启事务提交 --了解: SAVEPOINT 保存点名 --设置一个事务保存点 ROLLBACK to SAVEPOINT 保存点名 --回滚到保存点名 RELEASE SAVEPOINT 保存点名 --撤销保存点,一个事务可以有多个保存点
定义:索引是帮助mysql高效获取数据的一种数据结构
分类:
使用:
在创建表的时候增加索引
创建完毕后,增加索引:
ALTER TABLE 表名 add 索引类型 索引名 (列名1,列名2,列名3,...)
--查看对应表的索引 show index from student --增加一个全文索引 ALTER TABLE student add FULLTEXT index `student_name` (`name`) --EXPLAIN:分析sql执行的状况 EXPLAIN SELECT * FROM student --非全文索引
create 索引类型 索引名 on 表 (列名)
CREATE UNIQUE INDEX `student_name` on student (name)
删除索引:DROP INDEX index_name ON table_name
drop index `student_name` on student
索引原则:
索引的数据结构和原理:
参考链接:http://blog.codinglabs.org/articles/theory-of-mysql-index.html
mysql优化:参考链接:参考链接;https://blog.csdn.net/jiadajing267/article/details/81269067
备份:
方式:
直接拷贝物理文件(data)
直接在可视化工具里面导出导入
使用命令行导出:在Bin目录下
--导出 --mysqldump -h主机 -u用户名 -p密码 数据库 [表1 表2 表3] >位置 mysqldump -hlocalhost -uroot -p18227022334a mysql user >D:/mysql_user.sql --导入 --登录的情况下,切换到对应数据库 --source 文件 source D:/mysql_user.sql --未登录的情况下 --mysql -u用户名 -p密码 库名 [表名]< 文件 mysql -uroot -p18227022334a mysql user< D:/mysql_user.sql
用户管理:
navicat操作:
sql命令操作:
用户表:mysql数据库下的user表
--创建用户: CREATE user 用户名 IDENTIFIED by 密码 --修改密码 ALTER USER 用户名@Host IDENTIFIED WITH mysql_native_password BY 密码 --用户重命名 RENAME user 用户名@Host to 新用户名@新Host --用户授权 grant all privileges on *.* to 用户名@Host with grant option; --查询权限 --撤销权限 --删除用户 DROP user 用户名@Host
三大范式:
规范性和性能问题:
阿里内部规定关联查询的表表的超过三张
导入数据库驱动
jdbc:Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口应用程序接口,提供了诸如查询和更新数据库中数据的方法,我们通常说的JDBC是面向关系型数据库的。
操作数据库步骤:
加载驱动:
Class.forName("com.mysql.jdbc.cj.Driver");
用户信息和密码:
String url="jdbc.url=jdbc:mysql://localhost:3306/dormitory_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"; String username="root"; String password="18227022334a";
连接数据库:
Connection conn= DriverManager.getConnection(url,username,password);
创建执行sql语句的Statement对象:
Statement statement=conn.createStatement();
执行sql语句:
String sql="SELECT * from room;"; ResultSet resultSet = statement.executeQuery(sql); //遍历结果集获得数据 while (resultSet.next()){ System.out.println(resultSet.getObject("id")); System.out.println(resultSet.getObject("number")); System.out.println(resultSet.getObject("building_name")); System.out.println(resultSet.getObject("max_capacity")); }
释放连接:
resultSet.close(); statement.close(); conn.close();
连接数据库各对象:
DriverManager:
Class.forName("com.mysql.jdbc.cj.Driver"); //加载数据库驱动 DriverManager.getConnection(url,username,password);//获得一个数据库的连接对象 //url成分分析 // jdbc:mysql://主机名:端口号/数据库名?参数
connection:
//相当于数据库 connection.commit();//事务提交 connection.rollback();//事务回滚 connection.setAutoCommit();//设置自事务动提交 connection.createStatement();//创建一个执行sql语句的
Statement:
statement.executeQuery(sql);//执行查询语句,返回结果集 statement.execute(sql);//执行任何语句 statement.executeUpdate(sql);//执行更新,插入,删除语句,返回受影响的行数
resulSet:
//遍历结果集 resultSet.next();//光标移动到下一行,注:光标一开始是在第一行前面 //获得数据 resultSet.getObject();//不知道类型情况下使用 resultSet.getXXX();//XXX为基本数据类型,根据指定的数据类型获得数据
注:在最后都应该释放资源,释放的原则遵循:假如创建时顺序为abc,那么释放是cba
Statement对象存在的问题:sql注入问题且效率低
//比如:模拟一个用户登录的场景 //假设存在一个login(username,password) //由于使用statement执行sql语句时,传入了参数,则需要使用字符串的拼接 String sql="select * from student where name ='"+name+"' and password = '"+"';"; //当用户非法传入进行字符串的拼接时,就会导致数据库的泄露,比如 login("' or '1=1'","' or '1=1'"); /*此时会查询出数据库student表所有信息,因为参数传进来进行拼接后成为 select * from student where name ="" or '1=1' and password="" or '1=1'; */
使用PreStatement对象:
public int execUpdate(String sql, Object[] parms) { int count = 0; try { this.getConn(); ps = conn.prepareStatement(sql); if (parms != null) { for (int i = 0; i < parms.length; i++) { ps.setObject(i + 1, parms[i]); } } count = ps.executeUpdate(); return count; } catch (SQLException e) { e.printStackTrace(); } finally { //关闭数据库连接 this.closeConn(conn, resultSet, ps); } return count; }
注:PreparedStatement 防止 SQL 注入的原理就是把用户非法输入的单引号进行转义,最终传入参数作为一个整体执行,从而防止 SQL 注入,而 Statement 对象不会进行此操作。
idea操作数据库
jdbc操作事务:
1、获得connection对象
2、设置conn.setAutoCommit(false);
3、只有执行conn.commit();才会一起提交,否则不会一起提交 conn.rollback(); 回滚方法
public void test(){ try { this.getConn(); String sql1="update user set money=money-500 where user_name='张三'"; String sql2="update user set money=money+500 where user_name='李四'"; conn.setAutoCommit(false);//关闭自动提交,开启事务 conn.prepareStatement(sql1).executeUpdate(); int x=1/0;//模拟中途出错 conn.prepareStatement(sql2).executeUpdate(); conn.commit();//事务提交 } catch (SQLException e) { try { conn.rollback();//执行失败,事务回滚 } catch (SQLException ex) { ex.printStackTrace(); } e.printStackTrace(); }finally { closeConn(conn,null,null); } }
数据库连接池:
数据库连接--执行完毕--释放
由于连接--释放十分浪费系统资源,故而开发出池化技术
池化技术:准备一些预先的资源,连接时连接预先准备好的
比如:
数据库最大资源数:20
假设常用连接数:10
那么最大连接数:20
小于10的连接数直接使用,超过10小于20则需要使用备用的资源
超过20那么进行一个等待
如果等待时间过长,那么等待超时
编写连接池:实现一个接口DataSource
开源数据源:DBCP,C3P0,Druid:阿里巴巴,当使用了数据库连接池之后就不用我们自己去实现数据库的连接的代码的编写了
注:使用数据库连接池都是需要去实现一个dataSource接口。