MySQL、JDBC、HTML、CSS、JavaScript、jQuery、tomcat、Http、Servlet、JSP、EL、JSTL、Maven、Cookie、Session(框架第一部分)

第一章 MySQL

一 、数据库

1.什么是数据库?

所谓的数据库就是指存储管理数据的仓库

2.数据库有哪些分类?

在这里插入图片描述

3.什么是关系型数据库?

底层以二维表的形式保存数据的库就是关系型数据库

stu-学生表
在这里插入图片描述

4.常见的关系型数据库有哪些?

  • Sql Server:微软提供,收费,适用于一些中型或大型的项目中,在java中的使用占比不高(.NET中使用的较多)

  • Oracle:甲骨文公司提供,收费,适用于一些大型或者超大型的项目中,在java中的使用占比非常高

  • mysql:瑞典MySQLAB公司提供,免费开源,适用于一些小型或者中型的项目中,在Java中的使用占比较高(小巧轻量)
    mariadb其实就是MySQL的一个分支,用法和MySQL完全一样。

  • DB2:IBM公司提供,收费,在一些银行、金融等行业中使用较多。在java中的使用占比也不高。

  • Sqlite:迷你数据库,嵌入式设备中(安卓、苹果手机、pad)

二 、数据库相关概念(数据库服务器、数据库、表、表记录)

1.什么是数据库服务器

数据库服务器就是一个软件(比如mysql软件)将数据库软件安装在电脑上,当前电脑就是一个数据库服务器。就可以对外提供存取数据的服务

2.什么是数据库

数据库就是存储和管理数据的仓库,通常情况下,一个网站的中的所有数据会存放在一个数据库中。例如:
在这里插入图片描述

3.什么是表

一个数据库中可以创建多张表,每张表用于存储一类信息(数据库),例如:

jd.com中的用户数据 tb_user(表)

jd.com中的商品数据 tb_product(表)

jd.com中的订单数据 tb_order(表)

4.什么表记录

一张表中可以包含多行表记录,每一行表记录用于存储某一个具体的数据,例如:
在这里插入图片描述

三 、SQL语言

SQL是一们用于操作关系型数据库的通用的语言(使用SQL可以操作所有的关系型数据库)

使用SQL可以操作数据库、表、表记录

(1)创建数据库、删除数据库、修改数据库、查询数据库

(2)创建表、删除表、修改表、查询表

(3)新增表记录、删除表记录、修改表记录、查询表记录

使用SQL也可以操作存储过程/视图/索引等。

提示:SQL是一个标准通用的操作关系型数据库的语言(普通话),每个数据库厂商为了增强自己数据库的功能,都提供了支持自己数据库的语言,称之为数据库的方言。方言不通用!

四 、连接mysql服务器

通过命令行工具可以登录MySQL客户端,连接MySQL服务器,从而访问服务器中的数据。

1.连接mysql服务器:

在这里插入图片描述
-u: 后面的root是用户名,这里使用的是超级管理员root;

-p:(小写的p) 后面的root是密码,这是在安装MySQL时就已经指定的密码;

2.连接mysql服务器并指定IP和端口:

在这里插入图片描述
-h: 后面给出的127.0.0.1是服务器主机名或ip地址,可以省略的,默认连接本机;

-P:(大写的P) 后面的3306是连接端口,可以省略,默认连接3306端口;

3.退出客户端命令:quit或exit或 \q

在这里插入图片描述

五 、数据库及表操作(创建、删除、查看数据库)

提示:
(1) SQL语句对大小写不敏感。推荐关键字使用大写,自定义的名称(库名,表名,列名等)使用小写。

SHOW DATABASES; -- 查看当前数据库服务器中的所有库
CREATE DATABASE mydb1; -- 创建mydb1库

(2) 并且在自定义名称时,针对多个单词不要使用驼峰命名,而是使用下划线连接。(例如:tab_name,而不是 tabName )

1.查看mysql服务器中所有数据库

show databases;

2.进入某一数据库(进入数据库后,才能操作库中的表和表记录)

语法:USE 库名;

use test;

查看已进入的库

SELECT DATABASE();

3.查看当前数据库中的所有表

先进入某一个库,再查看当前库中的所有表
show tables;

4.删除mydb1库

语法:DROP DATABASE 库名;

drop database mydb1;

思考:当删除的库不存在时,如何避免错误产生?

drop database if exists mydb1;

5.重新创建mydb1库,指定编码为utf8

语法:CREATE DATABASE 库名 CHARSET 编码;

需要注意的是,mysql中不支持横杠(-),所以utf-8要写成utf8;

如果存在mydb1,则先删除,再重建
create database mydb1 charset utf8;
如果不存在则创建mydb1;
create database if not exists mydb1 charset utf8;

6.查看建库时的语句(并验证数据库库使用的编码)

语法:SHOW CREATE DATABASE 库名;

show create database mydb1; -- 查看建库时的语句
show create table stu; -- 查看建表时的语句

创建、删除、查看表

7.进入mydb1库,删除stu学生表(如果存在)

语法:DROP TABLE 表名;

use mydb1;
drop table if exists stu;

8.创建stu学生表(编号[数值类型]、姓名、性别、出生年月、考试成绩[浮点型]),建表的语法:

CREATE TABLE 表名(
	列名 数据类型,
	列名 数据类型,
	...
  列名 数据类型
);

SQL语句:

drop table if exists stu;
create table stu(
	id int primary key auto_increment, -- 将id设置为主键(唯一且不能为空),并且设置为自增
  name varchar(50),
  gender varchar(10),
  birthday date,
  score double
);

9.查看stu学生表结构

desc stu;

在这里插入图片描述

六 、新增、更新、删除表记录

1.往学生表(stu)中插入记录(数据)

语法:INSERT INTO 表名(列名1,列名2,列名3…) VALUES(值1,值2,值3…);

如果是在cmd中执行插入记录的语句,set names gbk; 再插入记录!
insert into stu(id,name,gender,birthday,score) value (null,'tom','male','1985-1-1',78);
insert into stu value(null,'孙悟空','female','1985-2-2',88);
insert into stu value(null,'猪八戒','male','1999-3-3',68);

提示:

(1)当为所有列插入值时,可以省写列名,但值的个数和顺序必须和声明时列的个数和顺序保持一致!
(2)SQL语句中的值为字符串或日期时,值的两边要加上单引号(有的版本的数据库双引号也可以,但推荐使用单引号)。
(3)(针对cmd窗口)在插入数据之前,先设置编码:set names gbk;

或者用一下命令连接mysql服务器:

mysql --default-character-set=gbk -uroot -proot

