MySQL笔记

笔记 专栏收录该内容
2 篇文章 0 订阅

一、基础

MySQL

一、数据库的相关概念(了解)

1、数据库的发展阶段

1.1.人工管理阶段:

​ 没有存储设备,数据不能共享

1.2文件管理阶段

​ 有存储设备,有操作系统和文件管理系统,此时数据可以以文件的形式和进行存储。可以进行增删改查操作

1.3数据库管理阶段

​ 数据库软件,可以大量的存储数据,冗余小,方便数据的管理和分享

2、数据库的概念

2.1 DB(存储数据的软件)

​ DataBase 数据库的含义,指的是长期保存在物理存储设备,按照某一定的数据结构来组织,存储和维护数据的仓库(数据的集合),可以被各种用户和各种程序共享。

2.2 DBMS

​ Data Base Management System,指的是用来管理和操作数据的大型软件。用来建立、使用、维护数据,对数据库进行统一的管理和控制,以保证数据的完整性和安全性。用户可以通过数据库管理系统来访问数据库中的数据。

3、常用关系型数据库

3.1概念

建立在关系模型上的数据库,称之为关系型数据库。

关系模型:一对一、一对多、多对多,等关系模型

3.2常见关系型数据库

Oracle :是Oracle 公司的数据库产品。

MySQL : 是一种关系型数据库管理系统。由瑞典 MySQL AB 公司研发,后被Sun公司收购,Sun在2009年4月20日被 Oracle 收购,目前属于 Oracle 旗下。是目前最流行的关系型数据库管理系统之一。

SQLServer:是微软推出的关系型数据库管理系统。

Access:微软旗下的数据库产品

DB2:IBM公司旗下数据库产品

4、表的概念(非常重要)

a 数据表示数据库的存储单位,数据库是由多个表组成的

b 数据表示二维结构,由行(row)和列(column)组成。

c 行是横排数据,一行数据也称为记录(record)

d 列是纵排数据,列也称为字段(Field)

e 表与表之间也存在着关系:一对一、一对多、多对多

二、数据库的安装与连接

1.安装

2.连接

三结构化查询语言的介绍(重点掌握)

1、简介

​ SQL: Structure Query Language, 结构化查询语言, SQL最早是被美国国家标准局(ANSI)确定为关系型数据库语言的美国标准。后来被国际化标准组织(ISO)采纳为关系型数据库的国际标准。

每个数据库管理系统都支持国际标准的SQL。 : 普通话

但是每个数据库管理系统也都在国际标准的基础上,增加了自己的拓展。 : 方言

​ SQL其实是一种标准化的语言,允许我们可以对一个数据库进行操作,例如: 增、删、改、查

而这些操作: 创建项目(Create)、查询(Read)、修改(Update)、删除(Delete): 被称为 CRUD 操作

注意:数据库脚本文件的扩展名(.sql)

2、分类

DDL(Data Definition Language), 数据定义语言, 用来定义数据库对象(数据库、表、列)

DML(Data Manipulation Language), 数据操作语言, 用户通过它可以实现对数据库的基本操作。例如,对表中数据的查询、插入、删除和修改。(增、删、改)

DQL(Data Query Language), 数据查询语言, 用来从数据库中查询数据

DCL(Data Control Language), 数据库控制语言, 用于设置访问权限和安全级别

TCL:事务控制语言

3、数据库操作语言(DDL)

用来创建、删除、修改数据库对象的语言,比如表结构,数据库等等

3.1创建数据库
#采用默认的字符集创建数据库
create database my_first_database;	 
#采用指定的字符集创建数据库
create database my_first_database character set gbk;	
3.2库操作常用语法(建议记住)
#操作:
#建立库:
create database summ[default character set charname][collate utf8_general_ci];(不区分大小写)

#删除库:
drop database summ;

#使用(切换)数据库:
use databaseName;

#修改数据库的字符集:
alter database databaseName character set charname[collate utf8_general_ci];——《collate gbk_chinese_ci》;


#显示数据库:(所有的数据库)
show databases;

#查看当前数据库:
select database();

#查看创建数据库语法:
show create database test;


#删除表数据、保留表结构:
truncate
3.3表操作常用语法(完全记住):

​ 数据在数据库中是以表的形式进行存储的,一个表设有若干个字段,数据按照这些字段进行存储。

#建表语句:
create table tableName(
	colName1 type(),
	colName2 type(),
	···,
	)[engine=innodb][default charset=charname];	
#删除表:
drop table tableName;
#修改表名称:
alter table tableName rename newTableName;
#查看建表语法:
show create table tableName;
#备份一张表结构和表数据:
create table tableName2 as select*form tableName1;
#备份表结构:
create table TableName2 like tableName1;
#查看表结构:
desc dastudent;
show columns from tableName;
#查看数据库支持的字符集:
show variables like '%char%';


#追加字段(列):
alter table tableName add colName type;(只能在表最后追加)
#删除字段(列):
alter table tableName drop colName;
#修改字段(列)类型:
alter table tableName modify colName newType;
#修改字段(列)名称:
alter table tableName change colName newColName newType;


#查看表中数据:
select*from tableName1;
3.4常用字段类型
a:字符串类型
	varchar(num):表示可变长度字符串类型——节省空间——后面必须跟带有数字的小括号
	char(num):表示固定长度字符串类型
b:数值类型
	int: 整数类型——可以不跟小括号——》(最大跟10)
	double(4,2):表示这个double数据最多只能有4位, 其中还需要有2位是小数部分, 12.32
	float(m,n):单精度类型
c:日期类型
	date:YYYY-MM-DD
	datetime:YYYY-MM-DD HH:mm:ss
	timestamp:YYYY-MM-DD HH:mm:ss()
	这两个时间类型一样,唯一区别就是timestamp可以自动获取当前系统的时间

实例:

create table Student(
stuid int(10),		#——》最大为10
name varchar(30),
gender char(1),		#——》只能为1
age int(2),
academy varchar(30),
major varchar(30),
address varchar(30)
);
3.5字段默认值

​ 在建表期间,可以使用 default 关键字,来指定字段的默认值,当插入数据时,如果不对此字段进行赋值操作,那么此字段使用默认值。

#案例1:
create table employee(
eid int default 1000,
ename varchar(20),
gender char(1) default 'f'
);

​ 在建表期间,可以使用 comment 关键字,来为指定字段添加备注

#案例2:备注每个字段的含义
drop table [ if exists] employee;	
create table employee(
eid int default 1000 comment '员工编号',
ename varchar(20) comment '员工姓名',
gender char(1) default 'f'  comment '员工性别,值只有f和m'
);

4修改表数据的语言(DML)

4.1 作用:

​ 用于对表中数据进行增加,删除,修改操作的。关键字:insert 、into 、delete、 update;

4.2常用语法

注意:

1、除了int与double不用单引号,其他都必须用 ’ ’ 来输入。

2、null较为特殊,在条件中使用的时候不用《=》用的是《is》或者是《is not》;——》null在做赋值的时候依旧使用《=》。

#增加表记录(行数据):
#写法1:给所有字段赋值
insert into tableName values (value1,value2....)  
#写法2:给部分字段赋值
insert into tableName(colName1,colName2.....)values (value1,value2....)

#删除表数据:
delete from tableName:删除所有的记录。
delete from tableName where 条件

#修改表数据:
update tableName set colName=newValue [,colName = newValue] [where 条件]#——》什么也不加是全部。
修改mysql15.7服务端的字符集

**报错:**ERROR 1366 (HY000): Incorrect string value: ‘\xD5\xC5\xC8\xFD’ for column ‘sname’ at row 1

第二步:找到C:\ProgramData\MySQL\MySQL Server 5.7\my.ini
		[mysql]
			no-beep
			default-character-set=utf8 :解开注释并添加
		[mysqld]
			character_set_server=utf8	:添加
第三步:重启服务项
		计算机-管理-服务-mysql57


二、进阶

MySQL的重点

1、数据查询语言
2、约束
3、关键查询

零、数据控制语言(熟悉DCL)

1、作用

​ 用于创建用户,授予权限,撤销权限等操作。

create user

grant

revoke

alter user

创建用户:(使用超级管理员root进行操作)

create user username@localhost(ip) identified password;

修改用户密码:(使用超级管理员root进行操作)

alter user userrName@localhost(ip) identified by '654123';

查看用户权限==(使用超级管理员root进行操作)==

show grants for userName@localhost(ip);

授权:(使用超级管理员root进行操作)

grant 权限名[,权限名....]on dbname. * to userName@localhost(ip);
DDL:create、alter、truncate、create view......
DML:insert、update、delete
DQL:select

#授予所有权限
grant all PRIVILEGES on dbname. * to userName@localhost(ip);

撤销权限:(使用超级管理员root进行操作)

revoke 权限名[,权限名....]on dbname.* from userName@localhost;(ip)

刷新权限

flush PRIVILEGES;

案例:

create user wangchongming@localhost IDENTIFIED by '123456';
alter user wangchongming@localhost IDENTIFIED by '654321';
#对用户授予数据库db1901 创建和查询权限
grant create,select on db1901.* to wangchongming@localhost;
#撤销权限,使用root来撤销
revoke CREATE on db1901.* from wangchongming@localhost;
#查询用户权限
show grants for wangchongming@localhost; 

一、数据查询语言《重点掌握》(DQL)

1、基本语法

1.1.子句构成
select colName[,colName2...] from tableName [where...][group by...][having....][order by...]
1.2执行顺序()

