一、数据库的基本概念
1. 什么是数据库?
* 用于存储和管理的仓库
2. 数据库的特点:
(1)持久化存储数据,其实数据库就是一个文件系统
(2)方便存储和管理数据
(3)使用了统一的方式操作数据库 SQL
二、MySQL数据库软件
1. [安装][1]
(http://jimshen.com/index.php/2021/04/09/windows-mysql-5-5-install)
2. 操作
* MySQL服务启停:使用管理员打开CMD
(1) 启动MySQL: net start mysql
(2) 关闭MySQL: net stop mysql
* MySQL登录({xxx}为占位符)
(1)mysql -u{root} -p{密码}
(2)mysql --host={ip} --user={root} --password={连接目标的密码}
* MySQL退出
(1)exit
(2)quit
* MySQL的目录结构
(1)安装目录: basedir="D:/dev/MySQL/MySQL Server 5.5/"
配置文件:my.ini
(2)MySQL数据目录:basedir="C:/ProgramData/MySQL/MySQL Server 5.5/Data/"
该目录下,一个文件夹是一个数据库,里面一个文件对应一张表
三、SQL概念
1. 什么是SQL?
Structured Query Language:结构化查询语言
其实就是定义了操作所有关系型数据库的规则。
每一种数据库操作的方式存在不一样的地方,称为"方言"(dialogue)。
2. SQL通用语法
(1)SQL语句可以单行或多行书写,以分号结尾。
(2)可以使用空格和缩进来增强语句的可读性
(3)MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。
(4)注释(3种):
* 单行注释: -- 注释内容
* 多行注释: /* 注释 */
* mysql特有: # 注释内容
3. SQL分类
(1)DDL(Data Definition Language) 数据定义语言
用来定义数据库对象:数据库,表,列等。关键字:create,drop,alter等
(2)DML(Data Manipulation Language) 数据操作语言
用来对数据库中表的数据进行增删改查。关键字:insert,delete,update等
(3)DQL(Data Query Language)数据查询语言
用来查询数据库中表的记录(数据)。关键字:select,where等
(4)DCL(Data Control Language)数据控制语言
用来定义数据库的访问权限和安全级别,以及创建用户。关键字:grant,revoke等
1. DDL: 操作数据库、表
(1) 操作数据库:CRUD
a)C(Create):创建
* 创建数据库:
`CREATE DATABASE 数据库名称;`
`CREATE DATABASE IF NOT EXISTS 数据库名称;`
`CREATE DATABASE 数据库名称 CHARACTER SET 字符集名称`
例如:创建test数据库,判断是否存在,并指定字符集为utf8
`CREATE DATABASE IF NOT EXISTS TEST CHARACTER SET UTF8`
b)R(Retrieve):查询
* 查询所有数据库的名称:
`show databases;`
* 查询某个数据库的字符集、查询某个数据库的创建语句
`show create database {数据库名称}`
c)U(Update):修改
* 修改数据库的字符集
`alter database {数据库名称} character set {字符集名称};`
d)D(Delete):删除
* 删除数据库、如果数据库存在则删除
`drop database {数据库名称};`
`drop database if exists {数据库名称}`
e)使用数据库
* 查询当前正在使用的数据库名称
`select database();`
* 使用数据库
`use {数据库名称};`
(2) 操作表
a)创建 & 常用数据类型:
* 基本语法
创建:`create table {表名}(列名1 数据类型1, ..., 列名2 数据类型2);`
复制: `create table {表名} like {被复制的表名};`
* 例子:
`create table student (
id int,
name varchar(32),
age int,
score double(4,1),
birthday date,
insert_time timestamp
);`
/*
数据库类型:
1. int:整数类型
* age int,
2. double:小数类型
* score double(5,2) //最大值999.99 (总位数,小数点后面的位数)
3. date:日期,只包含年月日,yyyy-MM-dd
4. datetime:日期,包含年月日时分秒 yyyy-MM-dd HH:mm:ss
5. timestamp:时间戳类型 包含年月日时分秒 yyyy-MM-dd HH:mm:ss
* 如果将来不给这个字段赋值,或赋值为null,则默认使用当前的系统时间,来自动赋值
6. varchar:字符串
* name varchar(20):姓名最大20个字符
* zhangsan 8个字符 张三 2个字符
*/
b)R 查询
* 查询某个数据库中所有表的名称
show tables;
* 查询表结构
desc 表名;
c)M 修改
* 表名
alter table 表名 rename to 新表名
* 字符集
alter table 表名 character set 字符集名称
例:
alter table stu character set utf8;
* 添加列
alter table 表名 add 列名 数据类型
* 修改列
alter table 表名 change 列名 新列名 新类型 -- 修改列名和类型
alter table 表名 modify 列名 新类型 -- 仅修改字段的类型
alter table 表名 drop primary key, add primary key(列名1,列名2,..) -- 修改表的主键
* 删除列
alter table 表名 drop 要删除的列名
d)D 删除
* 删除数据表
drop table 表名;
drop table if exists 表名;
2. DML: 增删改表中数据
(1) 添加数据
语法:
insert into 表名 (列名1, 列名2, ..., 列名n) values (值1, 值2, ..., 值n);
/* 注意
** 列名与值一一对应
** 如果表名后,不定义列名,则默认给所有列添加值:insert into 表名 values(列值...)
** 除了数字类型,其他类型都需要使用引号引起来
*/
例:
insert into student (id,name,age) values (1,'shen',28);
(2) 删除数据
语法:
delete from 表名 [where 条件]
/* 注意:
** 如果不加条件,则删除表中所有记录
** 如果要删除所有记录 */
a) delete from 表名; -- 不推荐使用,有多少条记录就会执行多少次删除操作
b) trunk table 表名; -- 推荐,效率更高,先删除表,然后再创建一张一样的表
(3) 修改数据
语法:
update 表名 set 列名1=值1,列名2=值2, ..., 列名n=值n [where 条件]
/** 注意:
** 如果不加条件,会将表中所有记录全部修改
*/
3. DQL: 查询表中的记录
(1) 语法
select
字段列表
from
表名列表
where
条件列表
group by
分组字段
having
分组之后的条件
order by
排序
limit
分页限定
(2) 基础查询
a) 多个字段的查询
select 字段名1,字段名2,... from 表名;
-- 注意:如果查询所有字段,则可以使用*来替代字段列表
b) 去除重复的结果集
distinct
例:select name,age from xxx; -- 会对name+age进行去重
c) 计算列
-- 一般可以使用四则运算计算一些列的值(一般只会进行数值型的计算)
-- ifnull(expr1, expr2) : null参与的运算,计算结果都为null
-- expr1: 哪个字段需要判断是否为null
-- expr2: default value
d) 别名
as
-- 可省略
(3) 条件查询
a) where子句后跟条件
b)运算符
* > 、< 、<= 、>= 、= 、<>
* BETWEEN...AND [a,b]
* IN( 集合)
* LIKE:模糊查询
* 占位符:
* _:单个任意字符 一个字符
* %:多个任意字符 字符数(0~x)
* IS NULL
* and 或 &&
* or 或 ||
* not 或 !
-- 注意:null值不能使用=或!=判断
(4) 排序查询
语法:order by子句
order by 排序字段1 排序方式1, 排序字段2 排序方式2, ...
排序方式:
asc:升序,默认
desc:降序
-- 注意:如果有多个排序条件,则当前面的条件值一样时,才会去判断第二个条件
(5) 聚合函数
将一列数据作为一个整体进行纵向的计算
-- 聚合函数的计算,排除null值,即不会将null纳入其中计算
count:计算个数
-- 一般选择非空的列:主键
-- count(*) :只要一行中,至少有一列非null,则会纳入计算
max: 计算最大值
min: 计算最小值
sum: 计算和
avg: 计算平均值
(6) 分组查询
语法:group by 分组字段
-- 注意:
-- 分组之后查询的字段:分组字段、聚合函数 (select中的字段)
-- where和having的区别?
a) where在分组之前进行限定,如果不满足条件,则不参与分组。having在分组之后进行限定,如果不满足条件,则不会被查询出来(where对行过滤,having对分的组过滤)
b) where后不可以跟聚合函数,having可以进行聚合函数的判断
例:
-- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人,不参与分组,分组之后。人数要大于2个人
select gender, avg(math) avg, count(id) count from stu where math > 70 group by gender having count > 2;
(7) 分页查询
语法:limit 开始的索引,每页查询的条数 (mysql方言)
公式:开始的索引 =(当前的页码 - 1)* 每页显示的条数
例:
select * from stu limit 0,3; -- 第一页
select * from stu limit 3,3; -- 第二页
四、 约束
1. 概念
对表中数据进行限定,保证数据的正确性、有效性和完整性
2. 分类
- 主键约束 primary key
- 非空约束 not null
- 唯一约束 unique
- 外键约束 foreign key
3. 非空约束 not null
not null 某一列的值不能为null
添加约束:
(1) 在创建表时添加
create table stu(
id int,
name varchar(20) not null -- name为非空
);
(2) 创建表完后,添加
alter table stu modify name varchar(20) not null; -- 字段类型修改+约束
(3) 删除name的非空约束
alter table stu modify name varchar(20); -- 字段修改,不加约束
4. 唯一约束 unique
unique,某一列的值不能重复
-- 注意:唯一约束可以有null值,但是只能有一条记录为null
添加约束:
(1) 创建表时添加约束
create table stu(
id int,
phone_number varchar(20) unique
);
(2) 创建完后添加
alter table stu modify phone_number varchar(20) unique;
(3) 删除唯一键
alter table drop index phone_number;
5. 主键 primary key
5.1 主键就是表中记录的唯一标识(非空且唯一)
-- 注意:一张表只能有一个字段为主键 ?
添加约束
(1) 创建表时添加约束
create table stu(
id int primary key,
name varchar(20)
);
(2) 创建后添加约束
alter table modify id int primary key;
(3) 删除主键
alter table drop primary key;
5.2 自动增长:如果某一列是数值类型的,使用auto_increment,可以来完成值的自动增长
-- 默认从1开始增长,每次加1
(1) 创建
create table stu(
id int primary key auto_increment,
name varchar(20)
);
(2) 创建后添加
alter table stu modify id int auto_increment;
(3) 删除
alter table stu modify id int; -- 不会删除主键,会将自增长删除
五、 多表查询
-- 准备sql
-- 创建部门表
CREATE TABLE dept(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);
INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
-- 创建员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙悟空','男',7200,'2013-02-24',1);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('猪八戒','男',3600,'2010-12-02',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);
1. 笛卡尔积
- 有两个集合A, B,取这两个集合的所有组成情况
- 要完成多表查询,需要消除无用的数据
2. 内连接查询
2.1 隐式内连接
使用where条件消除无用数据
-- 例:查询员工表的名称,性别,部门表的名称
SELECT
t1.name, -- 员工表的姓名
t1.gender,-- 员工表的性别
t2.name -- 部门表的名称
FROM
emp t1,
dept t2
WHERE
t1.`dept_id` = t2.`id`;
2.2 显示内连接
-- 语法:select 字段列表 from 表名1 [inner] join 表名2 on 条件
-- 例:
SELECT * FROM emp INNER JOIN dept ON emp.`dept_id` = dept.`id`;
SELECT * FROM emp JOIN dept ON emp.`dept_id` = dept.`id`;
注意:
- 从哪写表中查数据
- 连接条件是什么
- 查询哪些字段
3. 外连接查询
3.1 左外连接
-- 语法:select 字段列表 from 表1 left [outer] join 表2 on 条件;
-- 查询的是左表所有数据以及其交集部分
-- 例:
-- 查询所有员工信息,如果员工有部门,则查询部门名称,没有部门,则不显示部门名称
SELECT t1.*,t2.name FROM emp t1 LEFT JOIN dept t2 ON t1.`dept_id` = t2.`id`;
3.2 右外连接
-- 语法:select 字段列表 from 表1 right [outer] join 表2 on 条件;
-- 查询的是右表所有数据以及其交集部分
-- 例:
SELECT * FROM dept t2 RIGHT JOIN emp t1 ON t1.`dept_id` = t2.`id`;
4. 子查询
4.1 子查询的结果是单行单列的
- 子查询可以作为条件,使用运算符去判断。> >= < <= =
-- 例:查询员工工资小于平均工资的人
select * from emp where emp.salary < (select avg(salary) from emp)
4.2 子查询的结果是多行多列的
- 子查询可以作为条件,使用运算符in来判断
-- 查询'财务部'和'市场部'所有的员工信息
select id from dept where name='财务部' name='市场部';
select * from emp where dept_id=3 or dept_id=2;
-- 子查询
select * from emp where dept_id in (select id from dept where name='财务部' name='市场部');
4.3 子查询的结果是多行多列的
- 子查询可以微微一张虚拟表参与查询(子查询或内连接)
-- 查询员工入职日期是2011-11-11日之后的员工信息和部门信息
-- 子查询
SELECT * FROM dept t1 ,(SELECT * FROM emp WHERE emp.`join_date` > '2011-11-11') t2 WHERE t1.id = t2.dept_id;
-- 普通内连接
SELECT * FROM emp t1,dept t2 WHERE t1.`dept_id` = t2.`id` AND t1.`join_date` > '2011-11-11'
六、 事务
1. 概念
- 如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。
2. 操作
-
开启事务:start transaction
-
回滚:rollback
-
提交:commmit
-- 例:转账
CREATE TABLE account (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);
SELECT * FROM account;
UPDATE account SET balance = 1000;
-- 张三给李四转账 500 元
-- 0. 开启事务
START TRANSACTION;
-- 1. 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 2. 李四账户 +500
-- 中间过程是否出错了...
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi'; -- 成功
-- 发现执行没有问题,提交事务
COMMIT;
-- 发现出问题了,回滚事务
ROLLBACK;
3. 数据库事务的提交方式
-
事务提交的两种方式:
- 自动提交:
- mysql就是自动提交的
- 一条DML(增删改)语句会自动提交一次事务。
- 手动提交:
- Oracle 数据库默认是手动提交事务
- 需要先开启事务,再提交
- 自动提交:
-
查看事务的默认提交方式:
SELECT @@autocommit; – 1 代表自动提交 0 代表手动提交
-
修改默认提交方式:
set @@autocommit = 0;
4. 事务的四大特征
-
原子性:
是不可分割的最小操作单位,要么同时成功,要么同时失败
-
持久性
当提交或回滚后,数据库会持久化保存的数据
-
隔离性
多个事务之间,相互独立
-
一致性
事务操作前后,数据总量不变
5. 事务的隔离级别
-
概念:多个事务之间是隔离、相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题
-
存在的问题:
- 脏读:一个事务,读取到另一个事务中没有提交的数据
- 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样
- 幻读:一个事务操作(dml)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
-
隔离级别
- read uncomitted:读未提交
- 产生的问题:脏读、不可重复读
- read committed: 读已提交 (oracle默认)
- 产生的问题:不可重复读,幻读
- repeatable read:可重复读 ( mysql默认)
- 产生的问题:幻读
- serializable:串行化
- 可解决所有问题
– 隔离级别从小到大,安全性越来越高,但是效率越来越低
- read uncomitted:读未提交
-
隔离级别修改
- 查询
- select @@tx_isolation;
- 修改
- set global transaction isolation level 级别字符串;
- 查询
七、JDBC
1. 概念
- Java DataBase Connectivity: java 数据库连接
官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。
2. 导入依赖
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
</dependencies>
3. 步骤
// 1. 导入jar包
// 2. 注册驱动 8.0以前使用com.mysql.jdbc.Driver
Class.forName('com.mysql.cj.jdbc.Driver');
// 3. 获取数据库连接对象 8.0后需要在url中增加参数 useSLL
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dbname?userSSL=false", "root", "root");
// 4. 定义sql语句
String sql = "update account set balance = 500 where id = 1";
String preSql = "update account set balance = ? where id = ?";
// 5. 获取执行sql的对象 statement
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.preparedStatement(preSql);
// 6. 执行sql
int count = stmt.executeUpdate(sql);
int count = pstmt.executeUpdate(sql);
// 7. 封装结果集
// 8. 释放资源
stmt.close();
conn.close();
4. 实际例子
// 新增数据
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "123456");
Statement statement = connection.createStatement();
String sql = "insert into user values (1, 'jimmy', '123')";
int count = statement.executeUpdate(sql);
System.out.println("affected rows " + count);
statement.close();
connection.close();
// 预编译修改数据
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "123456");
String psql = "update user set password = ? where id = ?";
PreparedStatement preparedStatement = connection.prepareStatement(psql);
preparedStatement.setString(1, "12345"); // 参数索引从1开始
preparedStatement.setInt(2, 1);
int count = preparedStatement.executeUpdate();
System.out.println("affected rows " + count);
preparedStatement.close();
connection.close();
// 查询
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useSSL=false", "root", "123456");
String sql = "select id, username, password from user";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
System.out.println(user);
}
rs.close();
preparedStatement.close();
connection.close();
更新日志
【2021/11/11】DDL 补充修改数据表主键语法例子
【2021/11/14】增加jdbc 插入、更新、查询例子
1935

被折叠的 条评论
为什么被折叠?