等价于:

mysql -uroot -proot

set names gbk;

2.查询stu表所有学生的信息

语法:SELECT 列名 | * FROM 表名

select * from stu;

3.修改stu表中所有学生的成绩,加10分特长分

修改语法: UPDATE 表名 SET 列=值,列=值,列=值…[WHERE子句];

update stu set score=score+10;

4.修改stu表中编号为1的学生成绩,将成绩改为83分。

update stu set score=83 where id=1;

提示:where子句用于对记录进行筛选过滤,保留符合条件的记录,将不符合条件的记录剔除。

5.删除stu表中所有的记录

删除记录语法: DELETE FROM 表名 [where条件]

delete from stu;

仅删除符合条件的

delete from stu where id>1;

七 、查询表记录

准备数据: 以下练习将使用db10库中的表及表记录,请先进入db10数据库!!!

1.基础查询

SELECT 语句用于从表中选取数据。结果被存储在一个结果表中(称为结果集)。

语法:SELECT 列名称 | * FROM 表名

提示:
(1) *(星号)为通配符,表示查询所有列。
(2)但使用 *(星号)有时会把不必要的列也查出来了,并且效率不如直接指定列名

查询emp表中的所有员工,显示姓名,薪资,奖金

select name,sal,bonus from emp;

查询emp表中的所有部门和职位

select dept,job from emp;

思考:如果查询的结果中,存在大量重复的记录,如何剔除重复记录,只保留一条?

在select之后、列名之前,使用DISTINCT 剔除重复的记录

select distinct dept,job from emp;

2.WHERE子句查询

WHERE子句查询语法:SELECT 列名称 | * FROM 表名称 WHERE 列 运算符 值

WHERE子句后面跟的是条件,条件可以有多个,多个条件之间用连接词(or | and)进行连接

下面的运算符可在 WHERE 子句中使用:
在这里插入图片描述

查询emp表中薪资大于3000的所有员工,显示员工姓名、薪资

select name,sal from emp 
where sal>3000;

查询emp表中总薪资(薪资+奖金)大于3500的所有员工,显示员工姓名、总薪资

select name,sal+bonus from emp
where sal+bonus > 3500; -- 结果是错误的!

ifnull(列, 值)函数: 判断指定的列是否包含null值,如果有null值,用第二个值替换null值

select name,ifnull(sal,0)+ifnull(bonus,0) from emp
where ifnull(sal,0)+ifnull(bonus,0) > 3500;

注意查看上面查询结果中的表头,如何将表头中的 sal+bonus 修改为 “总薪资”

使用as可以为表头指定别名

select name as 姓名,ifnull(sal,0)+ifnull(bonus,0) as 总薪资 from emp
where ifnull(sal,0)+ifnull(bonus,0) > 3500;

另外as可以省略

select name 姓名,ifnull(sal,0)+ifnull(bonus,0) 总薪资 from emp
where ifnull(sal,0)+ifnull(bonus,0) > 3500;

查询emp表中薪资在3000和4500之间的员工,显示员工姓名和薪资

select name,sal from emp
where sal>=3000 and sal<=4500;

提示: between…and… 在…之间

select name,sal from emp
where sal between 3000 and 4500;

查询emp表中薪资为 1400、1600、1800的员工,显示员工姓名和薪资

select name,sal from emp
where sal=1400 or sal=1600 or sal=1800;

或者

select name,sal from emp
where sal in(1400,1600,1800);

查询薪资不为1400、1600、1800的员工

方式一:

select name,sal from emp
where not(sal=1400 or sal=1600 or sal=1800);

方式二:

select name,sal from emp
where sal!=1400 and sal!=1600 and sal!=1800;

方式三:

select name,sal from emp
where sal not in(1400,1600,1800);

查询emp表中薪资大于4000和薪资小于2000的员工,显示员工姓名、薪资。

select name,sal from emp
where sal>4000 or sal<2000;

查询emp表中薪资大于3000并且奖金小于600的员工,显示员工姓名、薪资、奖金。

select name,sal,bonus from emp
where sal>3000 and bonus<600;

处理null值

select name,sal,ifnull(bonus,0) from emp
where sal>3000 and ifnull(bonus,0)<600;

查询没有部门的员工(即部门列为null值)

select * from emp where dept is null;

思考:如何查询有部门的员工(即部门列不为null值)

select * from emp where dept is not null;

3.模糊查询

LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式。

可以和通配符(%、_)配合使用,其中"%"表示0或多个任意的字符。’_'表示一个任意的字符。

语法:SELECT 列 | * FROM 表名 WHERE 列名 LIKE 值

示例:

查询emp表中姓名中包含"涛"字的员工,显示员工姓名。

select name from emp
where name like '%涛%';
select name from emp
where name like '%王%';

查询emp表中姓名中以"刘"字开头的员工,显示员工姓名

select name from emp
where name like '刘%'; -- 查询以'刘'开头的

select name from emp
where name like '%涛'; -- 查询以'涛'结尾的

查询emp表中姓名以"刘"开头,并且姓名为两个字的员工,显示员工姓名。

select name from emp
where name like '刘_'; -- 以"刘"开头,并且姓名为两个字
select name from emp
where name like '刘_ _'; -- 以"刘"开头,并且姓名为三个字

3.多行函数查询

多行函数也叫做聚合(聚集)函数,根据某一列或所有列进行统计。

常见的多行函数有:
在这里插入图片描述
提示:
(1)多行函数不能用在where子句中

(2)多行函数和是否分组有关,分组与否会直接影响多行函数的执行结果。

(3)多行函数在统计时会对null进行过滤,直接将null丢弃,不参与统计。

统计emp表中薪资大于3000的员工个数

select count(*) from emp where sal>3000;
select count(id) from emp where sal>3000;

求emp表中的最高薪资

select sal from emp; -- 查询emp表中的所有薪资
select max(sal) from emp; -- 统计emp表中的最高薪资
select min(sal) from emp; -- 统计emp表中的最低薪资

统计emp表中所有员工的薪资总和(不包含奖金)

select sum(sal) from emp; -- 统计sal这一列中的所有值的和
select sum(bonus) from emp; -- 统计bonus这一列中的所有值的和

select sum(sal)+sum(bonus) from emp; -- 统计 薪资总和+奖金总和
select sum(sal+bonus) from emp; -- 因为bonus列中有null值,所以结果有误差
select sum(sal+ifnull(bonus,0)) from emp; -- 处理null值,结果正确