​ a. from子句 基于表进行查询

​ b. where子句 进行条件限制过滤

​ c. group by 子句 按照字段进行分组查询…

​ d. having 子句 对分组查询再一次进行条件过滤

​ d. select 子句 选择哪些字段进行查询

​ f. order by 子句 按照字段进行升序降序,进行排序

1.3一个查询中必须要有select子句和from子句

2、基本查询

2.1计算
#案例:
#案例1:查询员工表的所有字段信息
select * from emp;——相当于——》
select empno,ename,job,mgr,hiredate,sal,somm,from emp;
#案例2:进行简单的数学运算,此时,可以不写from子句。计算1与2的和。
select 1+2;
#案例3:计算 4与5的2倍的和。
select 4+5*2;
#案例4:计算4与5和的2倍。
select (4+5)*2;
2.2 别名
select colName1 as nickName1,colName2 as nickName2,....from tableName as nickTableName.
#其中:《as》可以省略

#案例5:
#查询所有的员工信息,按照工资降序排序(默认升序排序)
select * from emp order by sal desc;

#查询员工的员工编号,员工姓名,职位,工资,不能号。表头使用汉字的类别名。
select empno '员工编号' ,ename as 员工姓名 ,job '职位' , sal '工资', deptno '部门号'from emp;
select a.empno,a.ename,a.deptno from emp a; 

3、where 子句

​ 是一个条件字句,可以确定一个数据筛选的条件。按照这些条件进行数据的过滤,取出满足条件的数据进行操作。

用法: 在where字句后面, 可以有若干个符号, 用来拼接一个条件

=			    : 相等比较, 相当于Java中的==
!=		<>	    : 不等比较
>  >=  <  <=	: 大小比较
and   or   not	: 与、或、非
between...and...: 在指定范围内,[]
in(set)			: 在某个集合中包含
not in(set)		: 没有在某个集合中包含
>all(set)		: 大于某个集合中的最大的
<all(set)		: 小于某个集合中的最小的
>any(set)		: 大于某个集合中的最小的
<any(set)		: 小于某个集合中的最大的
is null			: 判断为空
is not null		: 判断不为空
!!!注意:mysql不支持简单的集合操作,但是支持子查询

案例:

#查询工资大于1500的所有员工的信息
select * from bostonemp where sal>1500;

#查询不是10部门的员工信息
select * from bostonemp where deptno != 10;

#查询10号部门,工资不小于1000的员工信息
select * from bostonemp where deptno = 10 and sal>= 1000;

#查询工资在【1000,2000】区间内的所有员工的姓名,入职日期,工资和部门编号
select * from bostonemp where sal<= 2000 and sal>= 1000;
select * from bostonemp where sal between 1000 and 2000;

#查询工资是500,1500,3000的所有员工
select * from bostonemp where sal = 500 or sal= 3000 or sal=1500;
select * from bostonemp where sal in (500,3000,1500);#在小括号内,注意不是区间!!

#集合(1000,1500,1800),查询大于集合中所有工资的所有员工信息
select * from bostonemp where sal>(1000,1500,1800);
3.1模糊查询 like
_:占位符,表示匹配任意一个字符
%:表示匹配任意N个字符,大于等于0
%s——》末尾是s的筛选条件
%a%——》包含a的筛选条件

#查询姓名首字母是J的员工的信息
select * from bostonemp where ename like 'j%';
#查询姓名中第二个字母是o的员工信息。
select * from bostonemp where ename like '_o%';
#查询姓名是五个字母的员工信息
select * from bostonemp where ename like '_____';

4、group by子句

4.1需求:

有的时候,需要分组统计一些,最大值,最小值,平均值,和,总数之类的这样的信息,需求:需要进行分组查询

4.2聚合函数:也叫分组函数
count()		 :#统计每组满足的记录总数
count(*)	:#与count(job)的结果是一样的。
max()		:#min():统计每组满足条件的最大值、最小值
avg()		:#统计每组满足条件的平均值
sum()		 :#统计每组满足条件的累加总和——不统计null

#案例:
#统计员工表中,最高工资数,最低奖金,工资总和,总人数,平均奖金。——》将整个表当做一组
#注意:统计自动过滤null,所以选择字段的时候不能有null,可以用*代替
#注意:所有的聚合函数都会直接忽略字段为 null 的那条记录,不进行统计。
select max(sal),min(comm),sum(sal),count(*),avg(comm) from emp;
4.3聚合函数处理null值
#可以使用ifnull(colName,value)
ifnull(colName,value):#如果colName对应的值不为空,就使用本身的值,如果为null,使用value.

#案例:查询每个部门中的每种职位的最高工资,最低工资,工资之和
select deptno,job ,max(sal),min(sal),sum(sal) from emp group by job,deptno;
#案例: 查询所有员工的平均工资,平均奖金 使用ifnull函数
select avg(ifnull(sal,0)),avg(ifnull(comm,0)) from emp;
4.4分组 group by

将查询到的结果集,按照某一个字段进行分类。这个字段作为分组的依据,这个字段对应的值相同的为一组。

只能按照具体的值来进行分组不能按照范围来分组。

# 分组 统计每组的人数(执行逻辑先根据group_id 来进行分组,每组分别执行聚合函数count(),并将最终的group_id,和人数 以组为单位返回)
select group_id, count(*) from t_score group by group_id;

# 统计每个分组的人数、Java成绩和、Java成绩平均分
select group_id, count(*), sum(score_java), avg(score_java) from t_score group by group_id;

# 统计每个分组中不及格的人数
# 执行逻辑:(注意:count()只统计数量,它才不管你是不是及格的,所以你得把符合条件的信息给它,它进行统计)先用where 将及格的人员信息过滤掉 ,然后再按照group_id进行分组,最后以组为单位统计每组中的数量

# 备注: 这里其实是将score_java >= 60的数据都剔除,然后用剩余的数据进行分组
select group_id, count(*) from t_score where score_java < 60 group by group_id;

5、having子句

类似于where,也可以对数据做一些约束,起到在过滤的作用。只能使用在分组查询子句后面

having与where的区别:

having是对分组后的数据进行过滤, where是对分组前的数据进行过滤;where后面不允许写聚合函数。都是指的子句

#查询部门平均工资大于1000部门号,平均工资。
select deptno,avg(ifnull(sal,0)),max(sal) avg_sal from emp group by deptno having avg(ifnull(sal,0)) >1000;
#查询每种职位的最高工资大于1500的职位、最高工资,平均工资,平均奖金。
select job,max(sal),avg(ifnull(sal,0)),avg(ifnull(comm,0)) from emp group by job having max(sal)>1500;

6、order by子句

#用于查询排序的,通常放置在一个查询语句的最后部分
语法:order by colName [asc升序|desc降序] [,colname][asc升序|desc降序]

#查询emp表中所有的数据,然后根据部门的编号进行升序排列,如果部门编号一致,根据员工的编号进行降序排列
select * from emp order by deptno asc,empno desc;

7、去重查询

有的时候,我们需要查询表中有哪些不同的数据,不需要重复出现,此时可以使用distinct关键字进行去重处理。

注意:distinct关键字只能放置在select关键字之后。

#案例:
#查询有那些部门号
#去重查询
select distinct deptno from emp;
#查询员工表中有那些职位
select distinct job from emp;

8、分页查询

需求:当一页的数据量过大时,我们可以进行分页显示操作。

关键字limit

#使用:limit m,n;
#m表示从第几条开始查询,n表示一页有多少数据。
#注意:mysql的索引与java一样,从0开始
#注意:分页查询时,都必须是在排序状态下,然后再分页。

#每页5条记录,查询第二页的数据。
select empno,ename from emp limit 5,5;
#每页3条记录,查询第四页的数据。
select * from emp limit 9,3;
#每页3条记录,查询第五页的数据,按照工资降序。
select * from emp order by sal desc limit 12,3;

9、条件查询if与case-when

#if(arg1,arg2,arg3);
#arg1:关系表达式
#arg2:值1
#arg3:值2
#案例1:
select t.*, if(hiredate<'1985-1-1','老员工','新员工') '年限' from emp t;

#case 
# when expr1 then 值1
# when expr2 then 值2
# .....
# else 值n
#end
#案例1:
select t.*,
case 
when hiredate<'1985-1-1' then '老员工' 
else '新员工' 
end '年限' from emp t;

#案例:
select t.*,
case 
when hiredate <'1983-1-1' then '一级员工'
when hiredate <'1985-1-1' then '二级员工'
when hiredate <'1988-1-1' then '三级员工'
else '四级员工'
end '等级'
from emp t;

二、约束(重点掌握)

约束是对表进行的一种强制性的校验规则。在进行DML操作时,必须符合约束条件,否则不能执行,约束的全称,完整性约束条件。用于保证表中数据的完整性和安全性。

1、非空约束:not null 简称NN

如果对字段设置了not null,在DML操作,不能为空

#建表写法:
create table tableName(
tname varchar(20)not null
);

#建表后写法:
alter table tableName modify colName type not null;


#案例:
#非空约束
#建表:temp_1
#      tid int
#      tname   varchar(20)    非空约束设置
#      tage int
#插入数据: 1001   '张三'   21
#           1002    null    22
create table temp_1(
tid int,
tname varchar(20) not null,
);


2、唯一性约束:unique,简称UK

用来约束这一列的数据不允许重复

和主键不同: unique可以是NULL, 主键不允许NULL

