Javaee加数据库笔记

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、插入数据

idnametypemoney
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、部门表插入以下数据:

idnameloc
1神仙部天庭
2妖怪部盘丝洞
insert into dept values(1,'神仙部','天庭'),(2,'妖怪部','盘丝洞');

5、emp员工表插入以下数据

idnamesaldept id
1悟空50001
2八戒20001
3蜘蛛精80002
4白骨精90002
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接口在这几周学到了很多也有很多不足还需要多多练习多多实践

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值