统计emp表员工的平均薪资(不包含奖金

select avg(sal) from emp;

多行函数需要注意的问题:

  • 多行函数和是否分组有关,如果查询结果中的数据没有经过分组,默认整个查询结果是一个组,多行函数就会默认统计当前这一个组的数据。产生的结果只有一个。

  • 如果查询结果中的数据经过分组(分的组不止一个),多行函数会根据分的组进行统计,有多少个组,就会统计出多少个结果。

select * from emp;

例如:统计CGB2003班的人数

select count(*) from emp;

结果返回的就是CGB2003班的所有人数

再例如:根据性别进行分组,再统计CGB2003每组的人数

select gender,count(*) from emp group by gender;

4.分组查询

select * from emp group by dept; -- 按照部门分组, 部门相同的是一组

对emp表按照职位进行分组,并统计每个职位的人数,显示职位和对应人数

select * from emp group by job; -- 按照职位分组, 职位相同的是一组
select job,count(*) from emp group by job; -- 按照职位分组, 统计每个职位的人数

对emp表按照部门进行分组,求每个部门的最高薪资(不包含奖金),显示部门名称和最高薪资

select dept,max(sal) from emp group by dept;

5.排序查询

使用 ORDER BY 子句将结果集中记录根据指定的列排序后再返回

语法:SELECT 列名 FROM 表名 ORDER BY 列名 [ASC|DESC]

ASC(默认)升序,即从低到高;DESC 降序,即从高到低。

对emp表中所有员工的薪资进行升序(从低到高)排序,显示员工姓名、薪资。

select name,sal from emp order by sal asc; -- 升序排序
select name,sal from emp order by sal; -- 默认是升序排序,因此asc可以省略

对emp表中所有员工的奖金进行降序(从高到低)排序,显示员工姓名、奖金。

select name,bonus from emp order by bonus desc; -- 按照奖金降序排序

-- 按照奖金降序排序,如果奖金相同,则按照薪资升序排序
select name,bonus,sal from emp order by bonus desc, sal asc;
-- 按照奖金降序排序,如果奖金相同,则按照薪资奖金排序
select name,bonus,sal from emp order by bonus desc, sal desc;

6.分页查询

在mysql中,通过limit进行分页查询:

limit (页码-1)*每页显示记录数, 每页显示记录数

查询emp表中的所有记录,分页显示:每页显示3条记录,返回第 1 页。

select * from emp limit 0,3; -- 每页显示3条, 查询第1页
select * from emp limit 3,3; -- 每页显示3条, 查询第2页
select * from emp limit 6,3; -- 每页显示3条, 查询第3页

查询emp表中的所有记录,分页显示:每页显示3条记录,返回第 2 页。

select * from emp limit 3,3; -- 每页显示3条, 查询第2页

求emp表中薪资最高的前3名员工的信息,显示姓名和薪资

-- 按照薪资降序排序查询员工信息
select name,sal from emp order by sal desc;
-- 在上面查询的基础上分页查询,每页显示3条, 查询第1页
select name,sal from emp order by sal desc limit 0,3; 

7.其他函数

在这里插入图片描述
查询emp表中所有在1993和1995年之间出生的员工,显示姓名、出生日期。

select name,birthday from emp
where birthday>='1993-1-1' and birthday<='1995-12-31';
-- 或 将birthday中的年份取出来, 和1993及1995进行比较!
select name,birthday from emp
where year(birthday)>=1993 and year(birthday)<=1995;

查询emp表中下个月过生日的所有员工

select * from emp
where month(birthday)=month(now()); -- 查询本月过生日的员工
select * from emp
where month(birthday)=month(now())+1; -- 查询下个月过生日的员工

查询emp表中员工的姓名和薪资(薪资格式为: xxx(元) )

select name, sal from emp;
select name, concat(sal,'(元)') from emp;

查询emp表中员工的姓名和薪资(薪资格式为: xxx/元 )

select name, concat_ws('/', sal, '元') from emp;

八 、mysql的数据类型

1.数值类型

tinyint:占用1个字节,相对于java中的byte

smallint:占用2个字节,相对于java中的short

int:占用4个字节,相对于java中的int

bigint:占用8个字节,相对于java中的long

其次是浮点类型即:float和double类型

float:4字节单精度浮点类型,相对于java中的float

double:8字节双精度浮点类型,相对于java中的double

2.字符串类型

1、char(n) 定长字符串,最长255个字符。n表示字符数,例如:

创建user表,指定用户名为char类型,字符长度不超过10

create table user(
    username char(10),
    ...
);

所谓的定长,是当插入的数据的长度小于指定的长度时,剩余的空间会用空格填充。(这样会浪费空间)

2、varchar(n) 变长字符串,最长不超过65535个字节,n表示字符数,一般超过255个字符,会使用text类型,例如:

iso8859-1码表:一个字符占用1个字节,1*n <= 65535, n最多等于 65535
utf8码表:一个中文汉字占用3个字节,3*n<=65535,n最多等于 65535/3
GBK码表:一个中文汉字占用2个字节,2*n<65535,n最多等于 65535/2

创建user表,指定用户名为varchar类型,长度不超过10

create table user(
	username varchar(10)
);

所谓的不定长,是当插入的数据的长度小于指定的长度时,剩余的空间可以留给别的数据使用。(节省空间)

3.大文本(长文本)类型

最长65535个字节,一般超过255个字符列的会使用text。

创建user表:

create table user(
	resume text
);

另,text也分多种,其中bigtext存储数据的长度约为4GB。

char(n)、varchar(n)、text都可以表示字符串类型,其区别在于:

(1)char(n)在保存数据时,如果存入的字符串长度小于指定的长度n,后面会用空格补全,因此可能会造成空间浪费,但是char类型的存储速度较varchar和text快。

因此char类型适合存储长度固定的数据,这样就不会有空间浪费,存储效率比后两者还快!

(2)varchar(n)保存数据时,按数据的真实长度存储,剩余的空间可以留给别的数据用,因此varchar不会浪费空间。

因此varchar适合存储长度不固定的数据,这样不会有空间的浪费。

(3)text是大文本类型,一般文本长度超过255个字符,就会使用text类型存储。

4.日期类型

date:年月日

time:时分秒

datetime:年月日 时分秒

timestamp:时间戳(实际存储的是一个时间毫秒值),与datetime存储日期格式相同。两者的区别是:

  • timestamp最大表示2038年,而datetime范围是1000~9999

  • timestamp在插入数据、修改数据时,可以自动更新成系统当前时间(后面用到时再做讲解)

九 、mysql的字段约束

字段约束/列约束 --> 约束: 限制

1.主键约束

主键约束:如果为一个列添加了主键约束,那么这个列就是主键,主键的特点是唯一且不能为空。

主键的作用: 作为一个唯一标识,唯一的表示一条表记录(作用类似于人的身份证号,可以唯一的表示一个人一样。)

① 添加主键约束,例如将id设置为主键:

create table stu(
	id int primary key,
	...
);

如果主键是数值类型,为了方便插入主键(并且保证插入数据时,主键不会因为重复而报错),可以设置一个主键自增策略

主键自增策略是指:设置了自增策略的主键,可以在插入记录时,不给id赋值,只需要设置一个null值,数据库会自动为id分配一个值(AUTO_INCREMENT变量,默认从1开始,后面依次+1),这样既可以保证id是唯一的,也省去了设置id的麻烦。

② 将id主键设置为自增:

create table stu(
	id int primary key auto_increment,
	...
);

2.非空约束

非空约束:如果为一个列添加了非空约束,那么这个列的值就不能为空,但可以重复。

① 添加非空约束,例如为password添加非空约束:

create table user(
	password varchar(50) not null,
	...
);

3.唯一约束

唯一约束:如果为一个列添加了唯一约束,那么这个列的值就必须是唯一的(即不能重复),但可以为空。

① 添加唯一约束,例如为username添加唯一约束及非空约束:

create table user(
	username varchar(50) unique not null,
	...
);

4.外键约束

① 创建表的同时添加外键

create table emp(
	id int,
	name varchar(50),
	dept_id int,
	foreign key(dept_id) references dept(id)
);

在这里插入图片描述
(1)如果是要表示两张表的数据之间存在对应关系,只需要在其中的一张表中添加一个列,保存另外一张表的主键,就可以保存两张表数据之间的关系。

但是添加的这个列(dept_id)对于数据库来说就是一个普通列,数据库不会知道两张表存在任何关系,因此数据库也不会帮我们维护这层关系。
在这里插入图片描述
(2)如果将dept_id列设置为外键,等同于通知数据库,部门表和员工表之间存在对应关系,dept_id列中的数据要参考部门的主键,数据库一旦知道部门和员工表之间存在关系,就会帮我们维护这层关系。

十 、表关系

常见的表关系分为以下三种:

一对多(多对一)、一对一、多对多

1.一对多

在这里插入图片描述

2.一对一

在这里插入图片描述

3.多对多

在这里插入图片描述

十一、多表查询

准备数据: 以下练习将使用db30库中的表及表记录,请先进入db30数据库!!!

1.连接查询

查询部门和部门对应的员工信息

select * from dept,emp;

上面的查询中存在大量错误的数据,一般我们不会直接使用这种查询。

笛卡尔积查询:所谓笛卡尔积查询就是指,查询两张表,其中一张表有m条记录,另一张表有n条记录,查询的结果是m*n条。

虽然笛卡尔积查询中包含大量错误数据,但我们可以通过where子句将错误数据剔除,保留下来的就是正确数据。

-- 条件: 员工所属的部门编号等于部门的编号
select * from dept,emp 
where emp.dept_id=dept.id;

通过where子句将笛卡尔积查询中的错误数据剔除,保留正确的数据,这就是连接查询!

上面的查询可以换成下面的查询:

select * from dept inner join emp 
on emp.dept_id=dept.id; -- 内连接查询

2.左外连接查询

查询所有部门和部门下的员工,如果部门下没有员工,员工显示为null

select * from dept left join emp 
on emp.dept_id=dept.id; -- 左外连接查询

在这里插入图片描述
左外连接查询:可以将左边表中的所有记录都查询出来,右边表只显示和左边相对应的数据,如果左边表中某些记录在右边没有对应的数据,右边显示为null即可。

3.右外连接查询

查询部门和所有员工,如果员工没有所属部门,部门显示为null

select * from dept right join emp
on emp.dept_id=dept.id;

在这里插入图片描述
右外连接查询:可以将右边表中的所有记录都查询出来,左边表只显示和右边相对应的数据,如果右边表中某些记录在左边没有对应的数据,可以显示为null。

扩展:如果想将两张表中的所有数据都查询出来(左外+右外并去除重复记录),可以使用全外连接查询,但是mysql又不支持全外连接查询。

select * from dept left join emp on emp.dept_id=dept.id
union
select * from dept right join emp on emp.dept_id=dept.id;

可以使用union将左外连接查询的结果和右外连接查询的结果合并在一起,并去除重复的记录。例如:
在这里插入图片描述
需要注意的是:union可以将两条SQL语句执行的结果合并有前提:

(1)两条SQL语句查询的结果列数必须一致

(2)两条SQL语句查询的结果列名、顺序也必须一致

并且union默认就会将两个查询中重复的记录去除(如果不希望去除重复记录,可以使用union all)

4.子查询练习

准备数据:以下练习将使用db40库中的表及表记录,请先进入db40数据库!!!

列出薪资比’王海涛’的薪资高的所有员工,显示姓名、薪资

-- 求出'王海涛'的薪资
select sal from emp where name='王海涛'; -- 2450
-- 列出比'王海涛'薪资还高的员工
select name,sal from emp 
where sal>(select sal from emp where name='王海涛');

列出与’刘沛霞’从事相同职位的所有员工,显示姓名、职位

-- 求出'刘沛霞'的职位
select job from emp where name='刘沛霞'; -- 推销员
-- 求出和'刘沛霞'从事相同职位的员工
select name,job from emp
where job=(select job from emp where name='刘沛霞');

列出薪资比’大数据部’部门(已知部门编号为30)所有员工薪资都高的员工信息,显示员工姓名、薪资和部门名称。

如果不考虑没有部门的员工

-- 1、连接查询员工和部门
select e.name,e.sal,d.name from dept d,emp e
where e.dept_id=d.id;
-- 2、求出大数据部门的最高薪资(查询员工表中部门编号为30的最高薪资)
select max(sal) from emp where dept_id=30;
-- 3、求出比大数据部门最高薪资还高的员工信息
select e.name,e.sal,d.name from dept d,emp e
where e.dept_id=d.id 
	and sal>(select max(sal) from emp where dept_id=30);

如果加上没有部门的员工

-- 1、用外连接查询所有员工和对应的部门
select e.name,e.sal,d.name from dept d right join emp e
on e.dept_id=d.id;
-- 2、求出大数据部门的最高薪资
select max(sal) from emp where dept_id=30;
-- 3、求出比大数据部门最高薪资还高的员工信息
select e.name,e.sal,d.name from dept d right join emp e
on e.dept_id=d.id and
sal>3000;

5.多表查询练习

列出在’培优部’任职的员工,假定不知道’培优部’的部门编号,显示部门名称,员工名称。

-- 关联查询两张表
select d.name,e.name from dept d, emp e
where e.dept_id=d.id;
-- 求出在培优部的员工
select d.name,e.name from dept d, emp e
where e.dept_id=d.id and d.name='培优部';

(自查询)列出所有员工及其直接上级,显示员工姓名、上级编号,上级姓名

/* emp e1 员工表, emp e2 上级表
 * 查询的表: emp e1, emp e2
 * 显示的列: e1.name, e2.id, e2.name
 * 连接条件: e1.topid=e2.id
 */
select e1.name, e2.id, e2.name
from emp e1, emp e2
where e1.topid=e2.id;

列出最低薪资大于1500的各种职位,显示职位和该职位的最低薪资

-- 根据职位进行分组,求出每种职位的最低薪资
select job,min(sal) from emp group by job;
-- 求出最低薪资大于1500的职位
select job,min(sal) from emp where min(sal)>1500 group by job; -- 错误写法

select job,min(sal) from emp group by job having min(sal) > 1500; -- 正确

where和having子句的区别:

(1)相同点: wherehaving都可以对记录进行筛选过滤。
(2)区别:where是在分组之前,对记录进行筛选过滤,并且where子句中不能使用多行函数以及列别名(但是可以使用表别名)
(3)区别:having是在分组之后,对记录进行筛选过滤,并且having子句中可以使用多行函数以及列别名、表别名。

列出在每个部门就职的员工数量、平均工资。显示部门编号、员工数量,平均薪资。

-- 根据部门对员工进行分组, 统计每个组(部门)的人数和平均薪资
select dept_id, count(*), avg(sal) from emp group by dept_id;

查出至少有一个员工的部门,显示部门编号、部门名称、部门位置、部门人数。

-- 连接查询部门表和员工表
select d.id,d.name,d.loc from emp e,dept d
where e.dept_id=d.id;
-- 按照部门进行分组,统计部门人数
select d.id,d.name,d.loc,count(*) from emp e,dept d
where e.dept_id=d.id 
group by d.id 
having count(*) >= 1;

列出受雇日期早于直接上级的所有员工,显示员工编号、员工姓名、部门名称。

/* emp e1 员工表, emp e2 上级表, dept d 部门表
 * 显示的列: e1.id, e1.name, d.name
 * 查询的表: emp e1,emp e2,dept d
 * 连接条件: e1.topid=e2.id  e1.dept_id=d.id
 * 筛选条件: e1.hdate<e2.hdate
 */
select e1.id, e1.name, d.name
from emp e1,emp e2,dept d
where e1.topid=e2.id and e1.dept_id=d.id
	and e1.hdate<e2.hdate;

查询员工表中薪资最高的员工信息

select name, max(sal) from emp; -- 错误写法
select name,sal from emp order by sal desc limit 0,1; -- 正确写法
-- 求出emp表中的最高薪资
select max(sal) from emp;
-- 根据最高薪资到emp表中查询, 该薪资对应的员工信息
select * from emp where sal=(select max(sal) from emp);

十二 、数据库备份与恢复

1.备份数据库

在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行备份:

mysqldump -u用户名 -p 数据库的名字 > 备份文件的位置

示例1: 对db40库中的数据(表,表记录)进行备份,备份到 d:/db40.sql文件中

mysqldump -uroot -p db40 > d:/db40.sql

键入密码,如果没有提示,即表示备份成功!

也可以一次性备份所有库,例如:

对mysql服务器中所有的数据库进行备份,备份到 d:/all.sql文件中

mysqldump -uroot -p --all-database > d:/all.sql

键入密码,如果没有提示错误(警告信息不是错误,可以忽略),即表示备份成功!

2.恢复数据库

① 恢复数据库方式一:

在cmd窗口中(未登录的状态下),可以通过如下命令对指定的数据库进行恢复:

mysql -u用户名 -p 数据库的名字 < 备份文件的位置

示例:将d:/db40.sql文件中的数据恢复到db60库中

– 在cmd窗口中(已登录的状态下),先创建db60库:

create database db60 charset utf8;

– 在cmd窗口中(未登录的状态下)

mysql -uroot -p db60 < d:/db40.sql

② 恢复数据库方式二:

在cmd窗口中(已登录的状态下),可以通过source执行指定位置的SQL文件:

source sql文件的位置

示例:将d:/db40.sql文件中的数据恢复到db80库中

– 在cmd窗口中(已登录的状态下),先创建db80库,进入db80库:

create database db80 charset utf8;
use db80;

– 再通过source执行指定位置下的sql文件:

source d:/db40.sql

十三 、Navicat软件的使用

Navicat Premium是一套带图形用户界面的数据库管理工具,让你从单一应用程序中同时连接MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite数据库。使用Navicat可以快速、轻松地创建、管理和维护数据库。

1、使用navicat连接mysql服务器(使用cmd连接mysql服务器)
2、查看所有库、进入数据库、创建数据库、删除数据库、修改数据库
3、创建表、查看表、修改表、删除表
4、新增表记录、查询表记录、修改表记录、删除表记录
5、使用navicat书写SQL语句操作数据库、表和表记录
...

十四 、扩展内容

现创建学生表:

use test; -- 进入test库
drop table if exists stu; -- 删除学生表(如果存在)
create table stu( -- 创建学生表
    id int, -- 学生id
    name varchar(20), -- 学生姓名
    gender char(1), -- 学生性别
    birthday date -- 出生年月
);

1.修改表—新增列

语法:ALTER TABLE tabname ADD col_name datatype [DEFAULT expr][,ADD col_name datatype…];

1、往stu表中添加score列,double类型

alter table stu add score double;

2.修改表—修改列

语法:ALTER TABLE tabname MODIFY (col_name datatype [DEFAULT expr][,MODIFY col_name datatype]…);

1、修改id列,将id设置为主键

alter table stu modify id int primary key;

2、修改id列,将id主键设置为自动增长

alter table stu modify id int auto_increment;

3.修改表—删除列

语法:ALTER TABLE tabname DROP [COLUMN] col_name;

1、删除stu表中的score列

alter table stu drop score;

4.添加或删除主键及自增

思考:a) 在建表时,如何为id指定主键约束和自增?