#唯一性约束
create table temp_2(
tname varchar(20) not null,		#————非空
idcard varchar(20) unique		#————唯一约束
);

3、主键约束:primary key,简称PK

**主键 : **作为一行数据的唯一的标志,主键不允许重复,也不允许为空。通常用做记录的唯一表示来使用

#选择主键约束的字段要求:
#1、对业务需求没有意义的字段,比如序号
#2、如果设置了主键约束,name字段最好不要人为的修改,而是自动生成。
#使用auto_increment(自增序列)——》约束某一个键,如果不对这个键进行赋值的情况下,这个键对应的值会在上一个的基础上自增1
#3、不建议对动态赋值的字段进行设置约束,比如时间戳

#建表时写法:
create table tableName(tid int primary key auto_increment);

#建表后写法:
alter table tableName add primary key(deptno);


#案例:
#主键约束:
#建表
create table temp_3(
tid int primary key auto_increment,
tname varchar(20) not null
);

4、外键约束foreign key,简称FK(视情况看要不要添加,影响删除及其他操作)

外键约束是指 字段A的值,依赖于字段B的值。这两个字段可以在同一张表中,也可以在不同的表中。字段A所在的表称之为从表(副表),字段B所在的表称之为主表(父表)。字段A值也可以存null.字段B必须为主键约束——》员工编号,部门编号

#建表时写法:
create table temp_4(
tid int  primary key auto_increment,
tname varchar(20),
tmgr int,
constraint fk_mgr_tid foreign key(tmgr) references temp_4(tid))
#约束——约束名——谁依赖于——那张表的——谁

#建表后写法:
alter table tableName1 add constraint consName foreign key(tmgr) references temp_4(tid))


#案例:
create table temp_4(
tid int  primary key auto_increment,
tname varchar(20),
tmgr  int,
constraint fk_mgr_tid foreign key(tmgr) references temp_4(tid)
);
insert into temp_4 values (1001,'zs',null);
insert into temp_4 values (1002,'zs',null);


select * from emp order by comm desc;

alter table emp add constraint con_fk_name foreign key(deptno) references dept(deptno);
show create table dept;
#建表后修改主键约束
alter table dept add primary key(deptno);
select * from dept;

5、检查约束:check,简称ck。mysql不支持,可以使用枚举代替。

#正常的建表语句:mysql不生效
create table tableName(
tgender char(1) check(tgender in('f','m'))
);

#枚举
create table tableName(
tgender enum('f','m')
);


#案例:
#create table temp_5(
#tid int,
#tname varchar(20),
#tgender char(1) check(tgender in('f','m'))   #语法通过,但是不生效
#);



create table temp_6(
tid int,
tname varchar(20),
tgender enum('f','m')            #枚举写法
);
insert into temp_6 values (1001,'zs','m');

三、关联查询 即为:多表查询(重点掌握)

1、概念:

有的时候,我们的业务需求数据不只是在一张表中,而是在两张或两张以上的表中。那么此时的查询操就要涉及到多表查询,即为关联查询

#案例:最简单的关联查询
select * from emp,dept;#——会出现笛卡儿积
1.2、笛卡尔积

当做关联查询时,表A中的每一条记录都与每一条记录都会与表B中的所有记录进行匹配组合。表A—m数据,表B—n数据,则查询结果为m*n条记录数据,此值被称之为笛卡儿积。通常没有意义。

连接查询会出现的问题: 笛卡尔积——解决方法通过添加条件来达到去除笛卡尔积的目的。

假设有连个集合 A = {a, b} B = {1, 2, 3}

A 和 B 的笛卡尔积: {(a,1), (a,2), (a,3), (b,1), (b,2), (b,3)}

1.3、等值查询

​ 在做关联查询时,使用有关系的字段进行等值条件的限制操作。我们称之为等值查询。

#等值查询
# 查询每个员工的姓名,职位,部门名称。
select ename,job,dname from emp,dept where emp.deptno=dept.deptno;
#查询部门中的每个员工的姓名,职位,部门名称
select e.ename,e.job,d.dname from emp e,dept d where e.deptno = d.deptno;

2、内连接

查询在两张表中同时出现的数据。如果内连接中左表或者右表的关联词为null,则不会被查询出来

#语法: 
from tableName1 [inner] join tableName2 on 条件
#注意:与等值查询的效果是一样的。


#案例
#内链接:将上的案例改为内链接。 
select ename,job,dname from emp join dept on emp.deptno = dept.deptno;

3、外连接

什么外连接,就在表中多加哪个表的值

查询在两张表中都出现的数据,和在其中的一张表中没有出现的数据

3.1、左外连接

查询两张表中共有的数据,和左表中的其他数据

from tableName1 left join tableName2 on 条件

#案例
select * from emp left join dept on emp.deptno = dept.deptno;
3.2、右外连接

查询两张表中共有的数据,和右表中的其他数据

from tableName1 right join tableName2 on 条件

#案例:
select * from emp right join dept on emp.deptno = dept.deptno;

外连接的两张表分为主表和从表。主表的数据都显示,从表的数据只显示满足条件,过滤掉从表中不满足条件的数据。——》叫什么名字哪个表就是主表

4、合并结果集(集合查询)

union(去重)/union all(不去重);

两个查询语句使用上述的关键字连接即可。注意:两个查询语句的 列字段名,字段个数,必须对应上。

#集合查询
#查询20号部门的员工 和查询30号部门的员工,做集合关联。
select * from emp  where deptno =20 union select * from emp where deptno = 30;
#查询 10、20号部门的员工信息 和 查询20、30号部门的员工信息 做集合关联。
#分别使用union/union all 连接,总结区别。
select * from emp  where deptno in (10,20) union all select * from emp where deptno in(20,30);
#查询10部门的员工的员工编号,员工姓名,职位。 再和20号部门的员工查询做集合关联。
select empno,ename,job from emp where deptno = 10 union select empno,ename,job from emp where deptno = 20;

四、高级关联查询即子查询《重点掌握》

当一个查询语句A所需要的数据不是直接在表中体现,而是有另外一个查询语句B查询出来的,A为主查询,B就是子查询语句。

1、在where子句中

#子查询
#案例:查询工资大于员工编号为7369这个员工的所有员工信息。
select * from emp where sal>(select sal from emp where empno = 7566);
#案例:查询工资大于10号部门的平均工资的所有员工信息
select * from emp where sal >(select avg(ifnull(sal,0)) from emp where deptno =10);
#案例:查询工资大于10号部门的平均工资的非10号部门的员工信息。
select * from emp where sal >(select avg(ifnull(sal,0)) from emp where deptno =10) and deptno != 10;


比较好的案例:

#案例1:查询emp表中每年入职的人数(提高题)
select date_format(hiredate, '%Y') yer,count(*) from emp group by yer;

#案例2:查询emp表中工资最高的员工信息
select * from emp having sal=(select max(sal) from emp);
select * from emp having max(sal);		#错误结果

#案例3:查询工资最低的员工的同事们的信息 (同事=相同job)
select * 
from emp a left join (select ename,job from emp where sal=(select min(sal) from emp)) b on a.job=b.job
where a.ename != b.ename;

#案例4:查询名字为king的部门编号和部门名称
select deptno,dname from dept where deptno=(select deptno from emp where ename='king');
select a.deptno, b.dname from emp a,dept b where a.deptno=b.deptno and a.ename='king';

#案例5:查询平均工资最高的部门信息(最大难度)
#每个部门的平均工资
#select avg(ifnull(sal,0)) from emp group by deptno
#最高平均工资的部门
#select deptno from emp group by deptno having avg(ifnull(sal,0)) >= all((select avg(ifnull(sal,0)) from emp group by deptno));
#最终结果
select * from dept 
where deptno=(select deptno from emp group by deptno having avg(ifnull(sal,0)) >= all((select avg(ifnull(sal,0)) from emp group by deptno)));

#案例6:每个部门中,每个主管的手下人数————》陷阱题让人误认为是两次分组,其实是一次分组
select deptno,mgr,count(*) from emp where mgr is not null group by mgr;

#案例7:每种工作的平均工资
select job,avg(ifnull(sal,0)) from emp group by job;

#案例8:平均工资最高的部门编号
#select deptno from emp;
#select avg(ifnull(sal,0)) av from emp group by deptno;
select deptno from emp group by deptno having avg(ifnull(sal,0)) >= all((select avg(ifnull(sal,0)) from emp group by deptno));
select deptno from emp group by deptno having avg(ifnull(sal,0)) >= all((select deptno,avg(ifnull(sal,0)) from emp group by deptno));	#——错误演示

#案例9:最后入职的员工信息
select * from emp where hiredate >= all((select hiredate from emp));

三、高级

MySQL的重点

1、高级关联查询

一、高级关联查询即子查询(重点掌握)

需求:当一个查询语句所需要的数据,不是直接体现在数据表中,而是需要使用另外一个查询语句查询出来的。这样的查询就被称为子查询。

1、在where子句中

#案例:查询与7369同部门的其他员工信息
#分析: 先查询7369的部门号   num
select deptno  from emp where empno = 7369;
#再查询num部门的所有员工信息,使用where条件排除7369
select * from emp where deptno=(select deptno  from emp where empno = 7369) and empno<>7369;

#案例:查询jones所在部门的部门名称和地理位置
select deptno from emp where ename = 'jones';
select dname,loc from dept where deptno=(select deptno from emp where ename = 'jones');

