- 分析AccountTransferServlet类都负责了什么?
-
- 数据接收
- 核心的业务处理
- 数据库表中数据的crud操作
- 负责了页面的数据展示
- 做了很多
- 在不使用MVC架构模式的前提下,完成银行账户转账的缺点:
-
- 代码的复用性太差。因为没有进行职能分工,没有独立组件的概念,所以没有办法进行代码复用。代码和代码之间的耦合度太高,扩展力太差
- 耦合度高,导致代码很难扩展
- 操作数据库的代码和业务逻辑代码写在一起,很容易出错,无法专注业务逻辑的编写
- 全部都写在了一个Servlet类中
MVC架构模式的理论基础
- 理解系统为什么要分层?
-
- 这样可以降低代码的耦合度,扩展力强,组件的可复用性增强
- MVC是一种软件架构模式(是一种软件架构设计思想,不止Java开发中用到,其它语言也需要用到),它将应用分为三块:
-
- M(Model:数据/业务):负责业务处理及数据收集(包含了业务逻辑层和持久层)
- V(View:视图/展示) :负责页面的展示(负责数据的展示)
- C(Controller:控制器):负责调度。它是一个调度中心,它来决定什么时候调用Model来处理业务,什么时候调用View视图来展示数据。
- MVC架构模式如下所示:
- MVC架构模式的描述:①前端浏览器发送请求给web服务器,web服务器中的Controller接收到用户的请求,Controller将前端提交的数据进行封装,②然后Controller调用Model来处理业务,Model处理完业务后返回处理后的数据给Controller,③Controller再调用View来完成数据的展示,最终将结果响应给浏览器,浏览器进行渲染展示页面。
面试题:什么是三层模型,并说一说MVC架构模式与三层模型的区别?
三层模型:
三层架构中哪些是MVC架构的部分:
现代的开发方式大部分都是MVC架构模式结合三层模型一起用。
MVC 和三层模型都采用了分层结构来设计应用程序,都是降低耦合度,提高扩展力,提高组件复用性。
区别在于:
- 三层模型更关注业务逻辑组件的划分。
- MVC架构模式关注整个应用程序的层次关系和分离思想。
JavaEE设计模式之DAO
- 什么是DAO
-
- Data Access Object(数据库访问对象),DAO是一种设计模式,属于JavaEE的设计模式之一。
- DAO类(Mapper类):负责做数据库表增删改查的类,在里面定义了一些操作数据库表crud的方法,没有任何处理业务逻辑的方法在里面。
- (做XXX数据库表crud的Mappp类 就叫做XXXMapper)
- DAO对象:专门做数据表增删改查的对象,没有任何的业务逻辑。
- 注意:一般情况下,一张表对应一个DAO对象
- DAO类中一般有这些方法
-
-
- insert方法、delete方法、update方法、select方法、selectAll方法
-
- 例如t_act账户信息表的DAO类
package mvc;
import utils.DBUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* AccountDao负责做数据表的crud
*/
public class AccountDao {
/**
* 插入账户信息
* @param act 账户信息
* @return
*/
public int insert(Account act){
//声明和操作数据库相关的对象
Connection connection = null;
PreparedStatement ps = null;
int count = 0;
try {
//获取数据库连接对象
connection = DBUtil.getConnection();
//获取预编译的数据库操作对象
String sql = "insert into t_act(actno,balance)values(?,?,)";
ps = connection.prepareStatement(sql);
ps.setString(1, act.getActno());
ps.setDouble(2,act.getBalance());
//执行SQL语句
count = ps.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
//关闭数据库资源
DBUtil.close(connection,ps,null);
}
return count;
}
/**
* 根据主键删除账户信息
* @param id 主键
* @return
*/
public int deleteById(Long id){
Connection connection = null;
PreparedStatement ps = null;
int count = 0;
try {
connection = DBUtil.getConnection();
String sql = "delete from t_act where id = ?";
ps = connection.prepareStatement(sql);
ps.setLong(1,id);
count = ps.executeUpdate();
}catch (SQLException e){
e.printStackTrace();
}finally {
DBUtil.close(connection,ps,null);
}
return count;
}
/**
* 更新账户信息
* @param act 账户信息
* @return
*/
public int update(Account act){
Connection connection = null;
PreparedStatement ps = null;
int count = 0;
try {
connection = DBUtil.getConnection();
String sql = "update t_act set balance = ?,actno = ? where id = ?";
ps = connection.prepareStatement(sql);
ps.setDouble(1,act.getBalance());
ps.setString(2, act.getActno());
ps.setLong(3,act.getId());
count = ps.executeUpdate();
}catch (SQLException e){
e.printStackTrace();
}finally {
DBUtil.close(connection,ps,null);
}
return count;
}
/**
* 根据账户查询一条账户信息,返回一个封装好的Account对象
* @param actno 账号
* @return
*/
public Account selectByActno(String actno){
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
Account act = null;
int count = 0;
try {
connection = DBUtil.getConnection();
String sql = "select id,actno,balance from t_act where actno = ?";
ps = connection.prepareStatement(sql);
ps.setString(1,actno);
resultSet = ps.executeQuery();
if(resultSet.next()){
Long id = resultSet.getLong("id");
Double balance = resultSet.getDouble("balance");
//将属性值封装成对象
act = new Account();
act.setId(id);
act.setBalance(balance);
act.setActno(actno);
}
}catch (SQLException e){
e.printStackTrace();
}finally {
DBUtil.close(connection,ps,resultSet);
}
return act;
}
/**
* 获取所有账户信息
* @return
*/
public List<Account> selectAll(){
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
List<Account> list = new ArrayList<>();
int count = 0;
try {
connection = DBUtil.getConnection();
String sql = "select id,actno,balance from t_act";
ps = connection.prepareStatement(sql);
resultSet = ps.executeQuery();
while (resultSet.next()){
Long id = resultSet.getLong("id");
String actno = resultSet.getString("actno");
Double balance = resultSet.getDouble("balance");
//将这些数据封装成对象
// Account act = new Account();
// act.setId(id);
// act.setActno(actno);
// act.setBalance(balance);
Account act = new Account(id,actno,balance);
//添加到集合中
list.add(act);
}
}catch (SQLException e){
e.printStackTrace();
}finally {
DBUtil.close(connection,ps,resultSet);
}
return list;
}
}
pojo==javabean==domain实体类
pojo==javabean==domain类:专门用于封装数据的类
pojo对象:简单的对象,专门用于封装数据的对象,也叫作为javabean对象,domain对象。
业务逻辑层的抽取及业务类的实现
- service翻译为:服务,业务。
- 在service业务类 中只编写纯业务代码,业务类一般起名为XxxService、XxxBiz。如AccountService类是专门处理Account业务的一个类。
- 一个业务对应业务类中的一个方法
MVC架构模式和三层架构的关系
先来说三层架构:
用户发送请求过来后:
- 表现层调用业务逻辑层进行业务处理,
- 业务逻辑层再调用持久层去操作数据库;
- 之后再将数据的处理结果一层一层的返回到表示层
代码实现:
- 用户发送请求过来到控制器,
- 在控制器类的处理器方法中使用业务逻辑层的对象调用相关业务方法,
- 在业务逻辑类中又使用持久层对象调用其操作数据库表的方法。
三层架构图:
MVC架构模式和三层架构的关系:
- MVC中的控制器和视图是三层架构中的表示层。
- MVC的Model是三层架构中的其余部分
不同功能的类放在不同的包下
- 三层架构中:
-
- servlet、jsp是表示层
- service是业务逻辑层
- 持久层是dao
- 在MVC架构模式中
-
- bean、dao、service都属于M
- jsp是V
- servlet是C
web包是放servlet类的
层与层之间是通过接口调用的,也就是面向接口编程,需要先在每个包中创建接口,然后再创建一个和接口同级的包叫imple,里面创建接口的实现类
ThreadLocal类源码分析及概述
源码
- ThreadLocal(线程局部变量类)其实就是在ThreadLocal类中定义了个Map<Thread,T>集合,key存储的是当前线程,value存与当前线程绑定的数据(对象)
- 作用:提供线程的局部(本地)变量,它是每个线程私有的(局部)本地变量,使用ThreadLocal存储的数据是线程安全的 。通过ThreadLocal使程序中不同位置获取到的数据库连接对象是同一个
package com.threadlocal;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* 自定义一个ThreadLocal类
*/
public class MyThreadLocal<T> {
/**
* 创建了一个Map集合,用于存储和当前线程 绑定 的数据(对象)
*/
private Map<Thread,T> map = new HashMap<>();
/**
* 向ThreadLocal变量中绑定数据:把当前线程和对象(数据)绑定
*/
public void set(T obj){
map.put(Thread.currentThread(),obj);
}
/**
* 从ThreadLocal中获取当前线程对应的对象(数据)
* @return
*/
public T get(){
return map.get(Thread.currentThread());
}
/**
* 删除ThreadLocal中的数据,删除当前线程对应的数据库连接对象
*/
public void remove(){
map.remove(Thread.currentThread());
}
}
概述
介绍:
ThreadLocal 并不是一个Thread,而是Thread的局部变量。
ThreadLocal为每个线程提供单独一份存储空间,具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问。
客户端发送的每一次请求,都是单独的一个线程。
常用方法:
public void set(T value) 设置当前线程的线程 局部变量值。
public T get() 获取当前线程的线程 局部变量值。
public void remove() 移除当前线程的线程 局部变量值
ThreadLocal的应用场景
- 线程上下文传递:在不同的线程中传递上下文信息,例如将用户信息和请求ID存储在ThreadLocal中,在后续的请求处理链中可以方便的访问。
- 数据库连接管理:在使用数据库连接池的情况下,可以把数据库的连接存储在ThreadLocal中,这样每个线程可以独立管理自己的数据库连接,从而有效减少线程间的竞争,提高资源利用率(Mybatis中的SqlSession对象使用了ThreadLocal存储当前线程的数据库会话信息)
- 事务管理:在需要手动管理事务时,使用ThreadLocal存储事务的上下文,每个线程可以独立控制自己的事务,保证事务的隔离性(Spring中的TransactionSynchronizationManager类使用了ThreadLocal存储事务的上下文信息)
- 总结:在使用ThreadLocal中需要避免出现内存泄漏的问题