数据库
数据库简介
通过IO流自己对数据进行操作需要写大量的代码,而且不能保证程序的执行效率,IT行业中凡是很常用实现又很麻烦的业务,
通常会有完整的解决方案,数据库软件就是对数据增删改查的解决方案,程序员只需要学习如何使用数据库软件即可
什么是DBMS:DataBase数据库Management管理System系统(数据库管理软件)
常见的DBMS:MySQL,Oracle,DB2,SQLserver等
DBMS介绍:
1.MySQL,MariaDB是MySQL的一个分支
2.Oracle
3.SQLserver
4.DB2
5.SQLite
开源和闭源区别:
1.开源:开放源代码,免费,盈利方式:靠提供服务赚钱,有技术大牛无偿维护升级
2.闭源:不公开源代码,收费,盈利方式:靠卖产品和卖服务,有技术大牛攻击,不过公司有钱可以养一帮人维护
SQL Structured Query Language结构化查询语言,用于程序员和数据库之间的交流,学习数据库主要学习的就是这门语言
如何连接MySQL数据库软件
1.Windows:
2.Linux:在空白区域右键-终端->mysql -uroot -p 回车->输入密码(没有密码直接回车)->回车
3.退出指令:exit
数据库相关SQL
1.查询所有数据库
格式:show databases;
2.创建数据库并指定字符集
格式: create database 数据库名 character set utf8/gbk;
create database db1 character set utf8;
3.查看数据库详情
格式: show create database 数据库名;
show create database db1;
4.删除数据库
格式: drop database 数据库名;
drop database db1;
5.使用数据库
格式: use 数据库名;
use db1;
表相关SQL
表相关的各种操作必须已经使用了数据库
1.创建表
格式: create table 表名(字段名 类型,字段名 类型);
create table person(name varchar(10),age int); //varchar 字符串
2.查询所有表
格式: show tables;
3.查看表详情
格式: show create table 表名;
show create table student;
4.创建表指定字符集
格式: create table 表名(字段名 类型,字段名 类型) charset=utf8/gbk;
create table t1(name varchar(10),age int) charset=utf8;
5.查看表字段
格式: desc 表名;
desc student;
6.删除表
格式: drop table 表名;
drop table t1;
7.添加表字段
最后添加格式: alter table 表名 add 字段名 类型;
alter table person add sal int;
最前面添加格式: alter table 表名 add 字段名 类型 first;
alter table person add id int first;
xxx的后面添加格式: alter table 表名 add 字段名 类型 after xxx;
alter table person gender varchar(10) after name;
8.删除表字段
格式: alter table 表名 drop 字段;
alter table person drop gender;
9.修改表字段名和类型
格式: alter table 表名 change 原名 新名 新类型;
alter table person change sal gender varchar(10);
数据相关SQL
1.插入数据
全表插入格式: insert into 表名 values(值1,值2,值3);
insert into emp values(1,'Tom',18);
指定字段插入格式: insert into 表名(字段名1,字段名2) values(值1,值2);
insert into emp(name,age) values('Jerry',15);
批量插入数据格式:
insert into emp values(4,'悟空',500),(5,'八戒',300),(6,'沙增',200);
insert into emp(name,age) values('刘备',25),('关羽',23),('张飞',18);
中文问题:
insert into emp values(3,'刘德华',35);
如果执行以上SQL语句报错的话执行以下SQL语句即可(原因可能是终端的编码和DBMS的解码字符集不一致)
set names gbk;
2.查询数据
格式: select 字段信息 from 表名 where 条件;
举例:
1.查询所有的员工姓名 select name from emp;
2.查询所有员工的所有信息 select * from emp;
3.查询年龄小于100岁的员工姓名和年龄 select name,age from emp where age<100;
3.修改数据
格式: update 表名 set 字段名=值,字段名=值 where 条件;
举例:
1.修改悟空名字为孙悟空 update emp set name='孙悟空' where name='悟空';
2.修改刘备年龄为50岁 update emp set age=50 where name='刘备';
3.修改30岁以下的员工年龄为10岁 update emp set age=10 where age<30;
4.删除数据
格式: delete from 表名 where 条件;
举例:
1.删除Tom delete from emp where name='Tom';
2.删除年龄10岁的员工 delete from emp where age=10;
3.删除所有数据 delete from emp;
数据类型
1.整数: int(m) 和 bigint(等效java中的long) ,m代表显示长度,需要结合zerofill关键字使用
create table t_int(id int,age int(10) zerofill);
insert into t_int values(1,20); //1 0000000020
2.浮点数 double(m,d) m代表总长度,d代表小数长度 m=5 d=3 -->23.456
超高精度浮点数decimal(m,d) 只有涉及到超高精度运算时使用
3.字符串:
char(m): 固定长度 m=5 "abc"所占长度为5 执行效率略高,最大长度255
varchar(m):可变长度 m=5 "abc"所占长度为3,节省空间,最大长度65535,超过255建议使用text
text(m):可变长度 最大长度65535
4.日期:
date:只能保存年月日
time:只能保存时分秒
datetime:年月日时分秒 默认值null 最大值9999-12-31
timestamp:时间戳 默认值当前系统时间 最大值2038年1月19日
create table t_date(t1 date,t2 time,t3 datetime,t4 timestamp);
insert into t_date values('2019-9-5',null,null,null);
insert into t_date values(null,'17:37:33','2019-9-5 17:37:33',null);
主键约束
约束:创建表时给表字段添加的限制条件
主键:表示数据唯一性的字段称为主键
主键约束:用于限制字段的值必须唯一并且不能为null(唯一且非空)
格式:
create table t1(id int primary key,name varchar(10));
insert into t1 values(1,'aaa');
insert into t1 values(1,'bbb');//报错,不能重复
insert into t1 values(null,'bbb');//报错,不能为Null
主键约束+自增 primary key auto_increment;
自增规则:历史最大值+1;(只会增,不会减)
格式:
create table t2(id int primary key auto_increment,name varchar(10));
insert into t2 values(null,'aaa'); // 1
insert into t2 values(null,'bbb'); //2
insert into t2 values(10,'ccc'); //10
insert into t2 values(null,'ddd'); //11
delete from t2 where id>10;
insert into t2 values(null,'eee');//12
注释 comment
创建表时给字段添加的注释
格式:
create table t3(id int primary key auto_increment comment '这是主键',name varchar(10) comment '这是名字');
查看:show create table t3;
导入*.sql文件
1. linux系统:
source /home/用户名/桌面/emp.sql;
2.windows系统
source d:/emp.sql;
出现乱码的按步骤执行以下命令
1.先把数据库删除掉 drop database newdb3;
2.set names utf8;
3.source d:/emp.sql;
4.set names gbk;
5.select * from emp;
is null 和 is not null
查询上级领导为空的员工姓名
select ename from emp where mgr is null;
select ename,sal,comm from emp where comm is null;
select ename,sal from emp where mgr is not null;
去重 distinct
查询员工所从事的职业有哪几种
select distinct job from emp;
比较运算符 > < >= <= = !=/<>
查询工作不是销售的员工姓名和工作
select ename,job from emp where job!='销售';
select ename,job from emp where job<>'销售';
and和or
and:类似java中的&&
or:类似java中的||
1.查询1号部门中工资低于1500的员工信息
select * from emp where deptno=1 and sal<1500;
2.查询2号部门员工或工资高于2000的员工姓名、工资和部门编号
select ename,sal,deptno from emp where deptno=2 or sal>2000;
between x and y 包含x和y
查询工资在2000到3000之间的员工信息
select * from emp where sal between 2000 and 3000;
select * from emp where sal>=2000 and sal<=3000;
in(x,y,z)
查询工资为800,3000,1500的员工信息
select * from emp where sal in(800,3000,1500);
select * from emp where sal=800 or sal=3000 or sal=1500;
模糊查询 like
%代表0或多个未知字符
_代表1个未知字符
举例:
1.以x开头: x%
2.以y结尾:y%
3.以a开头b结尾
4.第二个字符是:_a%;
5.包含a:%a%;
查询名字中以孙开头的员工姓名
select ename from emp where ename like '孙%';
排序 order by
格式: order by 字段名 asc(升序,默认) /desc (降序)
1.查询每个员工的姓名和工资要求按照工资升序排序
select ename,sal from emp order by sal; (降序 desc)
分页查询 limit
格式: limit 跳过的条数,请求的条数
举例
1.请求第一页的三条数据 limit 0,3
2.第三页的5条数据 limit 10,5;
3.第8页的6条数据 limit (8-1)*6,6;
查询工资最高的前三名 姓名和工资
select ename,sal from emp order by sal desc limit 0,3;
数值计算 + - * / %
查询每个员工的姓名,工资和年终奖(年终奖=工资*5)
select ename 姓名,sal '工资',sal*5 as '年终奖' from emp;
聚合查询
对多条数据进行统计查询
求和,平均值,最大值,最小值,计数
1.求和 sum(字段名)
查询1号部门的工资总和
select sum(sal) from emp where deptno=1;
2.平均值 avg(字段名)
查询2号部门的平均工资
select avg(sal) from emp where deptno=2;
3.最大值 max(字段名)
select max(sal) from emp where job like '%销售%';
4.最小值 min(字段名)
5.计数 count(字段名)
查询2号部门的人数
select count(*) from emp where deptno=2;
分组查询
题目中只要出现类似:每个、每种、一般都使用分组查询
1.查询每个部门的平均工资
select deptno,avg(sal) from emp group by deptno;
3.查询每种工作的人数
select job,count(*) from emp group by job;
4.查询每个部门工资大于1500的员工人数
select deptno '部门',count(*) '人数' from emp where sal>1500 group by deptno;
5.查询1号和3号部门中每个部门的最低工资
select deptno,min(sal) from emp where deptno in(1,3) group by deptno;
having
where后面只能写普通字段的条件
having结合group by使用,后面写聚合函数的条件
关键字的顺序:
select ... from 表名 where ... group by ... having .... order by ... limit ...;
1.查询每个部门的平均工资,要求平均工资大于2000
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;
2.查询工资在1000-3000之间的员工,统计每个部门的编号,工资总和,平均工资,过滤掉平均工资低于2000的部门,最后按照平均工资升序排序
select deptno,sum(sal),avg(sal) from emp where sal between 1000 and 3000 group by deptno having avg(sal)>=2000 order by avg(sal);
别名的方式:
select deptno,sum(sal),avg(sal) a from emp where sal between 1000 and 3000 group by deptno having a>=2000 order by a;
3.查询有上级领导的员工,每个部门的编号,最高工资,最低工资,工资总和,要求工资总和大于5400,最后按照工资总和降序排序
select deptno,max(sal),min(sal),sum(sal) s from emp where mgr is not null group by deptno having s>5400 order by s desc;
综合练习题
查询没有上级领导的员工编号,姓名,工资
select empno,ename,sal from emp where mgr is null;
查询有奖金的员工姓名和奖金
select ename,comm from emp where comm>0;
查询名字中包含精的员工姓名和工资
select ename,sal from emp where ename like '%精%';
查询名字中第二个字是八的员工信息
select * from emp where ename like '_八%';
查询1号部门工资大于2000的员工信息
select * from emp where deptno=1 and sal>2000;
查询2号部门或者工资低于1500的员工信息
select * from emp where deptno=2 or sal<1500;
查询工资为3000,1500,5000的员工信息按照工资升序排序
select * from emp where sal in(3000,1500,5000) order by sal;
查询每种工作中有领导的员工人数按照人数降序排序
select job,count(*) 人数 from emp where mgr is not null group by job order by 人数 desc;
查询3号部门的工资总和
select sum(sal) from emp where deptno=3;
查询每个部门工资大于1000的员工人数,按照人数升序排序
select deptno,count(*) 人数 from emp where sal>1000 group by deptno order by 人数;
查询每种工作中有领导的员工人数按照人数降序排序
select job,count(*) 人数 from emp where mgr is not null group by job order by 人数 desc;
查询所有员工信息,按照部门编号升序排序,如果部门编号一致则工资降序
select * from emp group by deptno,sal desc;
查询有领导的员工,每个部门的编号和最高工资
select deptno,max(sal) from emp where mgr is not null group by deptno;
查询有领导的员工,按照工资升序排序,第3页的2条数据
select * from emp where mgr is not null order by sal limit 4,2;
子查询(嵌套查询)
1.查询工资高于平均工资的员工信息
select * from emp where sal>(select avg(sal) from emp);
2.查询员工表中工资最高的员工信息
select * from emp where sal=(select max(sal) from emp);
3.查询工资高于2号部门平均工资的员工信息
select * from emp where sal>(select avg(sal) from emp where deptno=2);
4.查询和孙悟空相同工作的其它员工信息
select * from emp where job=(select job from emp where ename='孙悟空') and ename!='孙悟空';
关联查询
同时查询多张表的查询方式成为关联查询
如果关联查询不写关联关系,会得到两张表的乘积,这个乘积成为笛卡尔积,这是一个错误的查询结果,工作中切记不要出现
1.查询每个员工的姓名和对应的部门名
select e.ename,d.dname
from emp e,dept d
where e.deptno=d.deptno;
2.查询孙悟空的部门信息
select d.*
from emp e,dept d
where e.deptno=d.deptno
and e.ename='孙悟空';
关联查询的三种查询方式
1.等值连接
格式: select * from A,B where A.x=B.x and A.age=18;
2.内连接
格式: select * from A join B on A.x=B.x where A.age=18;
1.查询每个员工的姓名和对应的部门名
select e.ename,d.dname
from emp e join dept d
on e.deptno=d.deptno;
2.查询神仙部的员工信息
Select
e.*
From
emp e join dept d
On
e.deptno=d.deptno
Where
d.dname='神仙';
等值连接和内连接查询到的数据都是两张表的交集数据
insert into emp(empno,ename,sal) values(12,'灭霸',500);
3.外连接
当需要查询一张表的全部和另一张表的交集数据时,使用外连接
格式: select * from A left/right join B on A.x=B.x where A.age=18;
1.查询所有的员工信息和对应的部门名
SELECT
e.*,d.dname
FROM
emp e LEFT JION dept d
ON
e.deptno=d.deptno;
2.查询所有部门的名称和对应的员工姓名
SELECT
d.dname,e.ename
FROM
emp e RIGHT JION dept d
ON
e.deptno=d.deptno;
关联查询总结
1.如果需要同时查询多张表的数据则使用关联查询
2.关联查询必须写关联关系
3.关联查询有三种方式:等值连接、内连接和外连接
4.查询两张表的交集数据时使用等值连接或内连接(推荐)
5.查询两张表中的一张表的全部和另外一张表的交集使用外连接
关联关系(了解)
关联关系指创建表时,表与表之间存在的业务关系
1.1对1:有AB两张表,A表中的一条数据对应B表中的一条数据,同时B表中的一条数据对应A表中的一条
2.1对多:有AB两张表,A表中的一条数据对应B表中的多条数据,同时B表中的一条数据对应A表中的一条
3.多对多:有AB两张表,A表中的一条数据对应B表中的多条数据,同时B表中的一条数据对应A表中的多条数据,多对多建立关系需要建立一张关系表.
JDBC
Java DataBase Connectivity: Java数据库连接,实际上JDBC是Sun公司提供的一套连接数据库的API(Application Programming Interface 应用程序
接口)
为什么使用JDBC:因为java语言中有可能连接多种数据库,如果没有JDBC,java程序员每一种数据库都要学习一套新的api,使用JDBC后,
各个数据库厂商根据JDBC中的方法声明写方法的实现,对应Java程序员来说只需要掌握JDBC中方法的调用就能通过一套代码访问如何数据库
如何使用JDBC
1.创建一个Maven工程
2.下载MySQL驱动(JDBC接口的实现类,就是一个jar包)
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
可以从maven.tedu.cn网站中搜索mysql 找到指定的版本坐标
3.创建Demo01.Java类,在main方法中写以下内容
//1.注册驱动 告诉虚拟机使用的是哪个数据库软件
Class.forName("com.mysql.jdbc.Driver");
//2.获取连接对象
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/newdb3", "root", "root");
System.out.println(conn);
如果电脑上安装的MySQL版本是8.0以上的版本,有以下几点需要注意
1.下载jar包时就不能是5.1.6版本了,必须是8.0以上版本
2.驱动类的地址 com.mysql.cj.jdbc.Driver
3.连接地址用以下写法:
jdbc:mysql://localhost:3306/newdb3?useSSL=false&serverTimezone=Asia/Shanghai
Statement执行SQL语句的对象
1.execute(sql):此方法用于执行数据库相关和表相关的SQL语句,返回一个布尔值,代表是否有结果集(不代表执行成功与否)
2.executeUpdate(sql):此方法执行增删改的相关SQL语句,返回值是一个int值,代表生效行数
3.ResultSet rs=executeQuery(sql):用于执行查询的SQL,返回值是结果集,里面装着查询回来的所有数据
属性配置文件
把在代码中写死的driver,url,username,password写到配置文件中便于后期维护
url=jdbc:mysql://localhost:3306/newdb3?useUnicode=true&characterEncoding=UTF-8 ?后面代码防止中文乱码
//创建读取配置文件数据的对象
Properties p = new Properties();
//获取文件流
InputStream ips = Demo02.class.getClassLoader().getResourceAsStream("jdbc.properties");
//把文件加载到属性对象中
p.load(ips);
//读取数据
String name = p.getProperty("name");
String age = p.getProperty("age");
System.out.println(name+":"+age);
连接池 DBCP DataBaseConnectivityPool
为什么使用连接池
如果不使用连接池,每一次业务请求都需要建立对应的一个数据库连接,如果有一万次请求则有一万次的开关连接,频繁开关连接
浪费资源,使用连接池可以将连接重用从而提高执行效率
如何使用连接池
1.在pom文件中导入连接池的jar包
<dependency>
<!-- 数据库连接池jar包坐标 -->
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
2.代码:
//创建数据库连接池对象
BasicDataSource ds = new BasicDataSource();
//设置数据库连接信息
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/newdb3");
ds.setUsername("root");
ds.setPassword("root");
//设置初始连接数量
ds.setInitialSize(3);
//设置最大连接数量
ds.setMaxActive(5);
//从连接池中获取连接 抛异常
Connection conn = ds.getConnection();
System.out.println(conn);
实现登录功能
创建用户表并插入几条数据
create table user(id int primary key auto_increment,username varchar(10),password varchar(10));
insert into user values(null,'libai','123456'),(null,'Tom','admin');
登录SQL:
select count(*) from user where username='libai' and password='123456';
SQL注入:往写值的地方,写进去了SQL语句破坏了原SQL语句的逻辑称为SQL注入 ' or '1'='1
select count(*) from user where username='fserff' and password='' or '1'='1'
通过预编译的SQL执行对象解决SQL注入问题
如果SQL语句中没有变量则使用Statement,有变量则使用prepareStatement
获取自增主键的值
//设置获取自增主键值
PreparedStatement ps =
conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
//替换问号内容
ps.setString(1, name);
ps.setInt(2, sal);
ps.executeUpdate();
System.out.println("保存完成!");
//开始获取自增主键值
ResultSet rs = ps.getGeneratedKeys();
while(rs.next()) {
int id = rs.getInt(1);
System.out.println("自增主键值:"+id);
}
数据库元数据
//获取数据库元数据对象
DatabaseMetaData dbmd = conn.getMetaData();
System.out.println("数据库名:"+dbmd.getDatabaseProductName());
System.out.println("数据库驱动版本:"+dbmd.getDriverVersion());
System.out.println("用户名:"+dbmd.getUserName());
表元数据
//获取和表相关的元数据
String sql = "select * from emp";
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery(sql);
//获取元数据对象
ResultSetMetaData rsmd = rs.getMetaData();
//获取字段数量
int count = rsmd.getColumnCount();
//遍历字段名和类型
for (int i = 0; i < count; i++) {
String name = rsmd.getColumnName(i+1);
String type = rsmd.getColumnTypeName(i+1);
System.out.println(name+":"+type);
}
###代码介绍
1. Demo01 测试DBUtils
2. Demo02 读取配置文件
3. Demo03 连接池
4. Demo04 登录练习 SQL注入
5. Demo05 批量操作 Statement
6. Demo06 批量操作 PreparedStatement
7. Demo07 分页查询练习
8. Demo08 获取自增主键值
9. Demo09 球队球员练习
10. Demo099 球队球员练习高级版
11. Demo10 元数据