b) 建好的表,如何通过修改添加主键约束和自增?

c) 如何删除表中的主键约束和自增?

1、创建stu学生表,不添加主键自增, 查看表结果

use mydb1; -- 切换到mydb1库
drop table if exists stu; -- 删除stu学生表(如果存在)
create table stu( -- 重建stu学生表,没有主键自增
    id int,
    name varchar(20),
    gender char(1),
    birthday date
);
desc stu; -- 查看表结构

表结构如下: 没有主键约束和自增。
在这里插入图片描述
2、如果表没有创建,或者要删除重建,在创建时可以指定主键或主键自增

drop table if exists stu; -- 删除stu表
create table stu( -- 重新创建stu表时,指定主键自增
    id int primary key auto_increment,
    name varchar(20),
    gender char(1),
    birthday date
);
desc stu; -- 查看表结构

表结构如下: 已经添加了主键约束和自增。
在这里插入图片描述
3、如果不想删除重建表,也可以通过修改表添加主键或主键自增

再次执行第1步,创建stu学生表,不添加主键自增,查看表结果

– 例如: 将stu学生表中的id设置为主键和自动增长

alter table stu modify id int primary key auto_increment;
desc stu; -- 查看表结构

在这里插入图片描述
如果只添加主键约束,不设置自增