#案例:查询scott的上司的姓名,职位,工资
#分析:先查询scott的上司的编号	  
select mgr from emp where ename = 'scott'; 
#上司也是一个普通员工,因此只需要查询员工编号为上一个语句查询出的数据即可。	  
select ename,job,sal from emp where empno =(select mgr from emp where ename = 'scott') ;

#案例: 查询员工编号,姓名,职位及其领导编码,姓名,职位。(自连接)
select a.empno "员工编号",a.ename "员姓名",a.job "员工职位",b.empno "领导编号",b.ename "领导姓名",b.job "领导职位"from emp a, emp b where a.mgr = b.empno;

#案例:查询员工编号,姓名,职位及其下属的编号,姓名,职位。(自连接)
select a.empno "下属编号",a.ename "下属姓名",a.job "下属职位",b.empno "员工编号",b.ename "员工姓名",b.job "员工职位" from emp a, emp b where a.mgr = b.empno; 

2、在from子句中

#查询员工的姓名,工资,及其部门的平均工资。
select a.ename,a.sal,t.avg_sal 
from emp a,(select deptno,avg(ifnull(sal,0)) avg_sal from emp group by deptno) t 
where a.deptno=t.deptno;

#查询员工编号,姓名,职位及其部门的人数,工资之和,最高工资。
select a.empno,a.ename,a.job,t.pcount,t.sum(sal),t.max_sal
from emp a,(select deptno,count(*) pcount, sum(sal) ,max(sal) max_sal from emp group by deptno) t
where a.deptno = t.deptno;

3、在having子句中

#案例:查询平均工资大于30号部门的平均工资的部门号,和平均工资
select deptno,avg(ifnull(sal,0)) avg_sal 
from emp group by deptno 
having avg(ifnull(sal,0)) >(select avg(ifnull(sal,0)) from emp where deptno=30);

4、在select子句中

#查询员工的姓名,工资,及其部门的平均工资。
select ename,sal,
(select avg(ifnull(sal,0)) from emp b where b.deptno=a.deptno) "部门平均工资" 
from emp a;

二、常用函数《熟悉》

1.字符串函数

#1.进制转换函数
	#conv(n,from_base,to_base):对from_base进制的数n,转成to_base进制的表示方式(PS:进制范围为2-36进制,当to_base是负数时,n作为有符号数否则作无符号数)

#案例:将16进制的'a'转成10进制的数据 
	select conv('1a',16,10);
	select conv('1010',2,16);


# 2.拼接函数:
	#concat(str1,str2,...)   :将多个参数拼接成一个字符串,只要有一个为null,就返回null。

#案例:拼接函数:concat(str1,str2,......)
	select concat('hello','kitty');
	select concat(ename,job) "result" from emp;


# 3.补位函数
	#lpad(str,len,padstr)/rpad(str,len,padstr) :用字符串padstr填补str左端/右端直到字串长度为len并返回 

#案例:用字符串padstr填补str左端/右端直到字串长度为len并返回
	select lpad("kitty",10,'#');
	select lpad(ename,20,' ') from emp;


# 4.截取函数
	#left(str,len)/right(str,len)  :返回字符串str的左端/右端的len个字符 
	#substring(str from pos for len):返回字符串str的位置pos起len个字符

# 'no zuo no die'——'no zuo'——'die'——'no die'
	select left('no zuo no die',6);
	select right('no zuo no die',3);
	select substring('no zuo no die' from 8 for 6);--# 字符串下标从1开始


# 5.字符串长度函数
	#length(str)/octet_length(str) :返回参数对应的默认字符集的所有字节数。
	#char_length(str)/character_length(str):返回字符串str的字符长度 

#案例:emp表格中员工名字的字符长度
	select ename, char_length(ename) '长度' from emp;
	select length("张三a");


# 6.去空格函数
	#ltrim(str)/rtrim(str) :返回删除了左空格/右空格的字符串str

#案例:去除"   hello   "左边的空格
	select ltrim("   hello   ");


# 7.大小写转换函数
	#lcase(str)/lower(str)/ucase(str)/upper(str) :返回str的大小写 

#案例:'abcABc'中的大写转小写
#案例:搜索emp中名字为"SMITH"的名字
	select lcase('abcABc');
	select * from emp where lower(ename) = 'smith';


# 8.替换函数
	#replace(str,from_str,to_str)   :用字符串to_str替换字符串str中的子串from_str并返回  
	#insert(str,pos,len,newstr)   作用:把字符串str由位置pos起len个字符长的子串替换为字符串newstr并返回  
	
#案例:使用# 替换"no zuo no     die"里的空格
	select replace('no zuo no     die',' ','#');#匹配到就进行替换操作
#案例:将'no zuo no die'中的'zuo no' 替换成'hello'
	select insert('no zuo no die',4,6,'hello');

2.数值函数

# 1.幂函数
# pow(x,y)/power(x,y) :返回值x的y次幂 


# 2.平方根函数
# sqrt(n)  :返回非负数n的平方根  


# 3.圆周率函数
# pi() : 返回圆周率   


# 4.随机函数
# rand()/rand(n) :返回在范围0到1.0内的随机浮点值(可以使用数字n作为初始值) 


# 5.截取函数
# truncate(n,d)    : 保留数字n的d位小数并返回  


# 6.求最小/大值函数
# least(x,y,...) /greatest(x,y,...) ————》一般是对数值进行操作,混淆使用时会失效
#只要有null值,就返回null;混合参数时,lease()函数失效,greatest()函数会将所有的数据转成数值运算,转换不了的会忽略


# 7.取模函数
# mod(n,m) :取模运算,返回n被m除的余数(同%操作符)    


# 8.向下/上取整函数
# floor(n) /ceiling(n)


# 9.四舍五入函数
# round(n,d) :返回n的四舍五入值,保留d位小数(d的默认值为0)  

3.日期函数

# 1.获取当前系统时间的函数
	# curdate()年月日/curtime();时分秒/
	#now()/sysdate()/current_timestamp();——》都有年月日时分秒

#显示时间
select curdate(),curtime(),now(),sysdate(),current_timestamp();


# 2.获取星期几的函数
	# dayofweek(date):      1=星期天
	# weekday(date)     0=星期一
	# dayname(date)

#获取星期
select dayofweek(sysdate()),weekday(now()),dayname(now());


# 3.获取第几天的函数
	# dayofmonth(date);一个月的第几天
	# dayofyear(date);一年中的第几天
	# monthname(date);获取月的名字

#获取第几天
select dayofmonth(now()),dayofyear(now()),dayofyear('1987-11-08'),monthname(now());


# 4.截取时间分量函数
	# year(date)
	# month(date)
	# day(date);
	# hour(date);
	# minute(date);
	# second(date);

#案例:
select year(hiredate),month(now()),day(now()),hour(now()),minute(now()),second(now())from emp;



# 5.日期运算函数
	# date_add(date,interval expr type)/date_sub(date,interval expr type)
	# adddate(date,interval expr type)/subdate(date,interval expr type) 
	# 对日期时间进行加减法运算。(也可以用运算符+和-。?date:一个datetime或date值;expr:对date进行加减法的一个表达式字符串;type指明表达式expr应该如何被解释)

#常用表达式:
#minute_second	分钟和秒	minutes:seconds
#hour_minute	小时和分钟	hours:minutes 
#day_hour 	天和小时	days:hours
#year_month	年和月	years-months
#hour_second	小时分钟秒	hours:minutes:seconds
#day_minute	天小时分钟	days:hours:minutes
#day_second 天小时分钟秒 days:hours:minutes:seconds;
#使用+,-号进行计算


#案例
#计算从现在开始1天后的时间
select date_add(now(),interval '1' day);
#计算从现在开始1天1小时后的时间
select date_add(now(),interval '1:1' day_hour);
#计算25小时之前的时间
select date_sub(now(),interval '1:1' day_hour);
#计算7小时10分30秒之前的时间
select date_sub(now(),interval  '7:10:30' hour_second);
#计算1天1小时1分1秒钟前的时间
select now()+interval '1:1:1:1' day_second;


# 6日期格式化函数
	# date_format(date,format)  :根据format字符串格式化date值  
	# %Y:年  %m月  %d日  %h时  %i分  %s秒  %p  上下午  %W星期
select date_format(now(),'%H:%i:%s %Y-%m-%d %p %W')

三、数据库的备份《熟悉》

使用mysqldump命令进行备份。

​ a.在命令提示符下输入(别登陆到mysql内):

​ mysqldump -uUsername -pPwd --all-databases > filename.sql #备份所有数据库

​ b.备份一部分数据库

​ mysqldump -uUsername -pPwd --databases dbname1 dbname2 > filename.sql

​ c.备份某个数据库中的某些表

​ mysqldump -uUsername -pPwd dbname tablename1 tablename2 > filename.sql

​ d.恢复数据

​ 登入到mysql内,使用source命令

​ 语法: source filename.sql

JDBC阶段

一、概述(了解)

​ 什么是JDBC:Java Database Connection

作用: 是一个用来使得Java程序连接到数据库的中间件

JDBC是一个中间件,将不同的数据库的访问封装了起来,提供了一套标准的接口。Java程序再需要访问数据库的时候,直接和JDBC打交道即可,不用管如何区分访问不同的数据库。

1、需求

​ 早期的数据库没有统一的应用程序编程接口。开发人员针对不同数据库使用需要花费时间去学习相应数据库专有的API,增加了开发成本和周期

