Javaee之数据库
mysql数据库
创建数据库字符集utf8
create database mydb1 character set utf8;
创建数据库字符集gbk
create database mydb2 character set gbk;
查询所有数据库
show databases;
分别查询检查字符集是否正确
show create database mydb1;
先使用mydb1 再使用mydb2
use 数据库名
use mydb1;
use mydb2;
删除数据库
drop database mydb2(数据库名);
进入数据库 use (数据库名)
创建数据库中的表
create table t1(name varchar(4),age int) charset=utf8;
格式:create table 表名(字段名1类型,字段名2类型,字段名3类型)charset=utf8;(gbk)
查看字段表
desc t1;
查看所有表
show tables;
查看表详情 show create table t1;
删除表 drop table 表名
修改表名 rename table原名 to 新名
添加表字段 alter table 表名 add字段名 字段类型;
删除表字段 alter table 表名 drop 字段名;
修改表字段 alter table表名 change 原字段名 新字段名 新类型 ;
表练习
1、创建数据库mydb,字符集utf8并使用该数据库
creat database mydb character set utf8;
2、在mydb中创建员工表emp,字段有name,表字符集也是utf8
create table emp(name varchar(10)) charset = utf8;
3、在最后添加表字段age
alter table emp add age int;
4、在最前面添加id字段
alter table emp add id int first;
5、添加性别gender在name后面
alter table emp add gender varchar(5) after name;
6、修改gender字段为salary
alter table emp change gender sal int;
7、删除age字段
alter table emp drop age;
8、修改表名为temp
rename table emp to temp;
9、删除temp表
drop table temp;
10、删除数据库mydb;
drop database mydb;
数据库的使用(更新数据)
1、插入数据
全表插入格式:insert into 表名valuse(值1,值2);
insert into t1 values('Tom',18);
select * from t1;(查询表中内容)
指定字段插入格式:insert into表名(字段名1,字段名2)values(值1,值2);
insert into t1(name,age) values('Jack',24);
select * from t1;
批量插入格式:insert into 表名 values(值1,值2), (值1,值2), …
insert into t1 values('张三丰',108),('张无忌',35),('赵敏',25);
select * from t1;
备注:如果你在命令行中输入中文报错,在创建之前先输入:set names gbk;
数据库支持中文和命令行支持中文是不一样的
2、简单查询
格式:select字段信息 from 表名 where条件;
举例:*表示查询所有列
select * from t1;
select name from t1;
select name from t1 where age>=30;
3、修改数据
把某个值进行修改,而且限定条件
格式:update 表名 set 字段名=新值where条件;
备注:在mysql中,对于命令行还是字段名都不区分大小写
update t1set age = 30 where name='Jerry';
update t1 set age = 28 where name='tom';
insert into t1(name) values('张三'),('李四');
update t1 set age=30 where age is null;
备注:判断值为空用is而不能用==
4、删除数据
delete 删除数据,而且是整行的删除
格式:delete from 表名 where 条件;
delete from t1 where age=30;
delete from t1 where name='张无忌';
delete from t1;删除表中所有的数据,表的结构还在
练习:
1、创建一个hero表,字段有id, name,type,money
create table hero(
id int,
name varchar(10),
type varchar(5),
money int);
charset = utf8;
2、插入数据
id | name | type | money |
---|---|---|---|
1 | ‘诸葛亮’ | ‘法师’ | 18888 |
2 | ‘周瑜’ | ‘法师’ | 13888 |
3 | ‘刘备’ | ‘战士’ | 8888 |
4 | ‘孙尚香’ | ‘射手’ | 6888 |
5 | ‘黄忠’ | ‘射手’ | 8888 |
insert into hero values(1,'诸葛亮','法师',18888),
(2,'周瑜','法师',13888),(3,'刘备','战士',8888),
(4,'孙尚香','射手',6888),(5,'黄忠','射手',8888);
3、修改13888为28888
update hero set money = 28888 where money =13888;
4、修改所有射手价格为3000
update hero set money = 3000 where type ='射手';
5、删除价格为18888的英雄
delete from hero where money =18888;
6、修改孙尚香为猪八戒
update hero set name='猪八戒' where name = '孙尚香';
7、删除价格低于5000的
delete from hero where money<5000;
8、添加性别gender字段
alter table hero add gender varchar(10);
9、修改所有英雄的性别为男
update hero set gender='男';
10、删除表中所有数据
delete from hero;
11、删除hero表
drop table hero;
练习二:
1、创建数据库mysky,字符集utf8
create database mysky character set utf8;
2、在mysky数据库当中创建员工表emp,字段有id,name,sal,dept id(部门id),字符集utf8
create table emp(id int,name varchar(10),sal int,dept_id int) charset=utf8;
3、创建部门表dept,字段有:id,name,loc(部门地址)
create table dept(id int,name varchar(10),loc varchar(10)) charset=utf8;
4、部门表插入以下数据:
id | name | loc |
---|---|---|
1 | 神仙部 | 天庭 |
2 | 妖怪部 | 盘丝洞 |
insert into dept values(1,'神仙部','天庭'),(2,'妖怪部','盘丝洞');
5、emp员工表插入以下数据
id | name | sal | dept id |
---|---|---|---|
1 | 悟空 | 5000 | 1 |
2 | 八戒 | 2000 | 1 |
3 | 蜘蛛精 | 8000 | 2 |
4 | 白骨精 | 9000 | 2 |
insert into emp values(1,'悟空',5000,1),
(2,'八戒',2000,1),
(3,'蜘蛛精',8000,2),
(4,'白骨精',9000,2);
6、查询工资6000以下员工的姓名和工资
select name,sal from emp where sal <6000;
7、修改神仙部的名字为取经部
update dept set name = '取经部' where name='神仙部';
8、给员工表emp添加奖金comm字段
alter table emp add comm int;
9、修改部门id为1的部门奖金为500
update emp set comm = 500 where dept_id = 1;
10、把取经部的地址改成五台山
update dept set loc='五台山' where name='取经部';
数据类型与约束
char类型字符串是固定长度的
varchar类型长度是可变的
存储字符串’abc’,使用char(10),表示存储的字符将占10个字节 (包括7个空字符)
varchar(10),则表示只占3个字节,10是最大值,当存储的字符小于10时,就按照实际的长度进行存储
相对来说,char的效率比varchar的效率更高
1、整数类型: int和bigint(等效java中的long)
create table t2(name varchar(10),age int(10) zerofill);
insert into t2 values('aaa',18);
select * from t2;
zerofill:表示这个列的数据长度不足时前面用0补位
2、浮点数 :float(m,d)和double(m,d)
m代表总长度,d代表小数长度,超高精度浮点数 decimal(m,d),只有涉及超高精度运算时使用
3、字符串:char(m),m=10,存abc占10个长度,最大长度255,
varchar(m):可变长度,m=10,存abc占三个长度,最大长度65535
建议:字符串长度超过255,使用text,节省空间 text(m):可变长度,最大长度65535
4、日期:
date:只能保存年月日 time:只能保存时分秒 datetime:默认值位null,最大在9999-12-31
timestamp:默认值为当前的系统时间,最大值为2038-1-19
create table n_t1(t1 date,t2 time, t3 datetime,t4 timestamp);
insert into n_t1 values(null,null,'2023-3-9 17:30',null);
insert into n_t1 values('2028-10-1','11:12:13',null,null);
select * from n_t1;
create table t4(
name varchar(50),
phone char(11),
note text(300),
height float(4,1),
weight float(5,2));
数据类型与约束
数据的完整性
存储在数据库中的所有数据值均正确的情况下的状态,如果数据库中存储有不正确的数据值,该数据库则已丧失数据的完整性
例如:这个同学有学号,没姓名
员工表,只有工资,没有姓名
主键约束
1、什么是主键
表示数据唯一性的字段称为主键,身份证号,准考证号,而且它一定存在,不能为空
2、什么是约束
创建表时给表字段添加限定条件
主键约束效果就是当前列的数据在表中唯一且非空
create table t2(
id int primary key,
name varchar(10));
insert into t2 values(1,'张无忌');可以
insert into t2 values(1,'谢逊');不可以,id不能重复
insert into t2 values(null,'张无忌');id不能为空
insert into t2 values(3,'张无忌');可以,名字可以重复
3、主键约束+自增
自增规则:从历史最大值+1,并且只增不减
create table t3(
id int primary key auto_increment,
name varchar(10)) charset=utf8;
insert into t3 values(null,'张无忌');
insert into t3 values(null,'赵敏');
insert into t3 values(10,'金轮法王');
insert into t3 values(null,'张翠山');
4、非空约束
被设置非空约束的列的数据不能为空
没设置的话就允许为空,注意单引号也是有数据的,而不是null空值
create table t5(
id int primary key auto_increment,
name varchar(10) not null,
addr varchar(30));
insert into t5 values(null, '曹操','兖州');//ok
insert into t5 values(null,'孙大圣','花果山');//ok
insert into t5 values(null,'','鄂尔多斯');//ok
5、唯一约束
被设置唯一约束的列数据不能出现重复的值
手机号不能重复,如果要加上不能重复而且不能为空,可以加上 not null, unique,无先后顺序
create table t6(
id int primary key auto_increment,
name varchar(10) not null,
phone varchar(11) unique);
insert into t6 values(null,'宋江','119');
insert into t6 values(45,'鲁智深',228);
数据查询
批量创建数据:sql文件导入,将sql文件放到没有中文字符的路径下
linux下使用命令行
source /home/emp.sql
windows下使用命令运行
source c:/emp.sql
简洁操作:将sql文件按住不放拖到mysql命令行中,直接输入命令
判断空值null
使用is null 和is not null判断数据是否为空
查询没有上级领导的员工信息
select * from emp where mgr is null;
查询有上级领导的员工姓名
select ename from emp where mgr is not null;
关系运算符
sql比较运算符:> < >= <= = !=与 <>都是不等于
查询员工工资小于等于3000的姓名和工资
select ename,sal from emp where sal<=3000;
查询工作不是程序员的员工姓名和工作
select ename,job from emp where job!='程序员';
select ename,job from emp where job<>'程序员';
逻辑运算符
sql中逻辑运算符and 和 or,类似于java 中的&&和||
查询1号部门工资高于2000的员工信息
select * from emp where deptno=1 and sal>2000;
查询工作是人事或工资大于3000的员工姓名、工资、工作
select ename,sal,job from emp where job='人事'or sal>3000;
between关键字
语法:between x and y
查询x和y之间的数据,包含x和y
查询工资在2000到3000之间的员工姓名和工资
select ename,sal from emp where sal>=2000 and sal<=3000;
select ename,sal from emp where sal between 2000 and 3000;
in关键字
语法:列名 in (x,y,z)
查询员工工资为3000,1500,5000的员工姓名和工资
select ename,sal from emp where sal in(3000,1500,5000);
select ename,sal from emp where sal=3000 or sal=1500 or sal=5000;
综合练习
查询有上级领导并且是3号部门的员工信息
select * from emp where mgr is not null and deptno=3;
查询2号部门工资在1000到2000之间的员工姓名、工资和部门编号
select ename,sal,deptno from emp where deptno=2 and sal between 1000 and 2000;
select ename,sal,deptno from emp where sal between 1000 and 2000 and deptno=2;
查询1号部门工资为800和1600的员工信息
select * from emp where sal=800 or sal=1600 and deptno=1;
select * from emp where deptno=1 and sal in (800,1600);
模糊查询
like关键字
sql语句中将关系运算符替换为like关键字,可以对数据进行模糊匹配
模糊匹配的数据类型针对字符串类型 (varchar\char\text)
可以使用通配符代替要查询的内容
通配符%: 代表0或者多个任意符
通配符_:代表一个任意字符
举例:
1、以x开头 :‘x%’
2、以x结尾 :‘%x’
3、包含x :‘%x%’
4、第二个字符是x:‘_x%’
5、倒数第三个字符是x:‘%x_’
6、以x开头,倒数第二个是y:‘x%y_’
查询姓孙的员工信息
select * from emp where ename like '孙%';
查询工作中包含销售的员工姓名和工作
select ename,job from emp where job like '销售%';
select ename,job from emp where job like '%销售%';
查询名字中以“精”结尾的员工姓名
select ename from emp where ename like '%精';
排序和分页
排序查询
有主键,尽量按照主键排,如果不是int类型,就进行字符串排序
order by 可以指定升序和降序
格式 order by 字段名 asc/desc
查询员工姓名和工资并且按照工资降序排序
select ename,sal from emp order by sal desc;
查询1号部门员工信息按照工资升序排序
select * from emp where deptno=1 order by sal;
select * from emp where deptno=1 order by sal asc;//默认升序
依靠多个字段进行选择
格式:order by 字段1 asc\desc,字段2 asc/desc;
查询员工姓名,工资和部门编号,按照部门编号升序排序,如果部门编号一致,按照工资降序排序
select ename,sal,deptno from emp order by deptno,sal desc;
分页查询
查询数据时可能查询的结果较多,不能一次完全展示完,就需要将数据进行分页,按页查询展示
mysql数据库支持使用limit关键字。实现分页查询功能
格式:limit x,y
x:跳过的条数
y:请求的条数(每页的条数)
查询员工表中第一页的5条数据,按照工资升序排序
select * from emp order by sal limit 0,5;
查询员工表中第2页的5条数据,按照工资升序排序
select * from emp order by sal limit 5,5;
查询员工表中工资最高的员工信息
select * from emp order by sal desc limit 0,1;
查询员工表中工资降序的第三页的第3条数据
select * from emp order by sal desc limit 6,3;
查询工资在1000到5000之间的第4页的2条数据
select * from emp where sal between 1000 and 5000 limit 6,2;
数值计算和聚合函数
数值计算
在sql语句中,我们可以在出现数据的位置进行计算,包括但不限于±*等运算符
查询每个员工的姓名工资及年终奖(5个月的工资)
select ename,sal,5*sal 年终奖 from emp;
select ename,sal 工资,5*sal 年终奖 from emp;
这里就是在数据的位置进行计算,5*sal,后面取个别名,不是新增加字段,别名是临时展示使用
别名前面的空格也可以用as代替
查询每个员工的姓名、工资以及涨薪500块之后的工资
select ename,sal,sal+500 涨薪后 from emp;
聚合函数
sql语句允许对查询出的多行数据中的某些列的值进行统计,可以统计这些值的函数我们称为聚合函数
这些函数如下:求和\计数\平均值\最大值\最小值
求和sum(字段)
查询2号部门员工工资总和
select sum(sal) from emp where deptno=2;
计数count(字段)
查询工资大于2000块钱的员工数量
select count(*) from emp where sal >2000;
select count(*) from emp where sal >2000 and job like "%销售%";
平均值avg(字段)
查询1号部门的平均工资
select avg(sal) from emp where deptno=1;
最大值max(字段)
查询员工表中工资最大值是多少
select max(sal) from emp;
查询1号部门的最大奖金comm是多少
select max(comm) from emp where deptno=1;
最小值min(字段)
查询1号部门的最低工资
select min(sal) from emp where deptno=1;
习题:
查询员工表中工资高于2000的员工姓名和工资,按照工资升序排序,查询第二页的2条数据
select ename,sal from emp where sal >2000 order by sal limit 2,2;
查询和销售相关的工资总和 like
select sum(*) from emp where job like "%销售%";
查询程序员人数
select count(*) from emp where job='程序员';
查询1号部门中有领导的员工最高工资
select max(sal) from emp where deptno=1 and mgr is not null;
查询2号部门的最高工资和最低工资并起别名
select max(sal) 最高,min(sal) 最低 from emp where deptno=2;
查询1号部门里面名字包含"空"字的员工姓名
select ename from emp where deptno=1 and ename like '%空%';
分组查询
聚合函数只能查询出一行数据,比如“查询2号部门工资总和”
但是如果想查询出多行的聚合结果,比如“查询每个部门的工资总和”,那就用到分组查询
1、group by 关键字
在需求中出现每个或者每种这样的关键字时使用分组查询
查询每个部门的平均工资
select deptno,avg(sal) from emp group by deptno;
select deptno,avg(sal),ename from emp group by deptno;不建议这样写
group by 什么你就查询什么,其余就不要查
查询每个部门的最高工资
select deptno,max(sal) from emp group by deptno;
查询每种工作的人数
select job,count(*) from emp group by job;
查询每个部门工资高于1500的员工数量
select deptno,count(*) from emp where sal >1500 group by deptno;
select deptno,count(*) 人数 from emp where sal >1500 group by deptno;
查询1号部门和2号部门的最高工资
select deptno,max(sal) from emp where deptno in(1,2) group by deptno;
2、having关键字
分组之后还有条件,这个就用到having
where后面只能写普通字段的条件,不能写聚合函数条件
having结合分组查询group by 使用,在having后面写聚合函数条件
最后面如果是聚合函数,用having,否则就用where
查询每个部门的平均工资并且只查询平均工资大于2000的
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;
查询每种工作人数,保留查询人数为1的工作
select job,count(*) c from emp group by job having c=1;
查询每个部门的平均工资,只查询工资在1000到3000之间的(针对的是员工),并且过滤掉平均工资低于2000的部门
select deptno,avg(sal) a from emp where sal between 1000 and 3000 group by deptno having a >= 2000;
查询工资在1500以上员工达两人以上的部门和人数
select deptno,count(*) c from emp group by deptno having avg(sal)>=1500 and c>2;
关键字总结一下
使用查询语句时应该注意这些关键字的含义和顺序
select 字段信息
from 表名
where 条件
group by 字段 以xx进行分组
having 聚合条件
order by 排序字段
limit 跳过几条,查询几条;
综合练习:
查询没有上级领导的员工编号empno,姓名,工资
select empno,ename from emp where mgr is null;
查询有奖金的员工姓名和奖金
select ename,comm from emp where comm is not null;
查询名字中第二个字是八的员工信息
select * from emp where ename like "_八%";
查询1号部门工资大于2000的员工信息
select * from emp where sal >2000 and deptno=1;
查询2号部门或者工资低于1500的员工信息
select * from emp where sal < 1500 or deptno=2;
查询每个部门工资大于1000的员工人数,按照人数升序排序
select deptno,count(*) c from emp where sal>1000 group by deptno order by c;
查询每种工作中有领导的员工人数,按照人数降序排序
select job,count(*) c from emp where mgr is not null group by job order by c desc;
查询所有员工信息,按照部门编号升序排序,部门若一致按照工资降序
select * from emp order by deptno, sal desc;
查询有领导的员工,按照工资升序排序,第三页的2条数据
select * from emp where mgr is not null order by sal limit 4,2;
查询每个部门的工资总和,只查询有上级领导的员工并且要求工作总和大于5400,最后按照工资总和降序排序,只查询结果中的第一条数据
select deptno,sum(sal) from emp where mgr is not null group by deptno having sum(sal)>5400 order by sum(sal) desc limit 0,1;
高阶内容
子查询 (嵌套查询)
什么是子查询
子查询就是在一条sql语句中,出现表达式的位置又编写了另外一条sql语句
为什么需要子查询
适用于比较复杂的多表查询需求
子查询的使用
查询工资高于1号部门平均工资的员工信息
先查询1号部门的平均工资,然后再查询表中工资大于1号部门平均工资的员工信息
select avg(sal) from emp where deptno=1;
select * from emp where sal > (select avg(sal) from emp where deptno=1);
查询工资最高的员工信息
先查询最高的工资值,然后查询emp表中谁的工资是这个值
select max(sal) from emp;
select * from emp where sal=(select max(sal) from emp);
查询工资高于2号部门最低工资的员工信息
先要找到2号部门的最低工资
select * from emp where sal>(select min(sal) from emp where deptno=2);
查询和孙悟空相同工作的其他员工信息
先得到孙悟空的工作
select job from emp where ename="孙悟空";
select * from emp where job=(select job from emp where ename='孙悟空') and ename!='孙悟空';
查询白骨精的部门信息
先找到白骨精的部门编号
select deptno from emp where ename="白骨精";
select * from dept where deptno=(select deptno from emp where ename="白骨精");
查询有员工的部门信息
distinct:去重
select distinct deptno from emp;
通过得到的部门编号查询部门信息
select * from dept where deptno in (select distinct deptno from emp);
Javaee之JDBC
Java DataBase Connectivity (java数据库连接)
让java和数据库进行沟通,让java控制页面,实现我们服务器资源的调用
sun公司提供一套API (接口) ,通过java语言对数据库发送sql语句,完成增删改查的操作,这一套流程我们称为JDBC
JDBC驱动接口就是sun公司提供的API,大多是接口,接口只有方法声明,而没有方法实现,数据库实现的操作是由厂商完成的。
所谓的驱动,就是实现这些接口的类,这些方法都是编写好的实现文件,jdbc声明接口的实现类:connection,statement,还有一些导入的jar包,都是写好的一些类
配置数据库依赖
file-project-structure-moudules-dependcies-手动添加数据库(找到自己数据库的jar包)
package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class demo1 {
public static void main(String[] args) throws Exception {
//jdbc 连接并操作数据库步骤
//1、加载jdbc驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获得连接
//桥梁 3306是Mysql数据库默认的端口号
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3",
"root",
"root"
);
//3、创建命令对象 状态通道 在桥上跑的各种对象
Statement st = conn.createStatement();
//4、发送命令
st.execute("create table mytb (id int,name varchar(10))");
//5、回收资源
conn.close();
//运行结束,可以取数据库看看mytb是否创建
System.out.println("over");
}
}
使用jdbc实现增删改查
execute(sql) 此方法可以执行任意的sql语句,推荐执行数据库和相关的sql
executeUpdate(sql) 此方法原来执行增删改相关的sql
executeQuery(sql) 此方法执行查询的sql
package cn.tedu;
import org.junit.jupiter.api.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class jdbcDemo2 {
public static void main(String[] args) throws Exception {
//jdbc 连接并操作数据库步骤
//1、加载jdbc驱动
Class.forName("com.mysql.jdbc.Driver");
//2、获得连接
//桥梁 3306是Mysql数据库默认的端口号
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3",
"root",
"root"
);
//3、创建命令对象 状态通道 在桥上跑的各种对象
Statement st = conn.createStatement();
//4、发送命令
st.execute("create table mytb1 (id int,name varchar(10))");
//5、回收资源
conn.close();
//运行结束,可以取数据库看看mytb是否创建
System.out.println("over");
}
增加数据
//测试函数
@Test
public void insert() throws SQLException {
System.out.println("开始新增");
//获得连接
Connection conn=DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3",
"root",
"root"
);
//获得执行命令的对象
Statement st=conn.createStatement();
//执行sql语句
String sql ="insert into mytb1(id,name) values(007,'周健宇')";
st.execute(sql);
System.out.println("mytb1中插入数据完成");
conn.close();
}
删除数据
@Test
public void delete() throws SQLException {
System.out.println("开始删除");
//获得连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3",
"root",
"root");
//获得执行命令的对象
Statement st=conn.createStatement();
//执行sql语句
String sql ="delete from mytb1 where id=9";
int num = st.executeUpdate(sql);
System.out.println("sql影响的行为数为:"+num);
System.out.println("over");
conn.close();
}
修改数据
@Test
public void update() throws SQLException {
System.out.println("开始修改");
//获得连接
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3",
"root",
"root");
//获得执行命令的对象
Statement st = conn.createStatement();
//执行sql语句,将lizhi改成ly
String sql = "update mytb1 set name='ly' where name='lizhi'";
//运行sql语句并查看修改的行数
int num=st.executeUpdate(sql);
System.out.println("sql影响的行数为:"+num);
System.out.println("over");
conn.close();
}
}
查询数据
@Test
public void select() throws SQLException {
System.out.println("开始查询");
//获得连接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3",
"root",
"root");
//获得执行命令的对象
Statement st = conn.createStatement();
//查询sql语句
String sql ="select ename,sal from emp";
//executeQuery执行sql语句
//返回查询到的结果集
ResultSet rs = st.executeQuery(sql);
//next执行,如果下一行有数据,则返回真,否则返回假
/* System.out.println(rs.next());
rs.next();
//指定列名获得该列数据
System.out.println(rs.getString("ename"));
System.out.println(rs.getString("sal"));
//指针再次移动,指向下一行 rs.next()控制指针的移动
rs.next();
//指定列序号获得数据
System.out.print(rs.getString(1));
System.out.print(rs.getString(2));
//指针向上移动
rs.previous();
rs.previous();
System.out.println(rs.getString(1));
System.out.println(rs.getString(2));
*/
//将rs.next()放入while循环中做循环条件
// 只要下一行有数据,就继续循环,否则循环结束
while (rs.next()){
//获取数据的两种方法,一是通过列名,二是通过序号
System.out.println(rs.getString(1));
System.out.println(rs.getString(2));
}
System.out.println("over");
conn.close();
}
}
ResultSet:结果集,不单单是一张表,rs包含一个箭头,刚开始谁也不指向,当运行rs.next,能够控制指针指向第一行,在执行rs.next,指针指向第二行,依次类推
如果下一行有数据,返回True,没有数据,返回False
DBUtils类
什么是DBUtils类
DBUtils类是我们自己编写的一个类,并不是java提供或者第三方提供的jar包,这个类中包含了连接数据库通用代码,使用它可以实现减少代码冗余
DB表示数据库,Utils表示工具包
package cn.tedu;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class DBUtils {
//定义一个包含每次连接数据库都要写的代码的方法
//这个方法返回值是可以连接,所以返回值类型是Connection
public static Connection getConn() throws Exception {
//定义连接数据库所需要的参数变量
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn= DriverManager.getConnection(
"jdbc:mysql://localhost:3306/newdb3?serverTimezone=GMT",
"root",
"root" );
return conn;
}
public static void main(String[] args) throws Exception{
System.out.println(getConn());
}
}
查询结果集rs
public class jdbcDemo3 {
public static void main(String[] args) {
//try 中可以直接使用conn
//conn是DBUtils类中获得可用连接
try(Connection conn = DBUtils.getConn();){
//创建执行命令对象
Statement st = conn.createStatement();
//定义sql语句
String sql = "select ename from emp";
ResultSet rs = st.executeQuery(sql);
while (rs.next()){
String ename = rs.getString(1);
System.out.println(ename);
}
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDBC批量插入数据
public class jdbcDemo4 {
public static void main(String[] args) {
try(Connection conn = DBUtils.getConn()) {
String sql = "insert into user values(?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
//i 不要从0开始
for (int i =1; i<=100;i++){
//替换用户名和密码
ps.setString(1,"user"+i);
ps.setString(2,"pwd"+i);
//添加到批量操作中
ps.addBatch();
// System.out.println("执行一半");
//每次20次执行一次,避免内存溢出
if(i%20==0){
ps.executeBatch();
}
}
//执行批量操作
ps.executeBatch();
System.out.println("执行完成!");
}
catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
SQL注入和PrepparedStatement接口
sql注入就是用户可填写的内容中包含了可运行的sql语句,这样恶意用户就可以攻击我们的数据库,可能会带来非常严重的后果,比如删除核心表
/注册登录sql注入
public class jdbcDemo5 {
public static void main(String[] args) {
//输入用户名和密码
Scanner scanner=new Scanner(System.in);
//请输入用户名
System.out.println("输入用户名:");
String username=scanner.next();
System.out.println("请输入密码:" +
"");
String password=scanner.next();
try (Connection conn=DBUtils.getConn()){
//定义statment对象
Statement st=conn.createStatement();
//定义sql语句
//String sql="select count(*) from user wherer username='刘备' and password='8888'";
String sql="select count(*) from user where username='"+username+"' and password='"+password+"'";
//执行sql语句
ResultSet rs=st.executeQuery(sql);
while (rs.next()){
//如果查询出来的结果是1。登录成功
//如果查询的结果不是1 是0,登录失败
int count=rs.getInt(1);
if (count>0){
System.out.println("登录成功");
}else {
System.out.println("登录失败");
}
}
} catch (SQLException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
用户名输入
fefewe
密码输入
'or'1'='1
结果是登录成功
为什么会出现这种情况,我们可以打印一下这个sql语句
select count(*) from where username= 'fefewe' and password=''or'1'='1'
那如何解决这个问题,jdbc给了我们解决方案,使用PreparedStatement接口
public class jdbcDemo6 {
public static void main(String[] args) {
//用户名密码输出
Scanner scan = new Scanner(System.in);
//提示输入
System.out.println("请输入用户名:");
String username = scan.next();
System.out.println("请输入密码:");
String password = scan.next();
try(Connection conn = DBUtils.getConn()){
//创建预编译命令对象
//和Statement对象不同的是:在创建PreparedStatement就需要指定执行的sql语句
//所以创建前先定义要执行的sql语句,需要有参数传入的位置
//使用?占位,不能写单引号
String sql = "select count(*) from user where username=? and password=?";
PreparedStatement ps = conn.prepareStatement(sql);//进入预编译状态
//sql中的问号需要编写代码来为它赋值
ps.setString(1,username);
ps.setString(2,password);
//执行sql语句
ResultSet rs = ps.executeQuery();
while (rs.next()){
int count = rs.getInt(1);
if (count>0){
System.out.println("登录成功");
}else{
System.out.println("登录失败");
}
}
System.out.println("over");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
这里面不能使用字符串拼接,准备状态,预编译状态通道,在父接口Statement基础上做了一些改进,拼接的过程不易出错,避免sql注入,因为在创建sql执行对象的时候就已经将sql语句的逻辑锁死,不会被用户输入的内容所影响。
一旦用户输入的位置,我们都当作是一个值,而不是sql语句
预编译机制,从第二次开始运行时直接运行已经编译好的sql语句,运行速度快
分页查询
当第一次查询业务时,查询出来的信息较多时,很多网站会采用分页策略
好处3点
1、不用查询出所有信息,节省服务器资源
2、用户按页查询自己需要的信息,节省流量,方便记录
3、大部分情况下,匹配用户需要的数据都会在前几页显示
public class jdbcDemo7 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//分页中注意两个参数,同时注意数据库
//输入每页多少条数据和要查询多少页
System.out.print("请输入每页查询条数");
int size = scan.nextInt();
System.out.println("请输入您要查询第几页");
int pageNum = scan.nextInt();
try(Connection conn = DBUtils.getConn()){
String sql = "select * from user limit ?,?";
PreparedStatement ps =conn.prepareStatement(sql);
//向?中赋值
//limit后第一个值的公式:(请求的页码-1)*每页的条数
ps.setInt(1,(pageNum-1)*size);
//limit后的第二个? 值,永远是每页的条数
ps.setInt(2,size);
ResultSet rs = ps.executeQuery();
while (rs.next()){
String name = rs.getString(1);
System.out.println(name);
}
System.out.println("over");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
创建一个id自增的user2表
create table user2(
id int primary key auto_increment,
username varchar(20),
password varchar(20));
实现获得自动增长的主键值
public class jdbcDemo8 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("请输入用户名:");
String username = scan.next();
System.out.println("请输入密码:");
String pwd = scan.next();
try(Connection conn = DBUtils.getConn()){
//sql语句
String sql = "insert into user2 values(null,?,?)";
//sql语句后面加另一个参数1
//表示这次查询要返回主键的值
PreparedStatement ps = conn.prepareStatement(sql,1);
ps.setString(1,username);
ps.setString(2,pwd);
//执行sql
// ps.executeUpdate();
int num = ps.executeUpdate();
//如果创建preparedStament时指定常量1
//那么就可以通过getGenerateKeys 查询刚刚新增的数据生成的主键
//返回结果集ResultSet
ResultSet rs =ps.getGeneratedKeys();
while (rs.next()){
//由于生成的主键只有一个值,所以获取第一列的值即可
int id = rs.getInt(1);
System.out.println("生成的主键为:"+id);
}
System.out.println("over");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在八周的学习中学到了很多知识数据库的增删改查、数据类型与约束、聚合函数和JDBC、DBUtils类SQL注入和PrepparedStatement接口在这几周学到了很多也有很多不足还需要多多练习多多实践
e.printStackTrace();
}
}
}
创建一个id自增的user2表
```mysql
create table user2(
id int primary key auto_increment,
username varchar(20),
password varchar(20));
实现获得自动增长的主键值
public class jdbcDemo8 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.print("请输入用户名:");
String username = scan.next();
System.out.println("请输入密码:");
String pwd = scan.next();
try(Connection conn = DBUtils.getConn()){
//sql语句
String sql = "insert into user2 values(null,?,?)";
//sql语句后面加另一个参数1
//表示这次查询要返回主键的值
PreparedStatement ps = conn.prepareStatement(sql,1);
ps.setString(1,username);
ps.setString(2,pwd);
//执行sql
// ps.executeUpdate();
int num = ps.executeUpdate();
//如果创建preparedStament时指定常量1
//那么就可以通过getGenerateKeys 查询刚刚新增的数据生成的主键
//返回结果集ResultSet
ResultSet rs =ps.getGeneratedKeys();
while (rs.next()){
//由于生成的主键只有一个值,所以获取第一列的值即可
int id = rs.getInt(1);
System.out.println("生成的主键为:"+id);
}
System.out.println("over");
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
在八周的学习中学到了很多知识数据库的增删改查、数据类型与约束、聚合函数和JDBC、DBUtils类SQL注入和PrepparedStatement接口在这几周学到了很多也有很多不足还需要多多练习多多实践