alter table stu modify id int **primary key**;

如果已经添加主键约束,仅仅设置自增,但需注意:

(1)如果没有设置主键,不可添加自增

(2)只有当主键是数值时,才可以添加自增

alter table stu modify id int **auto_increment**;

4、如果想删除主键自增

– 删除主键自增时,要先删除自增

alter table stu modify id int;

– 再删除主键约束

alter table stu drop primary key;
desc stu; -- 查看表结构

在这里插入图片描述

5.添加外键约束

① 添加外键方式一:建表时添加外键

现有部门表如下:

– 创建部门表

create table dept(
	id int primary key auto_increment, -- 部门编号
	name varchar(20) -- 部门名称
);

要求创建员工表,并在员工表中添加外键关联部门主键

– 创建员工表

create table emp(
    id int primary key auto_increment, -- 员工编号
    name varchar(20), -- 员工姓名
    dept_id int, -- 部门编号
    foreign key(dept_id) references dept(id) -- 指定dept_id为外键
);

② 添加外键方式二:建表后添加外键

现有部门表和员工表:

– 创建部门表

create table dept(
    id int primary key auto_increment, -- 部门编号
    name varchar(20) -- 部门名称
);

– 创建员工表

create table emp(
    id int primary key auto_increment, -- 员工编号
    name varchar(20), -- 员工姓名
    dept_id int -- 部门编号
);