2、ODBC

​ 微软开发ODBC(open database connectivity).定义了统一的标准接口。方便了开发人员,不需要浪费时间学习数据库专有的API。

​ a.应用程序:只需要开发人员开处理和调用ODBC提供函数即可

​ b.驱动管理器:用来管理和注册驱动程序

​ c.驱动程序:就是对方法的实现,由数据库厂商去提供的。

​ d.数据源:就是连接的数据库的url,username ,password等信息。

3、JDBC

​ Sun公司参照了ODBC,为java语言专门设计的一套java连接数据库技术(JDBC)。定义了一套通用的连接数据库的标准接口。jdbc不依赖任何的数据库。不与DBMS直接交互。而是由数据库厂商提供的驱动程序将sql语句转发到dbms上进行解析处理。

​ jdbc是使用java语言设计的一组类和接口。具体实现由数据库厂商自己完成。

二、JDBC的实现(重点)

1. 准备jar包

JDBC是一个第三方的,需要在项目中导入对应的jar包,并配置相关的路径。

  1. 在项目根目录下,新建一个文件夹,命名为 lib
  2. 将jar包放到这个目录下面
  3. 在jar包上右键 -> Build Path -> Add to Build Path

2. 使用JDBC的基本步骤

1. 注册驱动
2. 建立连接
3. 创建Statement对象
4. 执行SQL,获取结果集
5. 处理结果集中的数据
6. 释放资源

3. 常用的JDBC组件

1. java.sql.DriverManager: 驱动管理器,用来管理数据库驱动。
2. java.sql.Driver: 驱动对象。
3. java.sql.Connection: 程序和数据库之间连接对象。
4. java.sql.Statement: 用来执行SQL语句。
5. java.sql.ResultSet: 执行SQL语句之后,得到的结果集。
6. java.sql.SQLException: 在SQL操作中能够产生的各种异常的父类。

4.第一个JDBC程序(DML)

4.1,注册驱动
// 使用DriverManager类来注册数据库驱动,参数是一个 java.sql.Driver 类型的
// 但是这个 java.sql.Driver 是一个接口,所以我们需要一个这个接口的实现类对象
// 而刚才导入的jar包中, com.mysql.jdbc.Driver 这个类就是一个实现了这个接口的mysql的驱动类
// DriverManager.registerDriver(new com.mysql.jdbc.Driver());

// 然而,在com.mysql.jdbc.Driver类的静态代码段中,其实已经使用了DriverManager注册了驱动
// 所以,我们没有必要去重复注册
Class.forName("com.mysql.jdbc.Driver");

4.2,建立连接
/**
 *方法1:
 * getConnection(String url, String user, String password)
 * url: 表示需要连接的数据库的路径
 * user: 连接数据库的用户名
 * password: 连接数据库的密码
 * 
 * 关于 url 是有一个固定的格式的:
 * jdbc:mysql://主机:端口/路径
 */
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_jdbc", "root", "123456");
		
/**
 *方法2:
 * getConnection(Strin url)
 * 将数据库的路径、用户名、密码都拼接到一个url中
 * jdbc:mysql://主机:端口/路径?键=值&键=值
 */
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my_jdbc?user=root&password=123456");

4.3 创建Statement对象
// 创建一个Statement对象
Statement st = conn.createStatement();

4.4,执行SQL,获取结果集
string sql="insert into emp (empno,ename,job,deptno) values(9901,'zangsan','manger',20)"
//发送语句:
    stat.executeUpdate(sql);

4.5,处理结果集中的数据
4.6,释放资源
  1. 需要释放的资源: ResultSet、Statement、Connection
  2. 释放的先后顺序, 按照使用的顺序倒着来

DQL操作

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

import org.junit.Test;
@Test
	public void testDQL() {
		try {
			//1:注册驱动
			Class.forName("com.mysql.jdbc.Driver");
			//2:获取连接
			Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db1901", "root", "mmforu");
			String sql = "select * from emp";
			//3:获取Statement对象
			Statement stat = conn.createStatement();
			//执行sql语句,返回结果集
			ResultSet rs = stat.executeQuery(sql);
			while(rs.next()) {
				/*
				 *    getString(int columnIndex)/getString(String columnName);
				 *    getInt(int columnIndex)/getInt(String columanName);
				 *    getDouble(int columnIndex)/getDouble(String columnName)
				 *    getDate(int columnIndex)/getDate(String columnName);
				 */
				int empno = rs.getInt("empno");
				String ename = rs.getString(2);
				double salary = rs.getDouble("sal");
				Date date = rs.getDate("hiredate");
				System.out.println(empno+","+ename+","+salary+","+date);
			}
            //关闭连接
            rs.close();
            stat.close();
            conn.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}



四、JDBC进阶

JDBC的重点

1、高级关联查询

一、JDBC的实现(重点掌握)

1 DBUtil工具类的封装

1.1.说明:

将大量重复的代码封装起来,为以后的调用提供方便

1.2.配置文件:

db.properties

1.3.静态块

static{},用于读取配置文件

静态块《static{}》在类中使用,跟方法平级的。属于一种加载块,只要涉及到该静态块所在的类,无论是调用属性还是方法,都会默认的使用静态块。跟构造方法一样,只不过构造方法是在实例化对象的时候调用。静态块比构造方法还要敏感。

1.4.连接方法

getConnection();

1.5.关闭方法

closeConnection(ResultSet rs,Statement stat,Connection conn)

/**
 * 封装一个数据库工具类,内部 定义两个方法, 一个方法为连接数据库的方法 另一个为关闭连接的方法
 */
public class DBUtil {
    //私有的静态变量————给静态块使用
	private static String driverClassName;
	private static String url;
	private static String username;
	private static String password;
	
    //静态块————加载资源用的,只要涉及到这个类中的东西,都会默认调用。不需要人为显式的调用
    static {
		try {
			//使用类加载器提供的方法读取db.properties,返回一个字节流对象(反射)
			InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("db.properties");
			//创建Properties对象,用于加载流内部的数据
			Properties prop = new Properties();		//——属性列表文件,做一些简单的键——值对
			prop.load(is);	 //加载流内部的信息,以key-value的形式进行加载
			/*
			 * 使用prop提供的getProperty(String key),通过key,获取value,
			 * 给静态属性赋值。
			 */
			driverClassName = prop.getProperty("driver");
			url = prop.getProperty("url");
			username = prop.getProperty("user");
			password = prop.getProperty("pwd");
            
			//注册驱动
			Class.forName(driverClassName);
            
		} catch (Exception e) {
			System.out.println("注册驱动失败");
			e.printStackTrace();
		}
	}
	
	/*
	 * 主函数中运行
	 */
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		Connection conn = getConnection();
		System.out.println(conn);
		closeConnection(null, null, conn);
	}
	
	/**
	 * 获取连接对象
	 *
	 * @return 连接对象
	 * @throws SQLException
	 * @throws ClassNotFoundException
	 */
	public static Connection getConnection() throws SQLException, ClassNotFoundException {
		return DriverManager.getConnection(url, username, password);
	}

	/**
	 * 关闭数据库连接
	 * 
	 * @param rs   结果集对象
	 * @param stat 处理sql的执行对象Statement
	 * @param conn 连接对象
	 */
	public static void closeConnection(ResultSet rs, Statement stat, Connection conn) {
		try {
			if (rs != null) {
				rs.close();
			}
			if (stat != null) {
				stat.close();
			}
			if (conn != null) {
				conn.close();
			}
		} catch (Exception e) {
			System.out.println("数据库连接关闭失败");
			e.printStackTrace();
		}
	}	
}

二、JDBC实例-模拟登陆(熟悉)

1.实体类 User——》服务端 Server——》客户端 Client

/**
 * 服务端的代码
 * @author Michael
 */
public class Server {
	/**
	 * 通过用户名和密码,查询表中是否有此用户
	 */
	public User verifyLogin(String username, String password) {
		Connection conn = null;
		Statement stat = null;
		ResultSet rs = null;
		User user = null;
		try {
			conn = DBUtil.getConnection();
			stat = conn.createStatement();
			String sql = "select id,user_name,user_pwd,gender from bank_account where user_name='" + username
					+ "' and user_pwd='" + password + "'";
			rs = stat.executeQuery(sql);
			if (rs.next()) {
				int id = rs.getInt("id");
				char gender = rs.getString("gender").charAt(0);
				user = new User(id, username, password, gender);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil.closeConnection(rs, stat, conn);
		}
		return user;
	}
}


/**
 * 客户端代码
 * @author Michael
 */
public class Client {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("请输入用户名:");
		String username = sc.next();
		System.out.println("请输入密码:");
		String password = sc.next();
		Server server = new Server();
		User user = server.verifyLogin(username, password);
		if(user==null) {
			System.out.println("登陆失败");
		}else {
			System.out.println("登陆成功........正在跳转页面");
		}
		sc.close();
	}
}


/**
 * 定义一个银行用户的实体类型,封装用户的一些基本信息
 * @author Michael
 *
 */
public class User {
	private int id;
	private String username;
	private String password;
	private char gender;
	public User() {}
	public User(int id, String username, String password, char gender) {
		this.id = id;
		this.username = username;
		this.password = password;
		this.gender = gender;
	}
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public char getGender() {
		return gender;
	}
	public void setGender(char gender) {
		this.gender = gender;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", username=" + username + ", password=" + password + ", gender=" + gender + "]";
	}	
}

