SQL的语言分类
DQL(Data Query Language):数据查询语言 select
DML(Data Manipulate Language):数据操作语言 insert 、update、delete
DDL(Data Define Language):数据定义语言 create、drop、alter
TCL(Transaction Control Language):事务控制语言 commit、rollback
DQL语言
DQL( Data Query Language 数据查询语言 )
- 查询数据库数据 , 如SELECT语句
- 简单的单表查询或多表的复杂查询和嵌套查询
- 是数据库语言中最核心,最重要的语句
- 使用频率最高的语句
SELECT语法
SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
[left | right | inner join table_name2] -- 联合查询
[WHERE ...] -- 指定结果需满足的条件
[GROUP BY ...] -- 指定结果按照哪几个字段来分组
[HAVING] -- 过滤分组的记录必须满足的次要条件
[ORDER BY ...] -- 指定查询记录按一个或多个条件排序
[LIMIT {[offset,]row_count | row_countOFFSET offset}];
-- 指定查询的记录从哪条至哪条
# 注意 : [ ] 括号代表可选的 , { }括号代表必选得
1:基础查询
语法: SELECT 要查询的东西 【FROM 表名】;
进阶2:条件查询
条件查询:根据条件过滤原始表的数据,查询到想要的数据
语法: select 要查询的字段|表达式|常量值|函数 from 表 where 条件 ;
3:排序查询
语法:
select
要查询的东西
from
表
where
条件
order by 排序的字段|表达式|函数|别名 【asc(升序)|desc(降序)】
4:常见函数
一、单行函数
1、字符函数 concat 拼接 substr 截取子串(索引从1开始) upper转换成大写 lower转换成小写 trim 去前后指定的空格和字符 ltrim 去左边空格 rtrim去右边空格 replace 替换 lpad 左填充 rpad 右填充 instr 返回子串第一次出现的索引 length 获取字节个数
2、数学函数 round 四舍五入 rand 随机数 floor 向下取整 ceil 向上取整 mod 取余 truncate 截断
3、日期函数 now 当前系统日期+时间 curdate 当前系统日期 curtime当前系统时间 str_to_date 将字符转换成日期 date_format 将日期转换成字符
4、流程控制函数 if 处理双分支 case语句 处理多分支 情况1:处理等值判断 情况2:处理条件判断 5、其他函数 version版本 database当前库 user当前连接用户
二、分组函数
sum 求和 max 最大值 min 最小值 avg 平均值 count 计数 特点: 1、以上五个分组函数都忽略null值,除了count(*) 2、sum和avg一般用于处理数值型 max、min、count可以处理任何数据类型 3、都可以搭配distinct使用,用于统计去重后的结果 4、count的参数可以支持: 字段、常量值,一般放1
建议使用 count(*)
5:分组查询
语法: select 查询的字段,分组函数 from 表 group by 分组的字段
特点: 1、可以按单个字段分组
2、和分组函数一同查询的字段最好是分组后的字段
3、分组筛选
针对的表 位置 关键字
分组前筛选: 原始表 group by的前面 where 分组后筛选:
分组后的结果集 group by的后面 having4、可以按多个字段分组,字段之间用逗号隔开
5、可以支持排序
6、having后可以支持别名
6:多表连接查询
JOIN 对比
七种Join:
**语法:**
select 字段,...
from 表1
【inner|left outer|right outer|cross】join 表2 on 连接条件
【inner|left outer|right outer|cross】join 表3 on 连接条件
【where 筛选条件】
【group by 分组字段】
【having 分组后的筛选条件】
【order by 排序的字段或表达式】
好处:语句上,连接条件和筛选条件实现了分离,简洁明了!
/*
连接查询
如需要多张数据表的数据进行查询,则可通过连接运算符实现多个查询
内连接 inner join
查询两个表中的结果集中的交集
外连接 outer join
左外连接 left join
(以左表作为基准,右边表来一一匹配,匹配不上的,返回左表的记录,右表以NULL填充)
右外连接 right join
(以右表作为基准,左边表来一一匹配,匹配不上的,返回右表的记录,左表以NULL填充)
等值连接和非等值连接
自连接
*/
-- 查询参加了考试的同学信息(学号,学生姓名,科目编号,分数)
SELECT * FROM student;
SELECT * FROM result;
/*思路:
(1):分析需求,确定查询的列来源于两个类,student result,连接查询
(2):确定使用哪种连接查询?(内连接)
*/
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
-- 右连接(也可实现)
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
RIGHT JOIN result r
ON r.studentno = s.studentno
-- 等值连接
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s , result r
WHERE r.studentno = s.studentno
-- 左连接 (查询了所有同学,不考试的也会查出来)
SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
LEFT JOIN result r
ON r.studentno = s.studentno
自连接
案例:查询员工名和直接上级的名称
SELECT e.last_name,m.last_name
FROM employees e
JOIN employees m ON e.`manager_id`=m.`employee_id`;
SELECT e.last_name,m.last_name
FROM employees e,employees m
WHERE e.`manager_id`=m.`employee_id`;
7、子查询
含义:
一条查询语句中又嵌套了另一条完整的select语句,其中被嵌套的select语句,称为子查询或内查询
在外面的查询语句,称为主查询或外查询
/*============== 子查询 ================
什么是子查询?
在查询语句中的WHERE条件子句中,又嵌套了另一个查询语句
嵌套查询可由多个子查询组成,求解的方式是由里及外;
子查询返回的结果一般都是集合,故而建议使用IN关键字;
*/
-- 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列
-- 方法一:使用连接查询
SELECT studentno,r.subjectno,StudentResult
FROM result r
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC;
-- 方法二:使用子查询(执行顺序:由里及外)
SELECT studentno,subjectno,StudentResult
FROM result
WHERE subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '数据库结构-1'
)
ORDER BY studentresult DESC;
-- 查询课程为 高等数学-2 且分数不小于80分的学生的学号和姓名
-- 方法一:使用连接查询
SELECT s.studentno,studentname
FROM student s
INNER JOIN result r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` sub
ON sub.`SubjectNo` = r.`SubjectNo`
WHERE subjectname = '高等数学-2' AND StudentResult>=80
-- 方法二:使用连接查询+子查询
-- 分数不小于80分的学生的学号和姓名
SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80
-- 在上面SQL基础上,添加需求:课程为 高等数学-2
SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '高等数学-2'
)
-- 方法三:使用子查询
-- 分步写简单sql语句,然后将其嵌套起来
SELECT studentno,studentname FROM student WHERE studentno IN(
SELECT studentno FROM result WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2'
)
)
8、分页查询
语法:
select 字段|表达式,...
from 表
【where 条件】
【group by 分组字段】
【having 条件】
【order by 排序的字段】
limit 【起始的条目索引,】条目数;
*公式:select * from 表 limit (page-1)sizePerPage,sizePerPage
假如:
每页显示条目数sizePerPage
要显示的页数 page
9、联合查询
引入: union 联合、合并
语法:
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
select 字段|常量|表达式|函数 【from 表】 【where 条件】 union 【all】
.....
select 字段|常量|表达式|函数 【from 表】 【where 条件】
DML语言(数据操作语言)
插入
语法:
方式一: insert into 表名(字段名,…) values(值1,…);
方式二:insert into 表名 set 字段1=值1,字段2=值2;
方式一支持多行查询和子查询,方法二不支持
特点:
1、字段类型和值类型一致或兼容,而且一一对应
2、可以为空的字段,可以不用插入值,或用null填充
3、不可以为空的字段,必须插入值
4、字段个数和值的个数必须一致 5、字段可以省略,但默认所有字段,并且顺序和表中的存储顺序一致
修改
修改单表语法:
update 表名 set 字段=新值,字段=新值
【where 条件】
修改多表语法:
语法
update 表1 别名1,表2 别名2
set 字段=新值,字段=新值
where 连接条件
and 筛选条件
语法
update 表1 别名1
连接类型(inner\left\right\full) join 表2 别名2
on 连接条件
set 字段=新值,字段=新值
where 筛选条件
删除
方式1 :delete语句
单表的删除: ★
delete from 表名 【where 筛选条件】
多表的删除:
语法
delete 别名1,别名2
from 表1 别名1,表2 别名2
where 连接条件
and 筛选条件;
语法
delete 别名1,别名2
from 表1 别名1
连接类型 join 表2 别名2
on 连接条件
where 筛选条件;
方式2 :truncate语句
truncate table 表名
两种方式的区别【面试题】
#1.truncate不能加where条件,而delete可以加where条件
#2.truncate的效率高一丢丢
#3.truncate 删除带自增长的列的表后,如果再插入数据,数据从1开始
#delete 删除带自增长列的表后,如果再插入数据,数据从上一次的断点处开始
#4.truncate删除没有返回值,delete删除有返回值
#5.truncate删除不能回滚,delete删除可以回滚
DDL语句(数据定义语言)
1.库和表的管理
库的管理:
一、创建库
create database (if not exists)库名
二、删除库
drop database (if exists) 库名
三、修改库
rename database 旧库名 to 新库名(已经废弃了,因为不够安全)
可以更改库的字符集
alter database 库名 character set utf8\gbk等
表的管理:
1.创建表
CREATE TABLE IF NOT EXISTS 表名(
列名 列的类型 【(长度)约束】,
列名 列的类型 【(长度)约束】,
…
)
CREATE TABLE IF NOT EXISTS stuinfo(
stuId INT,
stuName VARCHAR(20),
gender CHAR,
bornDate DATETIME
);
DESC studentinfo;//查询表结构
2.修改表 alter
语法:ALTER TABLE 表名 ADD|MODIFY|DROP|CHANGE COLUMN 字段名 【字段类型】;
#①修改字段名
ALTER TABLE studentinfo CHANGE COLUMN sex gender CHAR;
#②修改表名
ALTER TABLE stuinfo RENAME [TO] studentinfo;
#③修改字段类型和列级约束
ALTER TABLE studentinfo MODIFY COLUMN borndate DATE ;
#④添加字段
ALTER TABLE studentinfo ADD COLUMN email VARCHAR(20) first;
#⑤删除字段
ALTER TABLE studentinfo DROP COLUMN email;
3.删除表
DROP TABLE [IF EXISTS] studentinfo;
4.复制表
- 仅仅复制表的结构-------------create table 表名 like 要复制的表名
- 复制表的结构+数据
create table 表名
select * from 要复制的表名
- 只复制部分数据
create table 表名
select 数据名 from 要复制的表名 where 筛选条件
- 只复制部分结构
create table 表名
select 数据名 from 要复制的表名 where 不成立的条件
常见类型
数值型:
(1)整型:
tinyint smallint mediumint int/integer bigint
1 2 3 4 8
设置无符号:undesign
如果插入数值超过范围,则报错 out of range,会插入临界值
长度代表显示结果的最大宽度,不够的话搭配zerofill用零填充
(2)小数:
浮点型 float double
定点型 DEC(M,D) DECIMAL(M,D)
M 整数和小数共同位数 D小数点后位数
M,D都可以省略
DEC(M,D) M默认为10,D默认为0
原则:使用的类型越简单越好,能保存的数值越小越好
(3)字符型:
较短的文本 char(M) 固定长度
varchar(M) 可变长度 M最大的字符数
char(M)空间耗费多,效率高,M可省略,默认为1
varchar(M)空间耗费少,效率低,M不可省略
(4)其他:
Bit 位类型 Bit(1)~bit(8)
binary和varbinary类型
说明:类似于char和varchar,不同的是它们包含二进制字符串而不包含非二进制字符串
enum枚举 set不区分大小写
区别:SET类型一次可以选取多个成员,而Enum只能选一个。据成员个数不同,存储所占的字节也不同
较长的文本 text blob(较大的二进制)
日期型:date datetime timestamp time year
4 8 4 3 1
常见约束
– NOT NULL 非空约束,规定某个字段不能为空
– UNIQUE 唯一约束,规定某个字段在整个表中是唯一的,可以为空
– PRIMARY KEY 主键(非空且唯一)查、外键
查看索引:show index from 表名
主键和唯一的对比:
保证唯一性 是否允许为空 一个表中可以有多少个 是否可以组合
主键 √ × 至多有一个 可以,但不推荐
独特 √ √ 可以有多个 可以,但不推荐
外键:
1.要求在从表设置外键关系
2.从表的外键列的类型和主表的关联列的类型要求一致或者兼容,名称无要求
3.主表中的关联列必须是一个key(一般是主键或独特)
4.插入数据时,先插入主表,在插入从表
删除数据时,先删除从表,再删除主表。
加入多个约束时直接添加,没有顺序。
一、创建表时添加约束
1.添加列级约束
直接在字段名和类型后面追加 约束类型即可。
只支持:默认、非空、主键、唯一
2.添加表级约束
语法:在各个字段的最下面
【constraint 约束名】 约束类型(字段名)
CREATE TABLE IF NOT EXISTS stuinfo(
id INT PRIMARY KEY,
stuname VARCHAR(20),
sex CHAR(1),
age INT DEFAULT 18,
seat INT UNIQUE,
majorid INT,
CONSTRAINT fk_stuinfo_major FOREIGN KEY(majorid) REFERENCES major(id)外键
);
二、修改表时添加约束
1、添加列级约束
alter table 表名 modify column 字段名 字段类型 新约束;
2、添加表级约束
alter table 表名 add 【constraint 约束名】 约束类型(字段名) 【外键的引用】;
位置 支持的约束类型 是否可以起约束名
列级约束:列的后面 语法都支持,但外键没有效果 不可以
表级约束:所有列的下面 默认和非空不支持,其他支持 可以(主键没有效果)
标识列
含义
标识列,又称为自增长列。可以不用手动的插入值,系统提供默认的序列值
特点
1、标识列必须和主键搭配吗?不一定,但要求是一个key
2、一个表可以有几个标识列?至多一个!
3、标识列的类型只能是数值型
4、标识列可以通过 SET auto_increment_increment=3;设置步长 可以通过 手动插入值,设置起始值
创建表时设置标识列
DROP TABLE IF EXISTS tab_identity;
CREATE TABLE tab_identity(
id INT ,
NAME FLOAT UNIQUE AUTO_INCREMENT,
seat INT
);
TRUNCATE TABLE tab_identity;
INSERT INTO tab_identity(id,NAME) VALUES(NULL,'john');
INSERT INTO tab_identity(NAME) VALUES('lucy');
SELECT * FROM tab_identity;
SHOW VARIABLES LIKE '%auto_increment%';
SET auto_increment_increment=3;
事务
什么是事务
- 事务就是将一组SQL语句放在同一批次内去执行
- 如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行
- MySQL事务处理只支持InnoDB和BDB数据表类型
事务的ACID原则
原子性(Atomic)
整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(ROLLBACK)到事务开始前的状态,就像这个事务从来没有执行过一样。
一致性(Consist)
一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving anInvariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。
隔离性(Isolated)
隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。
持久性(Durable)
在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。
基本语法
-- 使用set语句来改变自动提交模式
SET autocommit = 0; /*关闭*/
SET autocommit = 1; /*开启*/
-- 注意:
--- 1.MySQL中默认是自动提交
--- 2.使用事务时应先关闭自动提交
-- 开始一个事务,标记事务的起始点
START TRANSACTION
-- 提交一个事务给数据库
COMMIT
-- 将事务回滚,数据回到本次事务的初始状态
ROLLBACK
-- 还原MySQL数据库的自动提交
SET autocommit =1;
-- 保存点
SAVEPOINT 保存点名称 -- 设置一个事务保存点
ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
RELEASE SAVEPOINT 保存点名称 -- 删除保存点
ER图
概念
E-R图也称实体-联系图(Entity Relationship Diagram),提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型。
它是描述现实世界关系概念模型的有效方法。是表示概念关系模型的一种方式。用“矩形框”表示实体型,矩形框内写明实体名称;用“椭圆图框”或圆角矩形表示实体的属性,并用“实心线段”将其与相应关系的“实体型”连接起来;
用”菱形框“表示实体型之间的联系成因,在菱形框内写明联系名,并用”实心线段“分别与有关实体型连接起来,同时在”实心线段“旁标上联系的类型(1:1,1:n或m:n)。
ER图分为实体、属性、关系三个核心部分。实体是长方形体现,而属性则是椭圆形,关系为菱形。
实体
ER图的实体(entity)即数据模型中的数据对象,例如人、学生、音乐都可以作为一个数据对象,用长方体来表示,每个实体都有自己的实体成员(entitymember)或者说实体对象(entity instance),例如学生实体里包括张三、李四等,实体成员(entitymember)/实体实例(entity instance) 不需要出现在ER图中。
属性
ER图的属性(attribute)即数据对象所具有的属性,例如学生具有姓名、学号、年级等属性,用椭圆形表示,属性分为唯一属性( uniqueattribute)和非唯一属性,唯一属性指的是唯一可用来标识该实体实例或者成员的属性,用下划线表示,一般来讲实体都至少有一个唯一属性。
关系
ER图的关系(relationship)用来表现数据对象与数据对象之间的联系,例如学生的实体和成绩表的实体之间有一定的联系,每个学生都有自己的成绩表,这就是一种关系,关系用菱形来表示。
关联关系
ER图中关联关系有三种:
1对1(1:1):
1对1关系是指对于实体集A与实体集B,A中的每一个实体至多与B中一个实体有关系;反之,在实体集B中的每个实体至多与实体集A中一个实体有关系。
1对多(1:N):1对多关系是指实体集A与实体集B中至少有N(N>0)个实体有关系;并且实体集B中每一个实体至多与实体集A中一个实体有关系。
多对多(M:N):
多对多关系是指实体集A中的每一个实体与实体集B中至少有M(M>0)个实体有关系,并且实体集B中的每一个实体与实体集A中的至少N(N>0)个实体有关系。
实例
ER图实例
假设教学管理规定:
一个学生可选修多门课,一门课有若干学生选修;
一个教师可讲授多门课,一门课只有一个教师讲授;
一个学生选修一门课,仅有一个成绩。
学生的属性有学号、学生姓名;教师的属性有教师编号,教师姓名;课程的属性有课程号、课程名。
要求:根据上述语义画出ER 图,要求在图中画出实体的属性并注明联系的类型。
图书管理系统ER图
表与表之间的关系
一、表关系的概念
现实生活中,实体与实体之间肯定是有关系的,如:学生和老师,学生和课程,部门和员工,每个人和自己的身份证号码等。
在设计表的时候,就应该体现出来表与表之间的这种关系。
表与表之间的三种关系:
-
一对多:最常用的关系,如部门和员工
-
多对多:学生选课表和学生表,一门课程可以有多个学生选择,一个学生选择多门课程
-
一对一:相对使用比较少,员工表,公民表,护照表
二、一对多
一对多(1:n)
例如:部门和员工,客户和订单,分类和商品。
一对多建表原则:在从表(多方)创建一个字段,字段作为外键指向主表(一方)的主键
三、多对多
多对多(m:n)
例如:老师和学生,学生和课程,用户和角色
**多对多关系建表原则:**需要创建第三张表,中间表至少两个字段,这两个字段分别作为外键指向各自一方的主键。
多对多关系示意图:
四、一对一
一对一(1:1)
在实际开发应用不多,因为一对一可以创建成一张表。
两种建表原则:
关系示意图:
五、表与表之间的关系总结
数据库设计三大范式
1.第一范式(1NF):确保每列保持原子性即列不可分
比如某些数据库系统中需要用到“地址”这个属性,本来直接将“地址”属性设计成为一个数据库表的字段就行,但是如果系统经常访问“地址”属性中的“城市”部分,那么一定要把“地址”这个属性重新拆分为省份、城市、详细地址等多个部分来进行存储,这样对地址中某一个部分操作的时候将非常方便 。
2.第二范式(2NF):属性完全依赖于主键(属性都是该对象拥有的)
在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下图:
这里产生一个问题:这个表中是以订单编号和商品编号作为联合主键,这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品的编号相关,所以在这里违反了第二范式的设计原则。
**利用对象之间的关系设计表,确认表的个数:**而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,就非常完美了,如下图。
这里这样设计,在很大程度上减小了数据库的冗余,如果要获取订单的商品信息,使用商品编号到商品信息表中查询即可。
3.第三范式(3NF):属性和主键不能间接相关(减少数据冗余,这样就可以通过主外键进行表之间连接)
第三范式:数据不能存在传递关系,**即每个属性都跟主键有直接关系而不是间接关系。**像:a–>b–>c 属性之间含有这样的关系,是不符合第三范式的。第三范式是对第二范式的细化。
比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系,而不可以在订单表中添加关于客户其他信息(比如姓名、所属公司)的字段,如下面这两个表所示的设计就是一个满足第三范式的数据库表。
这样在查询订单信息的时候,就可以使用客户编号来引用客户信息表中的记录,也不必再订单信息表中多次输入客户信息的内容,减小了数据冗余。
例子:儿子的玩具车与玩具枪和爸爸是间接关系,应该拆为 两个表,通过儿子将两个表关联起来:
因为上表的玩具车与玩具枪属于儿子,因此不符合第三范式,对上表进行拆分
MVC
经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。其中,View的定义比较清晰,就是用户界面。
MVC开始是存在于桌面程序中的,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
模型-视图-控制器(MVC)是Xerox
PARC在二十世纪八十年代为编程语言Smalltalk-80发明的一种软件设计模式,已被广泛使用。后来被推荐为Oracle旗下Sun公司Java
EE平台的设计模式,并且受到越来越多的使用ColdFusion和PHP的开发者的欢迎。模型-视图-控制器模式是一个有用的工具箱,它有很多好处,但也有一些缺点
一、MVC 开发模式的优点
提高 开发的代码复用性,避免了重复性开发
有效帮助开发人员实现业务开发中【事务管理】
二、MVC开发角色组成
C: controller–控制层
M: model–业务模型层,完成业务处理
service层:调用dao层来完成业务实现,负责管理所调用的dao层的【业务管理】
dao层:直接操作数据库
V: view–视图层:将处理结果写入到响应包 JSP
三、Dao层作用:
在实际的业务处理过程中,往往需要进行多次的数据库访问。这些访问性质往往是相同的,采用Dao层可以将对数据库访问进行封装,避免及进行重复性的数据库访问开发操作,同时降低维护的成本。
四、Dao层实现
Dao层角色:
Dao接口层:声明Dao接口
Dao实现层:声明Dao接口实现类
Dao层命名规则
Dao接口层:com.bjpowernode.dao [接口]:表Dao
Dao实现层 com.bjowernode.daoImpl [实现类] :表DaoImpl
五、独立使用Dao层处理业务存在问题
无法实现【业务的复用】
无法将参与同一业务的sql命令放入同一事务管理。
con.setAutoCommit(false)
PreparedStatement ps1=con . preparedStatement ( sql1 )
PreparedStatement ps2=con .preparedStatement( sql2 )
ps1 .execute();
ps2 .execute();
sql_1与sql_2是储存在同一事务中
六、service层作用
封装的是一个具体业务的实现方案,来提高业务实现的复用性。
负责将参与本次业务实现的Dao层中事务进行管理。
七、service层实现
角色
service接口层
service实现层
命名
service接口层:com.biowernode.service [接口] 如果本次业务之和一张表关联 --表名Service ;
如果本次业务与多张表关联 --业务名称Service
service实现层:com.biowernode.serviceImpl [接口] 如果本次业务之和一张表关联 —表名ServiceImpl ;
如果本次业务与多张表关联 —业务名称ServiceImpl
八、service层的简化开发:
service层需要负责本次业务中的事务管理
try{
con.setAutoCommit(false)
dao...
dao...
con.commit
}catch(Exception ex){
con.rollback()
}finally{
con.close()
}
九、三层架构
三层架构就是为了符合“高内聚,低耦合”思想,把各个功能模块划分为表示层(UI)、业务逻辑层(BLL)和数据访问层(DAL)三层架构,各层之间采用接口相互访问,并通过对象模型的实体类(Model)作为数据传递的载体,不同的对象模型的实体类一般对应于数据库的不同表,实体类的属性与数据库表的字段名一致。
三层架构区分层次的目的是为了 “高内聚,低耦合”。开发人员分工更明确,将精力更专注于应用系统核心业务逻辑的分析、设计和开发,加快项目的进度,提高了开发效率,有利于项目的更新和维护工作。
例子
在后厨中,小小的餐厅厨房,却是厨师们的一番战场。都说艺术来源于生活,同样,技术也是如此。其实,三层架构就可以用后厨这个场景来抽象理解。
- 服务员:负责接待客人和传菜
- 主厨:后厨的头头,后处里主厨说了算。可以理解为架构师,负责后厨和服务员的对接
- 小厨:每个小厨有自己特定的工作,各司其职
三层架构每层之间的逻辑关系:
三层优缺点
【优点】
- 开发人员可以只关注整个结构中的其中某一层;
- 可维护性高,可扩展性高
- 可以降低层与层之间的依赖;
- 有利于标准化;
- 利于各层逻辑的复用
【缺点】
- 降低了系统的性能。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成
- 有时会导致级联的修改,这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码
- 增加了开发成本
为什么使用三层
使用三层架构的目的:解耦!!!
同样拿上面饭店的例子来讲:
服务员(UI层)请假——另找服务员;
主厨(BLL层)辞职——招聘另一个主厨;
小厨(DAL)辞职——招聘另一个小厨;
【顾客反映】
你们店服务态度不好——服务员的问题。开除服务员;
你们店菜里有虫子——主厨的问题。换厨师;
任何一层发生变化都不会影响到另外一层!!!
MVC与三层架构的区别
无论是MVC还是三层架构,都是一种规范,都是奔着"高耦合,低内聚"的思想来设计的。三层中的UI和Servlet来分别对应MVC中的View和Controller,业务逻辑层是来组合数据访问层的原子性功能的。
在三层中,业务逻辑层和数据访问层要遵循面型接口编程的。这种接口定义和具体实现逻辑的分开,非常有利于后续扩展和维护!