– 如果表已存在,可以使用下面这种方式:

alter table emp add constraint fk_dept_id foreign key(dept_id) references dept(id);

其中 fk_dept_id (名字由自己定义),是指外键约束名称,也可以将【constraint fk_dept_id】省略,MySQL会自动分配一个外键名称,将来可以通过该名称删除外键。

foreign key(dept_id)中的dept_id为外键

6. 删除外键约束

1、首先通过 “show create table 表名”语法,查询含有外键表的建表语句,例如:

show create table emp;

显示结果如下:
在这里插入图片描述
其中,emp_ibfk_1是在创建表时,数据库为外键约束指定的一个名字,删除这个名字即可删除外键关系,例如:

alter table emp drop foreign key emp_ibfk_1;

在这里插入图片描述
外键删除成功!

7.添加外键约束(多对多)

现有学生(stu)表和教师(tea)表:

创建学生表

create table stu(
    stu_id int primary key auto_increment, -- 学生编号
    name varchar(20) -- 学生姓名
);

创建教师表

create table tea(
	tea_id int primary key auto_increment, -- 教师编号
	name varchar(20) -- 教师姓名
);

添加第三方表(stu_tea)表示学生表和教师表关系

创建学生和教师关系表

create table stu_tea(
    stu_id int, -- 学生编号
    tea_id int, -- 教师编号
    primary key(stu_id,tea_id), -- 设置联合主键
    foreign key(stu_id) references stu(stu_id), -- 添加外键
    foreign key(tea_id) references tea(tea_id) -- 添加外键
);

其中为了防止重复数据,将stu_id和tea_id设置为联合主键。

将stu_id设置为外键,参考stu表中的stu_id列

并将tea_id设置为外键,参考tea表中的tea_id列

8.级联更新、级联删除

创建db20库、dept表、emp表并插入记录

删除db20库(如果存在),并重新创建db20库

drop database if exists db20;
create database db20 charset utf8;
use db20;

创建部门表, 要求id, name字段

create table dept(
	id int primary key auto_increment, -- 部门编号
	name varchar(20) -- 部门名称
);

往部门表中插入记录

insert into dept values(null, '财务部');
insert into dept values(null, '人事部');
insert into dept values(null, '科技部');
insert into dept values(null, '销售部');

创建员工表, 要求id, name, dept_id

create table emp(
    id int primary key auto_increment, -- 员工编号
    name varchar(20), -- 员工姓名
    dept_id int, -- 部门编号
    foreign key(dept_id) references dept(id) -- 指定外键
    on update cascade -- 级联更新
    on delete cascade -- 级联删除
);
insert into emp values(null, '张三', 1);
insert into emp values(null, '李四', 2);
insert into emp values(null, '老王', 3);
insert into emp values(null, '赵六', 4);
insert into emp values(null, '刘能', 4);

级联更新:主表(dept表)中的主键发生更新时(例如将销售部的id改为40),从表(emp表)中的记录的外键数据也会跟着该表(即赵六和刘能的部门编号也会更新为40)

级联删除:如果不添加级联删除,当删除部门表中的某一个部门时(例如删除4号部门),若该部门在员工表中有对应的员工(赵六和刘能),删除会失败!

若果添加了级联删除,当删除部门表中的某一个部门时,若该部门在员工表中有对应的员工,会在删除部门的同时,将员工表中对应的员工也删除!

9.where中不能使用列别名

① SQL语句的书写顺序

select * | 列名 -- 确定要查询的列有哪些
from 表名 -- 确定查询哪张表
where 条件 -- 通过筛选过滤,剔除不符合条件的记录
group by 分组的列 -- 指定根据哪一列进行分组
having 条件 -- 通过条件对分组后的数据进行筛选过滤
order by 排序的列 -- 指定根据哪一列进行排序
limit (countPage-1)*rowCount, rowCount -- 指定返回第几页记录以及每页显示多少条

② SQL语句的执行顺序:

from 表名 -- 确定查询哪张表
where 条件 -- 通过筛选过滤,剔除不符合条件的记录
select * | 列名 列别名 -- 确定要查询的列有哪些,
group by 分组的列 -- 指定根据哪一列进行分组
having 条件 -- 通过条件对分组后的数据进行筛选过滤
order by 排序的列 -- 指定根据哪一列进行排序
limit (countPage-1)*rowCount, rowCount

关于where中不能使用列别名但是可以使用表别名?