三、SQL注入问题(重点)

1.安全隐患

Statement会出现此问题

sql = “select * from emp where empno = 7369”

通过传值:结构发生变化,如下:

sql = “select * from emp where empno = 10000 or 1=1”

这种破坏结构的情况,我们称之为sql注入问题,很容易被黑客使用。

2.解决办法

使用预编译sql语句执行对象 PreparedStatement替换了Statement, 这个接口在确定s’q’l语句的结构后,就不会在被改变结构,如果遇到强制改变情况,则报异常。

四、事务(重点)

1、概念

当一个业务需求有N个DML操作时,我们要把这个业务看成一个整体,不可分割。要么执行成功,要么执行失败,不可以做到一半就终止操作。那么这样的一个过程,我们称之为“事务”。比如在银行存、取款。

关键字:

取消自动提交:conn.setAutoCommit(false);

commit:提交DML操作

rollback:回滚

savepoint:保存点

2、特点

原子性:事务符合原子这个特点不可在进行分割。即只有成功、失败。
一致性:事务开始前与事务结束后,数据总量必须一致。
隔离性:事务与事务之间有隔离性质。跟线程共享资源一样,对共有资源进行操作时,不能同时操作,只能一个操作,其他等待。
持久性:事务一经提交,数据时永久性改变。

3、隔离级别(四种机制)

未提交读取机制():事务A读取到事务B未提交的数据,这种情况叫脏读
提交读取机制(read-commited):只能读取事务提交后的数据。多数数据库都是采用这种隔离机制。
可重复机制(repeatread):mysql数据库默认采用的是这种隔离机制。(对当前正在操作的数据上锁)
序列化机制(对正在操作的表上锁):严重影响性能。

4、JDBC中的事务

注意:mysql的DML操作,每次操作都会触发自动提交操作。

案例:转账业务

/**
 * 使用PreparedStatement来执行sql语句
 * @author Michael
 *
 */
public class Server1 {
	/**
	 * 通过用户名和密码,查询表中是否有此用户
	 */
	public User verifyLogin(String username, String password) {
		Connection conn = null;
		PreparedStatement stat = null;
		ResultSet rs = null;
		User user = null;
		try {
			conn = DBUtil.getConnection();
			String sql = "select id,user_name,user_pwd,gender from bank_account where user_name = ? and user_pwd = ?";
			/*
			 * 调用连接对象里的prepareStatement(String sql),先预编译sql语句,
			 * 返回预编译对象PreparedStatement
			 * 
			 * 方法:setString(parameterIndex, x);
			 * parameterIndex:表示占位符的序号,从1开始
			 * x:给占位符赋的具体值
			 *     setInt(parameterIndex,x);
			 */
			stat =conn.prepareStatement(sql);
			//给占位符赋值
			stat.setString(1, username);
			stat.setString(2, password);
			//执行预编译
			rs = stat.executeQuery();
			if (rs.next()) {
				int id = rs.getInt("id");
				char gender = rs.getString("gender").charAt(0);
				user = new User(id, username, password, gender);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			DBUtil.closeConnection(rs, stat, conn);
		}
		return user;
	}
}


public class SwitchMoney {
	/**
	 * 测试:诸葛亮向周瑜转账1000元
	 */
	@Test
	public void testSwitch() {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			conn = DBUtil.getConnection();
			
			/*
			 *因为每一个DML操作都会出发自动提交,也就是每一个DML是一个单独的事务。
			 *而此业务,需要将多个DML当成一个事务处理。因此需要取消自动提交,最后手动提交
			 *,如果中间出现异常,需要回滚。 
			 */
			//取消自动提交
			conn.setAutoCommit(false);
			
			//1:先查询诸葛亮的余额是否大于等于1000
			String sql = "select account_balance from bank_account where user_name=?";
			ps = conn.prepareStatement(sql);
			ps.setString(1, "zhugeliang");
			rs = ps.executeQuery();
			boolean flag = rs.next();
			if(!flag) {
				System.out.println("无此用户");
				return;
			}
			//取出余额
			double balance  = rs.getDouble(1);
			if(balance<1000) {
				System.out.println("余额不足");
				return;
			}
			//可以转账,诸葛亮扣钱
			sql = "update bank_account set account_balance=? where user_name=?";
			ps = conn.prepareStatement(sql);
			ps.setDouble(1, balance-1000);
			ps.setString(2, "zhugeliang");
			ps.executeUpdate();
			
			/*模拟空指针异常*/
//			String str = null;
//			System.out.println(str.length());	
			
			//周瑜+钱
			sql = "update bank_account set account_balance=account_balance+1000 where user_name=?";
			ps = conn.prepareStatement(sql);
			ps.setString(1, "zhouyu");
			ps.executeUpdate();
			System.out.println("转账成功");
			
			//事务成功后,手动提交
			conn.commit();
			
		} catch (Exception e) {
			//出现异常,手动回滚
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(rs, ps, conn);
		}
	}
}


五、JDBC高级部分

一、连接池(重点掌握)

1 概念

每一次对数据库的操作,如果都是触发重新连接(DriverManager.getConnection(url,username,password)),那么会增加性能的开销,降低工作的效率。

此问题如何解决:使用连接池技术

我们使用连接池技术,初始化n个连接,保存在连接池对象里。当有需求时,先去连接池中寻找空闲连接,进行操作,如果业务完成,就释放连接,归还到连接池中(而不是真正意义上断开连接),让给其他需求继续使用。这样的技术明显降低了对数据库连接产生的性能开销。

2、常用连接池技术介绍:

将大量重复的代码封装起来,为以后的调用提供方便

1、dbcp:是apache组织提供的一个连接池技术。
	所需要的jar包:
        commons-dbcp2-2.6.0.jar
	    commons-logging.jar
		commons-pool2-2.4.3.jar
	使用方式:
        在工具类中,创建dbcp连接池对象,然后配置相应的属性即可

2、c3p0:也时一个开源的数据库连接池技术
	所需要的jar包:
		c3p0-0.9.5-pre8.jar

3、druid:阿里的连接池技术——国内普遍认为阿里的连接池技术比较好
	所需要的jar包:
		druid-1.1.18.jar
2.1、dbcp:是apache组织提供的一个连接池技术。
public class JDBUtil_dbcp {
	private static String driverClassName;
	private static String url;
	private static String user;
	private static String password;
	
	private static BasicDataSource pool=new BasicDataSource();
	
	static {
		try {
		InputStream is=JDBUtil_dbcp.class.getClassLoader().getResourceAsStream("db.properties");
		Properties propert=new Properties();
		propert.load(is);
		driverClassName=propert.getProperty("driver");
		url=propert.getProperty("url");
		user=propert.getProperty("user");
		password=propert.getProperty("pwd");
		
		//配置连接池
		pool.setDriverClassName(driverClassName);
		pool.setUrl(url);
		pool.setUsername(user);
		pool.setPassword(password);
		
		//配置连接池的连接信息
		//设置连接池创建时的初始化连接数量
		pool.setInitialSize(Integer.valueOf(propert.getProperty("initialSize")));
		//设置连接池中最大空闲连接数
		pool.setMaxIdle(Integer.parseInt(propert.getProperty("maxIdle")));
		//设置连接池中最小空闲连接数
		pool.setMinIdle(Integer.parseInt(propert.getProperty("minIdle")));
		//设置最大的等待时间
		pool.setMaxWaitMillis(Long.parseLong(propert.getProperty("minIdle")));
		//设置连接池中最多支持的连接数
		pool.setMaxTotal(Integer.parseInt(propert.getProperty("maxTotal")));
		
		//Class.forName(driverClassName);
		} catch (Exception e) {
			System.out.println("注册失败!");
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws Exception {
		Connection conn=getConnection();
		System.out.println(conn);
		colseConnection(null,null,conn);
	}
	
	public static Connection getConnection() throws Exception {
			//return DriverManager.getConnection(url,user,password);
		return pool.getConnection();
	}
	
	public static void colseConnection(ResultSet rs,Statement stat,Connection conn) {
		try {
			if(rs != null) {
				rs.close();
			}
			if(stat != null) {
				stat.close();
			}
			if(conn != null) {
				conn.close();//释放连接,归还给连接池
			}
		}catch(Exception e) {
			System.out.println("数据库连接的关闭操作失败");
			e.printStackTrace();
		}	
	}
}

配置文件:dbcp.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1901?useUnicode=true&characterEncoding=utf8
user=root
pwd=654123
initialSize=5
maxIdle=10
minIdle=3
maxWaitMillis=6000
maxTotal=20
2、c3p0:也是一个开源的数据库连接池技术
import java.sql.*;
import com.mchange.v2.c3p0.*;
public class JDBCUtil2_c3p0 {
	
	//创建一个c3p0的连接池对象,使用构造器,来自动加载src下的配置文件
	private static ComboPooledDataSource pool= new ComboPooledDataSource("c3p0-config.xml");

	public static void main(String[] args) throws Exception {
		Connection conn=getConnection();
		System.out.println(conn);
		colseConnection(null,null,conn);
	}
	
	//丛连接池,获得连接对象
	public static Connection getConnection() throws Exception {
			//return DriverManager.getConnection(url,user,password);
		return pool.getConnection();
	}
	
	//关闭连接,将连接返回给连接池
	public static void colseConnection(ResultSet rs,Statement stat,Connection conn) {
		try {
			if(rs != null) {
				rs.close();
			}
			if(stat != null) {
				stat.close();
			}
			if(conn != null) {
				conn.close();//释放连接,归还给连接池
			}
		}catch(Exception e) {
			System.out.println("数据库连接的关闭操作失败");
			e.printStackTrace();
		}
	}
}

配置文件:c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
   
    <default-config>
        <property name="user">root</property>
        <property name="password">654123</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/db1901</property>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
      
        <property name="acquireIncrement">10</property>
       
        <property name="maxPoolSize">50</property>
        
        <property name="minPoolSize">2</property>
       
        <property name="initialPoolSize">5</property>
        
        <property name="maxIdleTime">600</property>
    </default-config>
</c3p0-config>
3、druid:阿里的连接池技术
import java.io.*;
import java.sql.*;
import java.util.*;
import javax.sql.*;
import com.alibaba.druid.pool.DruidDataSourceFactory;

public class JDBCUtil_druid {
	public static DataSource pool=null;
	
	static {
		try {
		InputStream is=JDBCUtil_dbcp.class.getClassLoader().getResourceAsStream("druid");
		Properties propert=new Properties();
		propert.load(is);
		pool=DruidDataSourceFactory.createDataSource(propert);	
		} catch (Exception e) {
			System.out.println("注册失败!");
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) throws Exception {
		Connection conn=getConnection();
		System.out.println(conn);
		colseConnection(null,null,conn);
	}
	
	
	public static Connection getConnection() throws Exception {
			//return DriverManager.getConnection(url,user,password);
		return pool.getConnection();
	}
	
	//关闭连接,将连接归还给连接池
	public static void colseConnection(ResultSet rs,Statement stat,Connection conn) {
		try {
			if(rs != null) {
				rs.close();
			}
			if(stat != null) {
				stat.close();
			}
			if(conn != null) {
				conn.close();//释放连接,归还给连接池
			}
		}catch(Exception e) {
			System.out.println("数据库连接的关闭操作失败");
			e.printStackTrace();
		}
	}
}

配置文件:druid

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1901?useUnicode=true&characterEncoding=utf8
username=root
password=654123
initialSize=5
maxIdle=10
minIdle=3
maxWait=6000
maxActive=20

二、DAO层的设计(重点)

数据访问对象思想,Data Access Object,简称DAO,是一种程序设计思想:将所有的与数据库直接操作的行为单独抽取出来(将持久层操作与业务层分离),定义成相应接口和实现类。

接口内部定义的是对数据库的需求方法:比如 增加,删除,修改,查询所有,按条件查询

实现类负责实现这些方法。

​ 1)实体对象:ORM Object relation Mapping 这种思想是将表字段映射成java中类的属性。表中的记录映射成类的实例

​ 2)DAO封装对数据库的操作

​ 3)编写步骤:

​ a.编写实体类
​ b.定义接口:
​ c.实现接口

2.1编写实体类

import java.sql.Date;
/**
 * 利用ORM思想 根据数据库中的emp表映射成java中的Emp类型
 * 字段映射成属性
 * @author Michael
 *
 */
public class Emp {
	private Integer empno;
	private String ename;
	private String job;
	private Integer mgr;
	private Date hiredate;
	private Double salary;
	private Double comm;
	private Integer deptno;
	public Emp() {}
	public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, Double salary, Double comm,
			Integer deptno) {
		super();
		this.empno = empno;
		this.ename = ename;
		this.job = job;
		this.mgr = mgr;
		this.hiredate = hiredate;
		this.salary = salary;
		this.comm = comm;
		this.deptno = deptno;
	}
	public Integer getEmpno() {
		return empno;
	}
	public void setEmpno(Integer empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public Integer getMgr() {
		return mgr;
	}
	public void setMgr(Integer mgr) {
		this.mgr = mgr;
	}
	public Date getHiredate() {
		return hiredate;
	}
	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	public Double getSalary() {
		return salary;
	}
	public void setSalary(Double salary) {
		this.salary = salary;
	}
	public Double getComm() {
		return comm;
	}
	public void setComm(Double comm) {
		this.comm = comm;
	}
	public Integer getDeptno() {
		return deptno;
	}
	public void setDeptno(Integer deptno) {
		this.deptno = deptno;
	}
	@Override
	public String toString() {
		return "Emp [empno=" + empno + ", ename=" + ename + ", job=" + job + ", mgr=" + mgr + ", hiredate=" + hiredate
				+ ", salary=" + salary + ", comm=" + comm + ", deptno=" + deptno + "]";
	}
}

2.2定义接口

import java.util.List;
import com.qianfeng.jdbc.entity.Emp;
/**
 *   编写数据库emp表的操作接口
 * @author Michael
 */
public interface EmpDao {
	/**插入操作:将一个Emp实例保存到数据表中*/
	public void insert(Emp emp);
	/**删除操作:根据员工编号删除数据库表中的数据*/
	public void delEmp(int empno);
	/**修改操作:根据员工编号修改员工的数据*/
	public void modEmp(Emp emp);
	/**查询操作:根据员工编号查询*/
	public Emp findByEmpno(int empno);
	/**查询所有的数据:*/
	public List<Emp> findAll();
	/**分页查询*/
	public List<Emp> findByPage(int page,int pageSize);
	/**查询记录数*/
	public int getCount();
}

3.2实现接口

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import com.qianfeng.jdbc.dao.EmpDao;
import com.qianfeng.jdbc.entity.Emp;
import com.qianfeng.jdbc.util.DBUtil;

public class EmpDaoImpl implements EmpDao {
//插入操作:将一个Emp实例保存到数据表中
	@Override
	public void insert(Emp emp) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("insert into emp values (?,?,?,?,?,?,?,?)");
			ps.setInt(1, emp.getEmpno());
			ps.setString(2, emp.getEname());
			ps.setString(3, emp.getJob());
			ps.setInt(4, emp.getMgr());
			ps.setDate(5, emp.getHiredate());
			ps.setDouble(6, emp.getSalary());
			ps.setDouble(7, emp.getComm());
			ps.setInt(8, emp.getDeptno());
			
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(null, ps, conn);
		}
	}
//删除操作:根据员工编号删除数据库表中的数据
	@Override
	public void delEmp(int empno) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("delete from emp where empno = ?");
			ps.setInt(1, empno);
			
			//执行
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(null, ps, conn);
		}
		
	}
//修改操作:根据员工编号修改员工的数据
	@Override
	public void modEmp(Emp emp) {
		Connection conn = null;
		PreparedStatement ps = null;
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("update emp set ename=?,job=?,mgr=?,hiredate=?,sal=?,comm=?,deptno=? where empno=?");
			ps.setString(1, emp.getEname());
			ps.setString(2, emp.getJob());
			ps.setInt(3, emp.getMgr());
			ps.setDate(4, emp.getHiredate());
			ps.setDouble(5, emp.getSalary());
			ps.setDouble(6, emp.getComm());
			ps.setInt(7, emp.getDeptno());
			ps.setInt(8, emp.getEmpno());
			
			ps.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(null, ps, conn);
		}
		
	}
//查询操作:根据员工编号查询
	@Override
	public Emp findByEmpno(int empno) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs =null;
		Emp emp = null;
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("select * from emp where empno =?");
			ps.setInt(1, empno);
			rs = ps.executeQuery();
			if(rs.next()) {
				String ename = rs.getString(2);
				String job = rs.getString(3);
				int mgr  = rs.getInt(4);
				Date hiredate = rs.getDate(5);
				double salary = rs.getDouble(6);
				double comm= rs.getDouble(7);
				int deptno = rs.getInt(8);
				emp = new Emp(empno, ename, job, mgr, hiredate, salary, comm, deptno);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(rs, ps, conn);
		}
		return emp;
	}
