MySQL
JavaEE : 企业级Java开发 Web
后台:连接点:链接数据库JDBC、连接前端(控制视图跳转,给前端传递数据)
数据库:存数据
1.1 为什么学习数据库
-
岗位需求
-
大数据时代:得数据者得天下
-
需求:存数据
-
数据库是所有软件体系中最核心的存在
1.2 什么是数据库
数据库(DB DataBase)
概念:数据仓库 软件(安装在操作系统之上) SQL可以存储大量的数据
作用:存储数据,管理数据
1.3 数据库分类
关系型数据库: (SQL)
-
MySQL、Oracle、SQL server......
-
通过表和表之间,行和列之间的关系进行数据的存储
非关系型数据库: (NOSQL) NO:Not Only
-
Redis、MongDB
-
对象存储,通过对象自身的属性来决定
DBMS(数据库管理系统)
-
数据库的管理软件,科学有效的管理我们的数据,维护和获取数据
-
MySQL,数据库管理系统
1.4 MySQL简介
-
MySQL是一个关系型数据库管理系统
-
由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品
-
在 WEB应用方面,MySQL是最好的 RDBMS 应用软件之一
-
体积小、速度快、总体拥有成本低
-
开放源码的数据库软件
1.5 安装MySQL、SQLyog并使用
安装MySQL、SQLyog 略
操作SQLyog:
-
新建一个数据库:school
-
新建一张表:student
字段:id name age
-
查看表
-
1.6 连接数据库
基本的命令行操作:
mysql -uroot -proot --连接数据库
update mysql.user set authentication_string=password('root') where user='root' and Host = 'localhost'; --修改用户密码
flush privileges; --刷新权限
---------------------------------------
-- 所有的sql语句都要使用;结尾
show databases; --查看所有的数据库
use school; --切换数据库 use 数据库名
show tables; --查看数据库中所有的表
describe student; --显示数据库中所有的表得信息
create database teacher; --创建一个teacher数据库
exit; --退出连接
DxL :数据库xxx语言
DDL 数据库定义语言 DML 操作 DQL 查询 DCL 控制
2. 操作数据库
操作数据库 > 操作数据库中的表 > 操作数据库中表的数据
mysql关键字不区分大小写
2.1 操作数据库(了解)
-
创建数据库
CREATE DATABASE teacher;
-
删除数据库
DROP DATABASE teacher;
-
使用数据库
-- `` tab键的上面 如果表名或者字段名是一个特殊字符,就需要带上
USE `school`; -
查看数据库
SHOW DATABASES; --查看所有的数据库
学习思路:
-
对照sqlyog的历史记录可以查看sql语句
-
固定的语法或关键字必须强行记住
2.2 数据库的列类型
数值
常用的:
-
int 标准的整数 4个字节
-
float 浮点数 4个字节
-
double 浮点数 8个字节 (存在精度问题)
-
decimal 字符串形式的浮点数 金融计算的时候 用decimal
字符串
-
varchar 可变字符串 0-65535
-
tinytext 微型文本 2^8-1
-
text 文本串 2^16-1 保存大文本
时间日期
java.util.Date
-
date YYYY-MM-DD 日期格式
-
time HH:mm:ss 时间格式
-
datetime YYYY-MM-DD HH:mm:ss
-
timestamp 时间戳 1970.1.1到现在的毫秒数
-
year 年份表示
null
-
没有值 未知
-
注意:不要使用NULL进行运算,结果为NULL
2.3 数据库的字段属性(重点)
Unsigned
-
无符号的整数
-
声明了该列不能为负数
Zerofill
-
0填充
-
不足的位数。使用0来填充 例:int(2) 1-->01
AUTO_INCREMENT
-
自增 自动在上一条记录的基础上 +1 (默认是0,可以更改)
-
通常用来设计唯一的主键 必须是整数类型
Not Null / NULL
-
假设设置为 not null 如果不给它赋值,就会报错
-
NULL 如果不填写值,默认就是NULL
Default
-
设置默认的值
-
例:sex 如果设置默认值为男,如果不指定该列的值,则默认值就是男
补充:阿里的建表规范
必须有的:
/*
每个表,都必须存在以下五个字段,表示每个记录都存在意义
*/
id 主键
`version` 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间
2.4 创建数据库(重点)
小案例:
-- 目标:创建一个school数据库
-- 创建学生表(列、字段) student
-- 学号 姓名 性别 密码 出生日期 家庭住址 email
CREATE TABLE `student`(
`id` INT(3) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`sex` VARCHAR(3) NOT NULL DEFAULT '男' COMMENT '性别',
`psw` VARCHAR(6) NOT NULL DEFAULT '123456' COMMENT '密码',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(120) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(30) DEFAULT NULL COMMENT '邮箱地址',
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
注意:
-
括号使用英文的 表的名称、字段最好使用``括起来(tab键上边那个)
-
字符串使用,单引号括起来
-
所有的语句后面加 , (英文的),最后一个不用加
-
PRIMARY KEY (主键) 主键用括号括起来
格式:
CREATE TABLE `表名`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
......
`字段名` 列类型 [属性] [索引] [注释]
)
SHOW CREATE DATABASE school -- 查看创建数据库的语句 SHOW CREATE TABLE student -- 查看创建student数据表的语句 DESC student -- 显示表的结构
2.5 数据表的类型
-- 关于引擎 INNODB 默认使用 MYISAM 早些年使用
MYISAM | INNODB | |
---|---|---|
事务支持 | 不支持 | 支持 |
数据行锁定 | 不支持 | 支持 |
外键约束 | 不支持 | 支持 |
全文索引 | 支持 | 不支持 |
表空间的大小 | 较小 | 较大 约为MYISAM的两倍 |
常规使用操作:
-
MYISAM 节省空间 速度较快
-
INNODB 安全性高 事务的处理 多表多用户操作
所有的数据库文件都存储在data目录下,一个文件夹对应一个数据库,本质上还是文件的存储
设置数据库表的字符集编码
CHAESET=utf8
MySQL的默认编码是Latin1,不支持中文
2.6 修改、删除表
修改
-- 修改表名:ALTER TABLE 旧表名 RENAME AS 新表名 ALTER TABLE student RENAME AS students -- 增加表的字段:ALTER TABLE 表名 ADD 字段名 列属性 ALTER TABLE students ADD age INT(3) -- 修改表的字段(重用名、约束) -- MODIFY 修改约束 ALTER TABLE 表名 MODIFY 字段名 列属性 ALTER TABLE students MODIFY age VARCHAR(3) -- CHANGE 字段重用名 ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性 ALTER TABLE students CHANGE age age1 INT(3)
删除
-- 删除表的字段:ALTER TABLE 表名 DROP 字段名 ALTER TABLE students DROP age1 -- 删除表:DROP TABLE 表名 DROP TABLE students
3. MySQL数据管理
3.1 外键(了解即可)
方式一:在创建表的时候,增加约束
-- 创建一个年级表 与学生表通过外键关联起来 CREATE TABLE `grade`( `gradeid` INT(3) NOT NULL AUTO_INCREMENT COMMENT '年级id', `gradename` VARCHAR(20) NOT NULL COMMENT '年级名称', PRIMARY KEY (`gradeid`) )ENGINE=INNODB DEFAULT CHARSET=utf8 -- 学生表的gradeid字段 去引用年级表的gradeid -- 定义外键key -- 给这个外键加约束(执行引用) references 引用 foreign key 外键 CREATE TABLE `students` ( `id` INT(3) NOT NULL AUTO_INCREMENT COMMENT '学号', `name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名', `sex` VARCHAR(3) NOT NULL DEFAULT '男' COMMENT '性别', `psw` VARCHAR(6) NOT NULL DEFAULT '123456' COMMENT '密码', `birthday` DATETIME DEFAULT NULL COMMENT '出生日期', `address` VARCHAR(120) DEFAULT NULL COMMENT '家庭住址', `email` VARCHAR(30) DEFAULT NULL COMMENT '邮箱地址', `gradeid` INT(3) NOT NULL COMMENT '年级id', PRIMARY KEY (`id`), KEY `FK_gradeid` (`gradeid`), CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`) ) ENGINE=INNODB DEFAULT CHARSET=utf8
删除有外键关系的表的时候,必须先删除引用的表,再删除被引用的表
方式二:创建表成功后,添加外键约束
-- 创建一个年纪表 与学生表通过外键关联起来 CREATE TABLE `grade`( `gradeid` INT(3) NOT NULL AUTO_INCREMENT COMMENT '年级id', `gradename` VARCHAR(20) NOT NULL COMMENT '年级名称', PRIMARY KEY (`gradeid`) )ENGINE=INNODB DEFAULT CHARSET=utf8 -- 学生表的gradeid字段 去引用年级表的gradeid CREATE TABLE `students` ( `id` INT(3) NOT NULL AUTO_INCREMENT COMMENT '学号', `name` VARCHAR(20) NOT NULL DEFAULT '匿名' COMMENT '姓名', `sex` VARCHAR(3) NOT NULL DEFAULT '男' COMMENT '性别', `psw` VARCHAR(6) NOT NULL DEFAULT '123456' COMMENT '密码', `birthday` DATETIME DEFAULT NULL COMMENT '出生日期', `address` VARCHAR(120) DEFAULT NULL COMMENT '家庭住址', `email` VARCHAR(30) DEFAULT NULL COMMENT '邮箱地址', `gradeid` INT(3) NOT NULL COMMENT '年级id', PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 -- 定义外键key -- 给这个外键加约束(执行引用) references 引用 foreign key 外键 -- ALTER TABLE 表名 ADD CONSTRAINT `FK_字段名` FOREIGN KEY(`字段名`) REFERENCES `被引用的表名`(`字段名`); ALTER TABLE `students` ADD CONSTRAINT `FK_gradeid` FOREIGN KEY(`gradeid`) REFERENCES `grade`(`gradeid`);
以上的操作都是物理外键,数据库级别的外键,不建议使用!(避免数据库过多造成困扰)
最佳实践:
-
数据库就是单纯的表,只用来存数据,只有行(数据),列(字段)
-
我们想使用多张表的数据,想使用外键,可以用程序去实现
3.2 DML语言(重点)
数据库意义:数据存储,数据管理
DML语言:数据操作语言
-
insert
-
update
-
delete
添加 insert
语法:INSERT INTO 表名(字段名1,字段名2,字段名3,......) VALUES('值1','值2','值3',......);
-- 插入语句 -- 语法:INSERT INTO 表名(字段名1,字段名2,字段名3,......) VALUES('值1','值2','值3',......) -- 如果设置主键自增,可以省略 INSERT INTO `grade`(`gradename`) VALUES('大三') -- 字段名与值按写的顺序一一匹配,写的时候要一一对应 INSERT INTO `students`(`name`,`psw`,`address`) VALUES('张三','13142','河北省石家庄市') INSERT INTO `students`(`name`,`sex`,`psw`,`birthday`,`address`,`email`,`gradeid`) VALUES('胖丫','女','666666','2000-1-6','河北省衡水市','6666666@qq.com','1') -- 全字段添加 可以省略字段名,数值会根据数据表所有字段按顺序一一对应 INSERT INTO `students` VALUES('3','菲菲','女','888888','2002-6-18','河北省衡水市','888888@qq.com','3') INSERT INTO `grade`(`gradename`) VALUES('大一') INSERT INTO `grade`(`gradename`) VALUES('大二') INSERT INTO `grade`(`gradename`) VALUES('大四') INSERT INTO `students`(`name`,`sex`,`email`,`psw`) VALUES('牛牛','男','66986@qq.com','669652')
修改 update
语法:UPDATE 表名 SET 字段名1=值1,字段名2=值2,字段名3=值3 WHERE 条件;
-- update 修改 set 字段=值 UPDATE `grade` SET `gradename`='大一' WHERE `gradeid`='1'; -- 不指定条件的情况下,会改动所有的表 UPDATE `grade` SET `gradename`='大一'; -- 修改多个属性,英文,隔开 UPDATE `students` SET `name`='超超',`psw`='211314',`address`='河北省衡水市',`email`='zcc2671185030@qq.com',`gradeid`='3' WHERE `id`='1'; -- 语法:UPDATE 表名 SET 字段名1=值1,字段名2=值2,字段名3=值3 WHERE 条件;
条件:where语句
操作符 | 含义 | 范围 | 结果 |
---|---|---|---|
= | 等于 | 5=3 | false |
<> 或 != | 不等于 | 5=3 | true |
> | 大于 | 5>3 | true |
< | 小于 | 5<3 | false |
>= | 大于等于 | 5>=3 | true |
<= | 小于等于 | 5<=3 | false |
BETWEEN...AND... | 双闭合区间 | [2,5] | |
AND | && 我和你 | 5>3 and 1>2 | false |
OR | || 我或你 | 5>3 or 1>2 | true |
-- 可以通过多个条件锁定数据 CURRENT_DATE:当前系统日期 UPDATE `students` SET `birthday`=CURRENT_DATE WHERE `sex`='女' OR `gradeid`='3';
删除 delete
语法:DELETE FROM 表名 WHERE 条件
-- 删除指定数据 DELETE FROM `students` WHERE `id`='4' -- 删除数据表 (避免这样写 会全部删除) DELETE FROM `students` -- 而且清除数据表数据的话 推荐用truncate命令 TRUNCATE TABLE `students` -- 这两个命令 DELETE、TRUNCATE都能清除整个数据表的命令 但是有区别 -- DELETE删除后,自增的字段不会清空,但是重新启动数据库后会清空,因为是存在缓存里的 -- TRUNCATE删除后,自增的字段会清空,再从1开始
4. DQL 查询语句(最重点)
4.1 DQL
(DATE QUERY LANGUAGE :数据查询语言)
-
所有的查询操作都用它 select
-
简单的查询 复杂的查询它都能做
-
数据库中最核心的语言 最重要的语句
-
使用频率最高的语句
select语法:
4.2 查询指定字段
语法:SELECT 字段名,...... FROM 表名
还可以通过as起别名
-- 查询全部的学生 SELECT * FROM `student` -- 查询所有的字段 SELECT `studentno`,`studentname` FROM `student` -- 别名 给结果起一个别名 AS 可以给字段起别名,也可以给表起别名 SELECT `studentno` AS `学号`,`studentname` AS `姓名` FROM `student` AS `学生` -- 函数 Concat(a,b) SELECT CONCAT('姓名:',`studentname`) AS `学生姓名` FROM `student`
去重:distinct
作用:去除SELECT查询出来的结果中重复的数据(重复的数据只显示一条)
-- 任务:查看有哪些同学参加了考试 SELECT * FROM `result` -- 查询全部的考试成绩 SELECT `studentno` FROM `result` -- 查询有哪些同学参加了考试 SELECT DISTINCT `studentno` FROM `result` -- 去重
数据库的列(表达式)
SELECT VERSION() -- 查看系统版本 SELECT 100/3 AS `结果` -- 用来计算 SELECT @@auto_increment_increment -- 查询自增的步长(变量) -- 设置所有学生的考试成绩+1 并查看 SELECT `studentno`,`studentresult`+1 AS '新成绩' FROM `result`
数据库中的表达式:文本值、列、null、函数、计算表达式、系统变量......
select 表达式 from 表
4.3 where条件子句
作用:检索数据中符合条件
的值
搜索的条件由一个或者多个表达式组成 结果为布尔值
逻辑运算符
运算符 | 语法 | 描述 |
---|---|---|
and && | a and b a && b | 逻辑与,两个都为真,结果为真 |
or || | a or b a || b | 逻辑或,两个都为假,结果为假 |
not ! | not a !a | 逻辑非 真为假 ,假为真 |
尽量使用英文字母
-- 查询考试成绩在95到100之间的学生 SELECT `studentno` FROM `result` WHERE `studentresult`>=95 AND `studentresult`<=100 -- and 和 && 作用一样 SELECT `studentno` FROM `result` WHERE `studentresult`>=95 && `studentresult`<=100 -- 模糊查询 (区间) between and SELECT `studentno` FROM `result` WHERE `studentresult` BETWEEN 95 AND 100 -- != not SELECT DISTINCT `studentno` FROM `result` WHERE `studentno` !=1000
模糊查询:比较运算符
运算符 | 语法 | 描述 |
---|---|---|
is null | a is null | 如果操作符为null,结果为真 |
is not null | a is not null | 如果操作符不为null,结果为真 |
between...and... | a between b and c | 若a在b和c之间,结果为u真 |
like | a like b | SQL匹配 如果a匹配b,则结果为真 |
in | a in(a1,a2,a3.....) | 假设a在a1,或者a2......其中的一个值中,结果为真 |
注意:判断为null时候,如果是varchar类型,注意加上空字符串''
% _ 是在like上用的
-
%:0到任意个字符
-
_:一个字符
-- 查询姓张的同学 -- like 结合 % _ SELECT studentname FROM student WHERE studentname LIKE '张%'; -- 查询姓张的、两个字的同学 SELECT studentname FROM student WHERE studentname LIKE '张_'; -- 查询名字中带有 强 字的同学 SELECT studentname FROM student WHERE studentname LIKE '%强%'; -- in 具体的一个或者多个值 -- 查询 赵强、张三、王五 这三个学生的信息 SELECT * FROM student WHERE studentname IN('赵强','张三','王五'); -- 查询在河北衡水的同学 SELECT studentname FROM student WHERE address IN('河北衡水'); -- 查询地址为空的同学 SELECT studentname FROM student WHERE address IS NULL OR address='';
4.4 联表查询
JOIN 对比
7种JOIN理论
-- 联表查询 join -- 查询参加了考试的同学(学号、姓名、科目、分数) SELECT * FROM `student` SELECT * FROM `result` /*思路: 1. 分析需求,分析查询的字段来自哪些表(联结查询) 2. 确定使用哪种连接查询 共7种 3. 确定交叉点(这两个表哪些数据是相同的) 4. 判断的条件:学生表中的studentno=成绩表中的studentno */ -- INNER JOIN 找共同有的 SELECT s.studentno,`studentname`,`subjectno`,`studentresult` FROM `student` AS s INNER JOIN `result` AS r ON s.studentno=r.studentno; -- LEFT JOIN 所有左表全部数据,找右边有的 但是没有成绩的也被显示出来了 SELECT s.studentno,`studentname`,`subjectno`,`studentresult` FROM `student` AS s LEFT JOIN `result` AS r ON s.studentno=r.studentno -- RIGHT JOIN 所有右表全部数据,找左边有的 SELECT s.studentno,`studentname`,`subjectno`,`studentresult` FROM `student` AS s RIGHT JOIN `result` AS r ON s.studentno=r.studentno -- 查询缺考的同学 SELECT s.studentno,`studentname`,`subjectno`,`studentresult` FROM `student` AS s LEFT JOIN `result` AS r ON s.studentno=r.studentno WHERE studentresult IS NULL
操作 | 描述 |
---|---|
INNER JOIN | 如果表中至少有一个匹配,就返回行 |
LEFT JOIN | 会从左表中返回所有的值,即使右表没有匹配 |
RIGHT JOIN | 会从右表中返回所有的值,即使左表没有匹配 |
JOIN ON 连接查询
JOIN WHERE 等值查询
-- 思考题:查询参加考试的学生信息:学号、姓名、科目名、分数 SELECT s.studentno,studentname,subjectname,studentresult FROM student s RIGHT JOIN result r ON s.studentno=r.studentno INNER JOIN `subject` sub ON r.subjectno=sub.subjectno /* 小结 我要查询哪些数据 select.... 从哪几个表中查 from 表 xxx join 连接的表 on 交叉条件 假设存在多张表查询,慢慢来,先查询两张表然后慢慢增加 */
自连接
自己的表和自己的表连接,核心:一张表拆为两张一样的表即可
原表:
拆分:
父类表:
categoryid | categoryname |
---|---|
2 | 信息技术 |
3 | 软件开发 |
5 | 美术设计 |
子类表:
pid | categoryid | categoryname |
---|---|---|
3 | 4 | 数据库 |
2 | 8 | 办公信息 |
3 | 6 | web开发 |
5 | 7 | ps技术 |
操作:查询父类对应的子类关系
父类 | 子类 |
---|---|
信息技术 | 办公信息 |
软件开发 | 数据库 |
软件开发 | web开发 |
美术设计 | ps技术 |
sql语句:
-- 查询父子信息 SELECT f.categoryname AS '父',z.categoryname AS '子' FROM category f,category z WHERE f.categoryid=z.pid
练习:
-- 查询学生所属的年级:学号、姓名、年级名称 SELECT studentno,studentname,gradename FROM student s LEFT JOIN grade g ON s.gradeid=g.gradeid -- 查询科目所属的年级(科目名称、年级名称) SELECT subjectname,gradename FROM `subject` s INNER JOIN grade g ON s.gradeid=g.gradeid -- 查询了参加 高等数学-1 考试的学生信息:学号、姓名、科目名、分数 SELECT s.studentno,studentname,subjectname,studentresult FROM student s RIGHT JOIN `result` r ON s.studentno=r.studentno INNER JOIN `subject` sub ON r.subjectno=sub.subjectno WHERE subjectname='高等数学-1'
4.5 分页和排序
排序
-- 需求:找到所有参加‘高等数学-1’考试的学生,并把成绩排序 -- 排序 order by 通过哪个字段 怎么排 (不写的话默认是升序) -- 查询的结果: 升序 ASC 降序 DESC SELECT studentname,subjectname,studentresult FROM student s RIGHT JOIN result r ON s.studentno=r.studentno INNER JOIN `subject` sub ON r.subjectno=sub.subjectno WHERE subjectname='高等数学-1' ORDER BY studentresult DESC
分页
语法: LIMIT (n-1)*pageSize,n
-- 为什么分页? 1. 缓解数据库压力 2. 给用户更佳的体验 -- 需求:分页 每页显示2条数据 -- 语法 limit 开始的下标 每页显示的几条数据 SELECT studentname,subjectname,studentresult FROM student s RIGHT JOIN result r ON s.studentno=r.studentno INNER JOIN `subject` sub ON r.subjectno=sub.subjectno WHERE subjectname='高等数学-1' ORDER BY studentresult DESC LIMIT 0,2 -- 第一页 LIMIT 0,2 (1-1)*2 -- 第二页 LIMIT 2,2 (2-1)*2 -- 第三页 LIMIT 4,2 (3-1)*2 -- 第N页 LIMIT (n-1)*2,2 (n-1)*2 -- pageSize: 页面大小 -- (n-1)*pageSize: 起始值 -- n: 当前页 -- 语法: LIMIT (n-1)*pageSize,n
练习
-- 需求:'高等数学-1' 课程排名前3的学生,并且分数大于80的学生信息 (学号、姓名、课程名称、分数) SELECT s.studentno,studentname,subjectname,studentresult FROM student s INNER JOIN result r ON s.studentno=r.studentno INNER JOIN `subject` sub ON r.subjectno=sub.subjectno WHERE subjectname='高等数学-1' AND studentresult>=80 ORDER BY studentresult DESC LIMIT 0,3
4.6 子查询
子查询
-- 需求 :查询 高等数学-1 的所有考试结果(学号、科目编号、成绩) 降序 -- 方法一:连接查询 SELECT studentno,r.subjectno,studentresult FROM result r INNER JOIN `subject` sub ON r.subjectno=sub.subjectno WHERE sub.subjectname='高等数学-1' ORDER BY studentresult DESC -- 方法二:子查询 -- 找到subjectname='高等数学-1'的subjectno SELECT subjectno FROM `subject` sub WHERE sub.subjectname='高等数学-1' -- 开始 子查询 SELECT studentno,subjectno,studentresult FROM result r WHERE subjectno=( SELECT subjectno FROM `subject` sub WHERE sub.subjectname='高等数学-1' )
练习:
-- 练习:分数不小于80分的学生的学号和姓名,课程是'高等数学-1' -- 方式1: SELECT s.studentno,studentname FROM student s INNER JOIN `result` r ON s.studentno=r.studentno INNER JOIN `subject` sub ON r.subjectno=sub.subjectno WHERE r.studentresult>=80 AND sub.subjectname='高等数学-1' ORDER BY r.studentresult -- 方式2: SELECT s.studentno,studentname FROM student s INNER JOIN `result` r ON s.studentno=r.studentno WHERE r.studentresult>=80 AND r.subjectno=( SELECT subjectno FROM `subject` sub WHERE sub.subjectname='高等数学-1' )
5. MySQL函数
5.1 常用函数
-- 常用函数 -- 数学运算 SELECT ABS(-1) 绝对值 SELECT CEILING(5.2) 向上取整 SELECT FLOOR(5.2) 向下取整 SELECT RAND() `随机数(0~1)` SELECT SIGN(2) -- 判断一个数的符号,负数返回-1,正数返回1 -- 字符串函数 SELECT CHAR_LENGTH('我爱学习') -- 字符串长度 SELECT CONCAT('我','爱','编程') -- 拼接字符串 SELECT LOWER('I Love You') -- 转小写字母 SELECT UPPER('I Love You') -- 转大写字母 SELECT INSTR('I Love You','Y') -- 返回第一次出现的字串的索引 SELECT REPLACE('I Love You','I','He') -- 替换出现的指定字符串 SELECT SUBSTR('I Love You',3,4) -- 返回指定的子字符串(开始索引下标,子字符串长度) SELECT REVERSE('I Love You') -- 反转 -- 时间和日期函数 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()
4.7 分组和过滤
-- 需求:查询不同课程的平均分,最高分,最低分 平均分>80 -- 核心:根据不同的课程分组 SELECT subjectname,AVG(studentresult) 平均分,MAX(studentresult) 最高分,MIN(studentresult) 最低分 FROM `subject` sub INNER JOIN result r ON sub.subjectno=r.subjectno GROUP BY sub.subjectno -- 通过哪个字段分组 HAVING 平均分>80
分组了 过滤分组的记录 需要用having 不能用where了 还要注意语句的顺序
5.2 聚合函数(常用)
函数名称 | 描述 |
---|---|
count() | 计数 |
sum() | 求和 |
avg() | 平均值 |
max() | 最大值 |
min() | 最小值 |
...... | ...... |
-- 聚合函数 SELECT COUNT(`studentname`) FROM student -- 会忽略所有的null值 SELECT COUNT(*) FROM student -- 不会忽略null值 本质是计算行数 SELECT COUNT(1) FROM student -- 不会忽略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
练习:
-- 需求:查询不同课程的平均分,最高分,最低分 平均分>80 -- 核心:根据不同的课程分组 SELECT subjectname,AVG(studentresult) 平均分,MAX(studentresult) 最高分,MIN(studentresult) 最低分 FROM `subject` sub INNER JOIN result r ON sub.subjectno=r.subjectno GROUP BY sub.subjectno HAVING 平均分>80
分组了 过滤分组的记录 需要用having 不能用where了 还要注意语句的顺序
5.3 数据库级别的md5加密
什么是md5?
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
主要是增强算法的复杂度和不可逆性
MD5不可逆,具体值的MD5是一样的
MD5破解网站原理:背后有有一个字典,MD5加密后的值,加密前的值
演示:数据库级别的md5加密
-- 测试md5加密 -- 建表 CREATE TABLE `md5Test`( `id` INT(3) NOT NULL AUTO_INCREMENT COMMENT 'id', `username` VARCHAR(20) NOT NULL COMMENT 'username', `psw` VARCHAR(20) NOT NULL COMMENT 'psw', PRIMARY KEY (`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8 -- 插入数据 明文密码 INSERT INTO md5Test(username,psw) VALUE('zhangsan','123456'),('lisi','666666'),('wangwu','888888') -- 加密 UPDATE md5Test SET psw=MD5(psw) WHERE id=1 UPDATE md5Test SET psw=MD5(psw) -- 加密所有 -- 但是应该在插入的时候进行加密 INSERT INTO md5Test(username,psw) VALUE('haha',MD5('123456')) -- 如何校验:将用户传递进来的密码 进行MD5加密,然后比对加密后的值 SELECT * FROM md5test WHERE username='haha' AND psw=MD5('123456')
6. 事务
6.1 什么是事务
-
SQL执行 A给B转账 A 1000 --->200 B 0
-
SQL执行 B收到A的钱 A 800 B 200
将一组SQL放在一个批次中去执行~
事务原则:ACID原则
原子性(Atomicity)
要么都成功,要么都失败
也就是说,事务中的操作要么都发生,要么都不发生
一致性(Consistency)
事务前后数据的完整性必须保持一致
比如说转账,A原来有1000,B有0,无论怎么转,两个的合都得是1000
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离
持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响
隔离所导致的一些问题
脏读:
指一个事务读取了另外一个事务未提交的数据。
不可重复读:
在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)
虚读(幻读):
是指在一个事务内读取到了别的事务插入的数据,导致前后读取数量总量不一致
6.2 执行事务
执行流程:
-- 事务 -- mysql 是默认开启事务自动提交的 SET autocommit=0 -- 关闭 SET autocommit=1 -- 开启(默认的) -- 手动处理事务 流程 SET autocommit=0 -- 1.关闭自动提交 START TRANSACTION -- 2. 事务开启 标记一个事务的开始,从这之后的SQL都在同一个事务内 INSERT xxx -- 3. 写SQL语句 INSERT xxx COMMIT -- 4. 提交 持久化(成功) (一旦提交就固定了,回滚不管用了) ROLLBACK -- 5. 回滚:回到原来的样子(失败) SET autocommit=1 -- 6. 事务结束,开启自动提交 -- 了解知识: SAVEPOINT 保存点名 -- 设置一个事务的保存点 ROLLBACK TO SAVEPOINT 保存点名 -- 回滚到保存点 RELEASE SAVEPOINT 保存点名 -- 撤销保存点
转账实例:
-- 转账 -- 创建数据表 USE school CREATE TABLE account( id INT(3) NOT NULL AUTO_INCREMENT, username VARCHAR(20) NOT NULL, money DECIMAL(9,2) NOT NULL, PRIMARY KEY(id) )ENGINE=INNODB DEFAULT CHARSET=utf8 -- 插入数据 INSERT INTO account(username,money) VALUES('张三','10000'),('李四','20000') -- 事务:模拟转帐 SET autocommit=0 START TRANSACTION UPDATE account SET money=money+5000 WHERE username='张三' UPDATE account SET money=money-5000 WHERE username='李四' COMMIT ROLLBACK SET autocommit=1
7. 索引
MySQL官方对索引的定义:索引(index)是帮助MySQL高效获取数据的数据结构。
索引本质:索引是数据结构
7.1 索引的分类
在一个表中,主键索引只能有一个,唯一索引可以有多个
-
主键索引(PRIMARY KEY)
-
唯一的标识,主键不可重复,只能由一个列作为主键
-
-
唯一索引(UNIQUE KEY)
-
避免重复的列出现,唯一索引可以重复,多个列可以标识为唯一索引
-
-
常规索引(KEY/INDEX)
-
默认 的,index或key关键字来设置
-
-
全文索引(FULLTEXT)
-
在特定的数据库引擎中才有,MyISAM
-
快速定位数据
-
基础语法:
-- 索引的使用 -- 1. 在创建表的时候给字段增加索引 -- 2. 创建完毕后,增加索引 -- 显示所有的索引信息 SHOW INDEX FROM student -- 增加一个全文索引 索引名(列名) ALTER TABLE student ADD FULLTEXT INDEX studentname(studentname) -- EXPLAIN 分析sql执行的情况 EXPLAIN SELECT * FROM student -- 非全文索引 EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('张')
7.2 测试索引
先创建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 NULL, `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=INNODB DEFAULT CHARSET=utf8 -- 插入100万数据 -- 写函数之前必须要写,标志 DELIMITER $$ CREATE FUNCTION mock_data2() RETURNS INT BEGIN DECLARE num INT DEFAULT 1000000; DECLARE i INT DEFAULT 0; WHILE i<num DO INSERT INTO `app_user`(`name`,`email`,`phone`,`gender`) VALUES(CONCAT('用户',i),'19224305@qq.com','123456789',FLOOR(RAND()*2)); SET i=i+1; END WHILE; RETURN i; END; SELECT mock_data2() -- 执行此函数 生成一百万条数据 -- 建表后,先执行18~31行的 然后好了,执行32行的
测试:
-- 测试有索引和无索引的区别 SELECT * FROM app_user WHERE `name`='用户99999' -- 时间 00:937 接近1秒 EXPLAIN SELECT * FROM app_user WHERE `name`='用户99999' -- rows:998577 -- 添加索引 -- id_表名_字段名 -- CREATE INDEX 索引名 on 表(字段) CREATE INDEX id_app_user_name ON app_user(`name`) -- 再次查询 EXPLAIN SELECT * FROM app_user WHERE `name`='用户99969' -- 时间 :00:000 几乎无 rows:1
注意:索引在小数据量的时候,用处不大,但是在大数据量的时候,区别十分明显
7.3 索引原则
-
索引不是越多越好
-
不要对进程变动数据加索引
-
小数据量的表不需要加索引
-
索引一般加在常用来查询的字段上
索引的数据结构
Hash 类型的索引
Btree:InnoDB的默认数据结构
8. 权限管理和备份
8.1 用户管理
sql yog 可视化
sql语句操作
-- 创建用户 CREATE USER 用户名 IDENTIFIED BY '密码' CREATE USER zcc IDENTIFIED BY 'root' -- 修改密码 > 修改当前用户密码 SET PASSWORD=PASSWORD('root') -- 修改密码 > 修改指定用户密码 SET PASSWORD FOR zcc=PASSWORD('123456') -- 重用名 RENAME USER zcc TO zcc2 -- 用户授权 -- ALL PRIVILEGES 除了不能给别人授权,其他的都能干 GRANT ALL PRIVILEGES ON *.* TO zcc2 -- 授权还可以对特定用户、特定表授权 -- 查询权限 SHOW GRANTS FOR zcc2 -- 查询指定用户的权限 -- 撤销权限 REVOKE ALL PRIVILEGES ON *.* FROM zcc2 -- 删除用户 DROP USER zcc2
8.2 MySQL备份
为什么要备份?
-
保证重要的数据不丢失
-
数据转移
MySQL数据库备份的方式
-
直接拷贝物理文件data
-
在SQLyog 这种可视化工具手动导出
导表和导库操作都一样
-
使用命令行导出 mysqldump 命令行使用
-- 语法:mysqldump -h主机 -u用户名 -p密码 数据库 表名 >物理磁盘位置/文件名 mysqldump -hlocalhost -uroot -proot school student >D:/a.sql -- 导出库 mysqldump -hlocalhost -uroot -proot school >D:/b.sql -- 导入 -- 登录的情况下,切换到指定的数据库 -- source 备份文件 source d:/a.sql
9. 规范数据库设计
9.1 为什么要设计
当数据库比较复杂的时候,我们就需要设计了
糟糕的数据库设计:
-
数据冗余,浪费空间
-
数据库插入和删除都会麻烦、异常【屏蔽使用武力外键】
-
程序的性能差
良好的数据库设计:
-
节省内存空间
-
保证数据库的完整性
软件开发中,关于数据库的设计:
-
分析需求:分析业务和需要处理的数据库的需求
-
概要设计:设计关系图 -->E-R图
设计数据库的步骤:(个人博客为例)
-
收集信息,分析需求
-
用户表(用户登录注销,用户的个人信息,写博客,创建分类)
-
分类表(文章分类,谁创建的)
-
文章表(文章的信息)
-
友链表(友联信息)
-
自定义表(系统信息,某个关键字。主字段 key:value)
-
..........
-
-
标识实体(把需求落地到每个字段)
-
标识实体之间的关系
-
写博客:user-->blog
-
创建分裂:user-->category
-
..........
-
9.2 三大范式
为什么需要数据规范化?
-
信息重复
-
更新异常
-
插入异常
-
无法正常显示信息
-
-
删除异常
-
丢失有效的信息
-
三大范式
第一范式(1NF)
原子性:保证每个列不可再分
第二范式(2NF)
前提:满足第一范式
每张表只描述一件事情
第三范式(3NF)
前提:满足第一范式和第二范式
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不是间接相关
规范性和性能的问题
鱼和熊掌不可兼得
阿里规范要求:关联查询的表不得超过三张表
-
也要考虑商业化的需求和目标(成本和用户体验) 数据库的性能更加重要
-
在规范性能的时候,需要适当的考虑以下规范性
-
有时候需要故意给某些表增加一些冗余的字段(从多表查询变为单表查询)
-
有时候需要故意增加一些计算列(从大数据量降低为小数据量的查询:索引)
10. JDBC(重点)
10.1 数据库驱动
驱动:声卡、显卡、数据库
我们的程序会通过 数据库 驱动,和数据库打交道
10.2 JDBC
sun公司为了简化开发人员对数据库的操作,提供了一个(java 操作数据库的)规范,俗称JDBC
这些规范的实现是由具体的厂商去做
对于开发人员,我们只需要掌握jdbc接口的操作即可
10.3 第一个JDBC程序
-
在idea中创建一个普通项目
-
在sqlyog建数据库表,插入数据
CREATE DATABASE `jdbcstudy`CHARACTER SET utf8 COLLATE utf8_general_ci; USE `jdbcstudy`; CREATE TABLE `user` ( `id` INT(3) NOT NULL AUTO_INCREMENT COMMENT '用户id', `username` VARCHAR(20) NOT NULL COMMENT '用户姓名', `password` VARCHAR(100) NOT NULL COMMENT '用户密码', `email` VARCHAR(60) NOT NULL COMMENT '用户邮箱', `birthday` DATE NOT NULL COMMENT '用户生日', PRIMARY KEY (`id`) ) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 INSERT INTO `jdbcstudy`.`user`(`id`,`username`,`password`,`email`,`birthday`) VALUES ( NULL,'张三','123456','123@qq.com','2016-05-06'); INSERT INTO `jdbcstudy`.`user`(`id`,`username`,`password`,`email`,`birthday`) VALUES ( NULL,'李四','965896','696@qq.com','1980-11-23'); INSERT INTO `jdbcstudy`.`user`(`id`,`username`,`password`,`email`,`birthday`) VALUES ( NULL,'胖丫','896657','568@qq.com','2001-06-16');
-
导入数据库驱动
-
编写代码:
package com.zcc.lesson01; import java.sql.*; //我的第一个JDBC程序 public class JdbcFirstDemo { public static void main(String[] args) throws ClassNotFoundException, SQLException { //步骤: //1. 加载驱动 Class.forName("com.mysql.jdbc.Driver"); //固定写法 加载驱动 //2. 用户信息和url String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true"; String username="root"; String password="root"; //3. 连接成功,数据库对象 Connection connection = DriverManager.getConnection(url, username, password); //4. 执行SQL的对象 Statement statement = connection.createStatement(); //5. 执行SQL的对象 去 执行SQL,可能存在结果,查看返回结果 String sql="SELECT * FROM user"; ResultSet resultSet = statement.executeQuery(sql); while (resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); System.out.println("username="+resultSet.getObject("username")); System.out.println("password="+resultSet.getObject("password")); System.out.println("email="+resultSet.getObject("email")); System.out.println("birthday="+resultSet.getObject("birthday")); } //6. 释放连接 resultSet.close(); statement.close(); connection.close(); } } /* id=1 username=张三 password=123456 email=123@qq.com birthday=2016-05-06 id=2 username=李四 password=965896 email=696@qq.com birthday=1980-11-23 id=3 username=胖丫 password=896657 email=568@qq.com birthday=2001-06-16 */
步骤总结:
-
加载驱动
-
连接数据库 DriverManager
-
获得执行SQL得对象 Statement
-
获得返回的结果
-
释放连接
-
10.4 第一个JDBC程序升级版
提取工具类
先写配置类文件db.properties
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true username=root password=root
提取工具类
package com.zcc.lession02.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 (Exception e) { e.printStackTrace(); } } //获取连接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,password); } //释放连接资源 public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException { if (rs!=null){ rs.close(); } if (st!=null){ st.close(); } if (rs!=null){ rs.close(); } } }
编写代码:
package com.zcc.lession02; import com.zcc.lession02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Test01 { public static void main(String[] args) throws SQLException { Connection conn=null; Statement st=null; ResultSet rs=null; try { conn= JdbcUtils.getConnection(); //获取数据库连接 st=conn.createStatement(); //获取SQL的执行对象 String sql="INSERT INTO `user`(`username`,`password`,`email`,`birthday`) VALUES('菲儿','687652','967@qq.com','2003-06-23')"; int i = st.executeUpdate(sql); if (i>0){ System.out.println("插入数据成功 "); } } catch (Exception e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } }
注意:插入数据、更新数据、删除数据都是用st.executeUpdate()方法
如果是查找,用st.executeQuery()方法
st.execute()方法对于增删改查都可以,但是效率比另外两个方法慢,而且这个方法返回的是布尔值,对于结果不好判断
sql注入问题
sql存在漏洞,会被攻击,导致数据泄露
因为SQL会被拼接 or
比如:
SELECT * FROM `user` WHERE `username`='胖丫' AND `password`='896657' 被or拼接,这样可以查询出全部的用户名密码 SELECT * FROM `user` WHERE `username`='丫' OR '1=1' AND `password`='657' OR '1=1' "丫 和 657"那里乱输都可以
package com.zcc.lession02; import com.zcc.lession02.utils.JdbcUtils; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; public class Test02 { public static void main(String[] args) throws SQLException { login("2 'OR' 1=1","1 'OR' 1=1"); } public static void login(String username,String password) throws SQLException { Connection conn=null; Statement st=null; ResultSet rs=null; try { conn= JdbcUtils.getConnection(); //获取数据库连接 st=conn.createStatement(); //获取SQL的执行对象 // String sql="SELECT * FROM `user` WHERE `username`='胖丫' AND `password`='896657'"; String sql="SELECT * FROM `user` WHERE `username`='"+username+"' AND `password`='"+password+"'"; ResultSet resultSet = st.executeQuery(sql); while (resultSet.next()){ System.out.println(resultSet.getString("username")); System.out.println(resultSet.getString("password")); System.out.println("------------"); } } catch (Exception e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,rs); } } } /* 输出结果 张三 123456 ------------ 李四 965896 ------------ 胖丫 896657 ------------ 菲菲 687652 ------------ */
解决sql注入的不安全
10.5 PreparedStatement对象(解决sql注入问题)
package com.zcc.lession02; import com.zcc.lession02.utils.JdbcUtils; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class Test04 { public static void main(String[] args) throws SQLException { login("2 'OR' 1=1","1 'OR' 1=1"); } public static void login(String username,String password) throws SQLException { Connection conn=null; PreparedStatement st=null; try { conn=JdbcUtils.getConnection(); String sql="SELECT * FROM `user` WHERE `username`=? AND `password`=?"; st=conn.prepareStatement(sql); st.setString(1,username); st.setString(2,password); ResultSet resultSet = st.executeQuery(); if (resultSet.next()){ System.out.println(username); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils.release(conn,st,null); } } }
10.6 数据库连接池
池化技术:准备一些预先的资源,过来就连接预先准备好的
最小连接数 最大连接数 等待超时
编写连接池,实现一个接口 DataSource
开源数据源实现
DBCP
C3P0
Druild :阿里巴巴的
使用了这些数据库连接池后,我们在项目开发中就不需要编写连接数据库的代码了
DBCP
需要用到的jar包
commons-dbcp-1.4
commons-pool-1.6
package com.zcc.lession03.utils; import org.apache.commons.dbcp.BasicDataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; import javax.sql.DataSource; 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("dbcpconfig.properties"); Properties properties = new Properties(); properties.load(resourceAsStream); //创建数据源 工厂模式-->创建 dataSource= BasicDataSourceFactory.createDataSource(properties); } catch (Exception e) { e.printStackTrace(); } } //获取连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); //从数据源中获取连接 } //释放连接资源 public static void release(Connection conn, Statement st, ResultSet rs) throws SQLException { if (rs!=null){ rs.close(); } if (st!=null){ st.close(); } if (rs!=null){ rs.close(); } } }
package com.zcc.lession03; import com.zcc.lession02.utils.JdbcUtils; import com.zcc.lession03.utils.JdbcUtils_dbcp; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class Test { public static void main(String[] args) throws SQLException { login("张三","123456"); } public static void login(String username,String password) throws SQLException { Connection conn=null; PreparedStatement st=null; try { conn= JdbcUtils_dbcp.getConnection(); String sql="SELECT * FROM `user` WHERE `username`=? AND `password`=?"; st=conn.prepareStatement(sql); st.setString(1,username); st.setString(2,password); ResultSet resultSet = st.executeQuery(); if (resultSet.next()){ System.out.println(username); } } catch (SQLException e) { e.printStackTrace(); }finally { JdbcUtils_dbcp.release(conn,st,null); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)