是因为,表别名是声明在from中,from先于where执行,先声明再使用没有问题,但是列别名是声明在select中,where先于select执行,如果先使用列别名,再声明,这样执行会报错!!

第二章 JDBC

一 、JDBC概述

1.什么是JDBC?为什么要学习JDBC?

JDBC(Java DataBase Connectivity) Java数据库连接

其实就是利用Java语言/程序连接并访问数据库的一门技术

之前我们可以通过CMD或者navicat等工具连接数据库

但在企业开发中,更多的是通过程序(Java程序)连接并访问数据库,通过Java程序访问数据库,就需要用到JDBC这门技术。
在这里插入图片描述

2.如何通过JDBC程序访问数据库?

① 提出需求:

创建一个 jt_db 数据库,在库中创建一个account表,并插入三条记录,然后利用Java程序查询出account表中所有的记录,并将查询的结果打印在控制台上。

② 开发步骤:

(1)准备数据, 创建jt_db库, 创建account表

drop database if exists jt_db;
create database jt_db charset utf8;
use jt_db;
create table account(
    id int primary key auto_increment,
    name varchar(50),
    money double
);
insert into account values(null, 'tom', 1000);
insert into account values(null, 'andy', 1000);
insert into account values(null, 'tony', 1000);

在这里插入图片描述

③ 代码实现:

public static void main(String[] args) throws Exception {
   
    //1.注册数据库驱动
    Class.forName("com.mysql.jdbc.Driver");
    //2.获取数据库连接
    Connection conn = DriverManager.getConnection(
        "jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8",
        "root", "root");
    //3.获取传输器
    Statement stat = conn.createStatement();
    //4.发送SQL到服务器执行并返回执行结果
    String sql = "select * from account";
    ResultSet rs = stat.executeQuery( sql );
    //5.处理结果
    while( rs.next() ) {
   
        int id = rs.getInt("id");
        String name = rs.getString("name");
        double money = rs.getDouble("money");
        System.out.println(id+" : "+name+" : "+money);
    }
    //6.释放资源
    rs.close();
    stat.close();
    conn.close();
    System.out.println("TestJdbc.main()....");
}

④ 执行结果:

在这里插入图片描述

3.JDBC API总结

① 注册数据库驱动

Class.forName(“com.mysql.jdbc.Driver”);

所谓的注册驱动,就是让JDBC程序加载mysql驱动程序,并管理驱动

驱动程序实现了JDBC API定义的接口以及和数据库服务器交互的功能,加载驱动是为了方便使用这些功能。

② 获取连接之数据库URL

Connection conn = DriverManager.getConnection(
    "jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8",
    "root", "root" );

DriverManager.getConnection() 用于获取数据连接,返回的Connection连接对象是JDBC程序连接数据库至关重要的一个对象。

参数2参数3分别是所连接数据库的用户名和密码。

参数1:“jdbc:mysql://localhost:3306/jt_db” 是连接数据库的URL,用于指定访问哪一个位置上的数据库服务器及服务器中的哪一个数据库,其写法为:

在这里插入图片描述
当连接本地数据库,并且端口为3306,可以简写为如下形式:

jdbc:mysql:///jt_db

③ Statement传输器对象

Statement stat = conn.createStatement();
该方法返回用于向数据库服务器发送sql语句的Statement传输器对象

该对象上提供了发送sql的方法:

executeQuery(String sql) --
用于向数据库发送查询类型的sql语句,返回一个ResultSet对象中
executeUpdate(String sql) --
用于向数据库发送更新(增加、删除、修改)类型的sql语句,返回一个int值,表示影响的记录行数

④ ResultSet结果集对象

ResultSet对象用于封装sql语句查询的结果,也是一个非常重要的对象。该对象上提供了遍历数据及获取数据的方法。

(1)遍历数据行的方法

next() – 使指向数据行的箭头向下移动一行,并返回一个布尔类型的结果,true表示箭头指向了一行数据,false表示箭头没有指向任何数据(后面也没有数据了)

(2)获取数据的方法

getInt(int columnIndex)
getInt(String columnLable)
getString(int columnIndex)
getString(String columnLable)
getDouble(int columnIndex)
getDouble(String columnLable)
getObject(int columnIndex)
getObject(String columnLable)

⑤ 释放资源

rs.close();
stat.close();
conn.close();

此处释放资源必须按照一定的顺序释放,越晚获取的越先关闭。所以先关闭
rs对象,再关闭stat对象,最后关闭conn对象。

另,为了避免上面的程序抛出异常,释放资源的代码不会执行,应该把释放资源的代码放在finally块中.

try{
   
	...
}catch(Exception e){
   
	...
}finally{
   
    if (rs != null) {
   
        try {
   
        	rs.close();
        } catch (SQLException e) {
   
            e.printStackTrace();
        } finally {
   
            rs = null;
        }
    }
    if (stat != null) {
   
        try {
   
        	stat.close();
        } catch (SQLException e) {
   
            e.printStackTrace();
        } finally {
   
            stat = null;
        }
    }
    if (conn != null) {
   
        try {
   
        	conn.close();
        } catch (SQLException e) {
   
            e.printStackTrace();
        } finally {
   
            conn = null;
        }
    }
}

二 、增删改查

1.新增:往account表中添加一个名称为john、money为3500的记录

JDBCUtil工具类

package com.tedu.util;

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

/** JDBC工具类 */
public class JdbcUtil {
   
	/**
	 * 获取数据库连接对象并返回
	 * @return Connection对象
	 * @throws Exception 
	 */
	public static Connection getConn() throws Exception{
   
		//1.注册驱动
		Class.forName( "com.mysql.jdbc.Driver" );
		//2.获取连接
		Connection conn = DriverManager.getConnection(
				"jdbc:mysql:///jt_db?characterEncoding=utf-8", 
				"root", 
				"root");
		return conn;
	}
	