//查询所有的数据:
	@Override
	public List<Emp> findAll() {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs =null;
		List<Emp> emps = new ArrayList<Emp>();
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("select * from emp");
			
			rs = ps.executeQuery();
			while(rs.next()) {
				int empno = rs.getInt(1);
				String ename = rs.getString(2);
				String job = rs.getString(3);
				int mgr  = rs.getInt(4);
				Date hiredate = rs.getDate(5);
				double salary = rs.getDouble(6);
				double comm= rs.getDouble(7);
				int deptno = rs.getInt(8);
				Emp emp = new Emp(empno, ename, job, mgr, hiredate, salary, comm, deptno);
				emps.add(emp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(rs, ps, conn);
		}
		return emps;
	}
//分页查询
	@Override
	public List<Emp> findByPage(int page, int pageSize) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs =null;
		List<Emp> emps = new ArrayList<Emp>();
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("select * from emp limit ?,?");
			ps.setInt(1, (page-1)*pageSize);
			ps.setInt(2, pageSize);
			rs = ps.executeQuery();
			
			while(rs.next()) {
				int empno = rs.getInt(1);
				String ename = rs.getString(2);
				String job = rs.getString(3);
				int mgr  = rs.getInt(4);
				Date hiredate = rs.getDate(5);
				double salary = rs.getDouble(6);
				double comm= rs.getDouble(7);
				int deptno = rs.getInt(8);
				Emp emp = new Emp(empno, ename, job, mgr, hiredate, salary, comm, deptno);
				emps.add(emp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(rs, ps, conn);
		}
		return emps;
	}
//查询记录数
	@Override
	public int getCount() {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs =null;
		try {
			conn = DBUtil.getConnection();
			ps = conn.prepareStatement("select count(*) from emp");
			rs = ps.executeQuery();
			
			if(rs.next()) {
				//取出第一个字段的总数,并返回
				return rs.getInt(1);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(rs, ps, conn);
		}
		return 0;
	}
}

3.3测试类:

import java.sql.Date;
import java.util.List;

import org.junit.Test;

import com.qianfeng.jdbc.dao.EmpDao;
import com.qianfeng.jdbc.dao.impl.EmpDaoImpl;
import com.qianfeng.jdbc.entity.Emp;

public class TestDao {
	
	@Test
	public void testFindByEmpno() {
		EmpDao dao = new EmpDaoImpl();
		Emp emp = dao.findByEmpno(9006);
		System.out.println(emp);
	}
	@Test
	public void testFindByPage() {
		EmpDao dao = new EmpDaoImpl();
		List<Emp> emps = dao.findByPage(2, 10);
		System.out.println(emps.size());
	}
	@Test
	public void testInsert() {
		EmpDao dao = new EmpDaoImpl();
		Emp emp = new Emp(9006,"kitty","manager",7369,Date.valueOf("2012-1-1"),1000.0,100.0,20);
		dao.insert(emp);
	}
	@Test
	public void testDelEmp() {
		EmpDao dao = new EmpDaoImpl();
		dao.delEmp(9006);//删除9006的员工信息
	}
	@Test
	public void testModEmp() {
		EmpDao dao = new EmpDaoImpl();
		//先查询9006的员工信息
		Emp emp = dao.findByEmpno(9006);
		//修改emp的一些属性值
		emp.setEname("hello");
		emp.setSalary(2200.0);
		//保存到数据库
		dao.modEmp(emp);
	}
	@Test
	public void testFindAll() {
		EmpDao dao = new EmpDaoImpl();
		List<Emp> emps = dao.findAll();
		for(Emp e:emps) {
			System.out.println(e);
		}
	}
	@Test
	public void testGetCount() {
		EmpDao dao = new EmpDaoImpl();
		int count = dao.getCount();
		System.out.println(count);
	}
}

三、DBUtils第三方工具的使用(了解熟悉)

​ 使用JDBC技术是一件繁琐的事情,为了使数据库更加高效,有一种简化jdbc技术的操作–DBUtils。

​ DBUtils是对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC程序开发,同时也不会影响程序的性能。DbUtils类主要负责装载驱动、关闭连接的常规工作。

1.关键类型和接口

a.QueryRunner:

QreryRunner类是Dbutils的核心类之一,它显著的简化了SQL查询,并与ResultSetHandler协同工作将使编码量大为减少。

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.dbutils.*;
import org.apache.commons.dbutils.handlers.*;
import org.apache.commons.dbutils.handlers.*;
import org.junit.Test;

import com.qianfeng.jdbc.entity.Emp;
import com.qianfeng.jdbc.util.DBUtil;
/**
 * ResultSetHandler是一个接口,其子类型
 * BeanHandler:将查询到的数据的第一行封装成Bean对象
 * BeanListHandler:将查询到的数据封装Bean的集合对象
 * @author Michael
 */
public class TestdbUtils {
	@Test
	public void test1() throws SQLException {
		QueryRunner qr = new QueryRunner(DBUtil.getPool());
		Emp emp =qr.query("select * from emp", new BeanHandler<Emp>(Emp.class)); 
		System.out.println(emp);
	}
	@Test
	public void test2() throws SQLException {
		QueryRunner qr = new QueryRunner(DBUtil.getPool());
		List<Emp> emps = qr.query("select * from emp where deptno=? and mgr=?", new BeanListHandler<Emp>(Emp.class),10,7499); 
		for(Emp e:emps) {
			System.out.println(e);
		}
	}
	@Test
	public void test3() throws SQLException {
		QueryRunner qr = new QueryRunner(DBUtil.getPool());
		Object[] emps = qr.query("select * from emp", new ArrayHandler()); 
		System.out.println(Arrays.toString(emps));
	}
	@Test
	public void test4() throws SQLException {
		QueryRunner qr = new QueryRunner(DBUtil.getPool());
		List<Object[]> emps = qr.query("select * from emp", new ArrayListHandler()); 
		for(Object[] obj:emps) {
			System.out.println(Arrays.toString(obj));
		}
	}
}

b.ResultSetHandler:

​ ResultSetHandler接口执行处理一个结果集对象,将数据转变并处理为任何一种形式,供其他应用使用。

public class TestdbUtils {
	@Test
	public void test1() throws SQLException {
		QueryRunner qr = new QueryRunner(DBUtil.getPool());
		Emp emp =qr.query("select * from emp", new BeanHandler<Emp>(Emp.class)); 
		ResultSetHandler rs=ArrayListHandler<>;
	}
}

四、JDBC批处理操作(熟悉)

1.Statement

public class TestBacth {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stat = null;
		try {
			conn = DBUtil.getConnection();
			stat = conn.createStatement();
			int num = (int)(Math.random()*10000)+10000;
			/*如果这样操作,那么每次都与数据库交互,操作了1000次*/
			for(int i=0;i<1000;i++) {
				String sql = "insert into emp (empno,ename )values ("+num+",'张三"+num+"')";
				stat.addBatch(sql);//将sql语句添加到批处理中(缓存)
				if(i%50==0) {//每50次一刷新
					stat.executeBatch();
				}
			}
			//循环结束后,缓存中有可能还有数据,不满50条
			stat.executeBatch();//刷新
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			DBUtil.closeConnection(null, stat, conn);
		}
	}
//	public static void main(String[] args) {
//		Connection conn = null;
//		Statement stat = null;
//		try {
//			conn = DBUtil.getConnection();
//			stat = conn.createStatement();
//			int num = (int)(Math.random()*10000)+10000;
//			/*如果这样操作,那么每次都与数据库交互,操作了1000次*/
//			for(int i=0;i<1000;i++) {
//				String sql = "insert into emp (empno,ename )values ("+num+",'张三"+num+"')";
//				stat.execute(sql);
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//		}finally {
//			DBUtil.closeConnection(null, stat, conn);
//		}
//	}
}

五、xml和json讲解(熟悉)

1 xml介绍

1.1、简介与特点
xml是可扩展标记语言,所有的标签都是用户自定义的,主要用于存储数据,定义数据结构和网络传输。而html是用于显示数据,里面的标签都是预定义的。

xml的特点:

1、标签可以是双标签 <book></book>, 也可以是单标记<value/>,但是必须是闭合的。
2、能用中文,但是不建议
3、不能数字开头
4、可以使用下划线
5、扩展名必须是.xml
1.2、XML语法
a.文档声明
	xml文件的首行,就是文档声明:
	<?xml version= '1.0' encoding ="utf-8"?>
	
b.属性
	元素就是标签,必须闭合,可是一单标签,也可以是双标签,能嵌套,不能交叉嵌套
	<book><name></name></book>
	
c.元素
	标签的开始标签中,可以添加属性,属性是以键值对的形式存在的。格式:属性名=“属性值”。可以有n个。属性也可以换成子标签来替代。

d.文本
	<![CDATA[金<庸]]>在此标记内写的文本就是纯文本。没有什么特殊字符之类的说法
	特殊字符对应的实体:
		>		&gt;
		<		&lt;
		&		&amp;
		'		&apos;
		"		&quot;
      
	e.注释
	 <!-- 文本 -->

1.3、约束
	<?xml  version="1.0" encoding="utf-8"?>

<!DOCTYPE                                #写在<!DOCTYPE  >内部
books[                                   #根标记
    <!ELEMENT books (book*)>             #books的子标记book可以有0到多个    
    <!ELEMENT book (name,author,price,desc)>      #book有四个子标记,书写时必须按照此定义顺序
    <!ELEMENT name (#PCDATA)>                     #name下不能有子标记,只能是字符串              
    <!ELEMENT author (#PCDATA)>
    <!ELEMENT price (#PCDATA)>
    <!ELEMENT desc (#PCDATA)>
    <!ATTLIST book id CDATA #REQUIRED>         #book标记中定义id属性,值为字符串,是必须的
    <!ATTLIST name time CDATA #IMPLIED>        #name标记中定义time属性,值为字符串,是不必须的
]>
<books>
	<book id="1001">
		<name>天龙八部</name>
		<author>金庸</author>
		<price>23</price>
		<desc>比较好看</desc>
	</book>
	<book id="1002">
		<name>圆月弯刀</name>
		<author>古龙<庸</author>
		<price>23</price>
		<desc>好看</desc>
	</book>
</books>

2 json简介

就是一种特殊字符串:数据都是key-value形式,key和value要用引号引起来,使用冒号连接,与其他的key-value对用逗号分开。

{}表示对象

[]表示数组

案例如下:

> 存储一个员工的信息,var str = '{"empno" : "1001","ename":"jones"}'
> 存储多个员工的信息,var str = '[{"empno" : "1001","ename":"jones"},'{"empno" : "1002","ename":"zs"}]'

json字符串的案例:

{
    "name": "中国",
    "province": [{
        "name": "黑龙江",
        "cities": {
            "city": ["哈尔滨", "大庆"]
        }
    }, {
        "name": "广东",
        "cities": {
            "city": ["广州", "深圳", "珠海"]
        }
    }, {
        "name": "台湾",
        "cities": {
            "city": ["台北", "高雄"]
        }
    }, {
        "name": "新疆",
        "cities": {
            "city": ["乌鲁木齐"]
        }
    }]
}

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值