	/**
	 * 释放JDBC程序中的资源
	 * @param conn 连接对象
	 * @param stat 传输器对象
	 * @param rs 结果集对象
	 */
	public static void close(Connection conn, 
			Statement stat, ResultSet rs){
   
		if(rs != null){
   
			try {
   
				rs.close();
			} catch (SQLException e) {
   
				e.printStackTrace();
			} finally{
   
				rs = null;
			}
		}
		if(stat != null){
   
			try {
   
				stat.close();
			} catch (SQLException e) {
   
				e.printStackTrace();
			} finally{
   
				stat = null;
			}
		}
		if(conn != null){
   
			try {
   
				conn.close();
			} catch (SQLException e) {
   
				e.printStackTrace();
			} finally{
   
				conn = null;
			}
		}
	}
}
/* 1、新增:往account表中添加一个名称为john、money为3500的记录 */
@Test
public void testInsert() {
   
	Connection conn = null;
	Statement stat = null;
	ResultSet rs = null;
	try {
   
		//注册驱动并获取连接
		conn = JdbcUtil.getConn();
		//获取传输器
		stat = conn.createStatement();
		//发送sql语句到服务器执行,并返回执行结果
		String sql = "insert into account values(null, 'john', 3500)";
		int rows = stat.executeUpdate( sql );
		//处理结果
		System.out.println( "影响行数: "+rows );
	} catch (Exception e) {
   
		e.printStackTrace();
	} finally {
   
		//通过JdbcUtil工具类中的close方法释放资源
		JdbcUtil.close(conn, stat, rs);
	}
}

2.修改:将account表中名称为john的记录,money修改为1500

/* 2、修改:将account表中名称为john的记录,money修改为1500 */
@Test
public void testUpdate() {
   
	Connection conn = null;
	Statement stat = null;
	ResultSet rs = null;
	try {
   
		//注册驱动并获取连接
		conn = JdbcUtil.getConn();
		//获取传输器
		stat = conn.createStatement();
		//发送sql语句到服务器执行,并返回执行结果
		String sql = "update account set money=1500 where name='john'";
		int rows = stat.executeUpdate( sql );
		//处理结果
		System.out.println( "影响行数: "+rows );
	} catch (Exception e) {
   
		e.printStackTrace();
	} finally {
   
		//通过JdbcUtil工具类中的close方法释放资源
		JdbcUtil.close(conn, stat, rs);
	}
}

3.查询:查询account表中名称为john的记录

/* 3、查询:查询account表中id为1的记录 */
@Test
public void testFindById() {
   
	Connection conn = null;
	Statement stat = null;
	ResultSet rs = null;
	try {
   
		//注册驱动并获取连接
		conn = JdbcUtil.getConn();
		//获取传输器
		stat = conn.createStatement();
		//执行sql语句,返回执行结果
		String sql = "select * from account where id=1";
		rs = stat.executeQuery( sql );
		//处理结果
		if( rs.next() ) {
   
			int id = rs.getInt("id");
			String name = rs.getString("name");
			double money = rs.getDouble("money");
			System.out.println( id+" : "+name+" : "+money);
		}
	} catch (Exception e) {
   
		e.printStackTrace();
	} finally {
   
		JdbcUtil.close(conn, stat, rs);
	}
}

4.删除:删除account表中名称为john的记录

/* 4、删除:删除account表中名称为john的记录 */
@Test
public void testDelete() {
   
	Connection conn = null;
	Statement stat = null;
	ResultSet rs = null;
	try {
   
		//注册驱动并获取连接
		conn = JdbcUtil.getConn();
		//获取传输器
		stat = conn.createStatement();
		//发送sql语句到服务器执行,并返回执行结果
		String sql = "delete from account where name='john'";
		int rows = stat.executeUpdate( sql );
		//处理结果
		System.out.println( "影响行数: "+rows );
	} catch (Exception e) {
   
		e.printStackTrace();
	} finally {
   
		//通过JdbcUtil工具类中的close方法释放资源
		JdbcUtil.close(conn, stat, rs);
	}
}

5.单元测试补充

单元测试:不用创建新的类,也不用提供main函数,也不用创建类的实例,就可以直接执行一个方法

加了@Test注解的方法,可以通过单元测试(junit)框架测试该方法。底层会创建该方法所在类的实例,通过实例调用该方法。

@Test
public void testInsert() {
   
	System.out.println("TestPreparedStatement.testInsert()");
}

能够使用@Test单元测试测试的方法必须满足如下几个条件:

(1)方法必须是公共的
(2)方法必须是非静态的
(3)方法必须是无返回值的
(4)方法必须是无参数的
(5)进行单元测试的方法或类,命名时不要命名为 Test/test

三、 PreparedStatement

在上面的增删改查的操作中,使用的是Statement传输器对象,而在开发中我们用的更多的传输器对象是PreparedStatement对象,PreparedStatement是Statement的子接口,比Statement更加安全,并且能够提高程序执行的效率。

Statement 父对象

PreparedStatement 子对象

1.模拟用户登录案例

(1)准备数据

use jt_db;
create table user(
    id int primary key auto_increment,
    username varchar(50),
    password varchar(50)
);
insert into user values(null,'张三','123');
insert into user values(null,'李四','234');

(2)创建LoginUser 类,提供 main 方法 和 login 方法。

public static void main(String[] args) {
   
	/* 1、提示用户登录,提示用户输入用户名并接收用户名
	 *  2、提示用户输入密码并接收密码
	 *  3、根据用户名和密码查询用户信息
	 */
	// 1、提示用户登录,提示用户输入用户名并接收用户名
	Scanner sc = new Scanner(System.in);
	System.out.println( "请登录:" );
	System.out.println( "请输入用户名:" );
	String user = sc.nextLine();
	
	// 2、提示用户输入密码并接收密码
	System.out.println( "请输入密码:" );
	String pwd = sc.nextLine();
	
	// 3、根据用户名和密码查询用户信息
	login( user, pwd );
}
/**
 * 根据用户名和密码查询用户信息
 * @param user 用户名
 * @param pwd 密码
 */
private static void login(String user, String pwd) {
   
	Connection conn = null;
	Statement stat = null;
	ResultSet rs = null;
	try {
   
		//1.注册驱动并获取连接
		conn = JdbcUtil.getConn();
		//2.获取传输器,执行sql并返回执行结果
		stat = conn.createStatement();
		String sql = "select * from user where username='"+user+"' and password='"+pwd+"'";
		rs = stat.executeQuery(sql);
		System.out.println( sql );
		//3.处理结果
		if( rs.next() ) {
    //有数据 -- 用户名密码都正确
			System.out.println("恭喜您登录成功!");
		}else {
    //没数据 -- 用户名或密码不正确
			System.out.println("登录失败, 用户名或密码不正确!");
		}
	} catch (Exception e) {
   
		e.printStackTrace();
	} finally {
   
		//4.释放资源
		JdbcUtil.close(conn, stat, rs);
	}
}

执行时,输入:

请登录:
请输入用户名:
张三'#'
请输入密码:

select * from user where username='张三'#'' and password=''
恭喜您登录成功了!

或输入

请登录:
请输入用户名:
张三' or '1=1
请输入密码:

select * from user where username='张三' or '1=1' and password=''
恭喜您登录成功了!

或输入

请登录:
请输入用户名:

请输入密码:

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值