JDBC应用最全笔记(附带案例)

JDBC

一、概述

在Java中,数据库存取技术可分为如下⼏类:

1、JDBC直接访问数据库

2、 JDO技术(Java Data Object)

3、第三⽅O/R⼯具,如Hibernate, Mybatis 等

JDBC是java访问数据库的基⽯,JDO, Hibernate等只是更好的封装了JDBC。

二、理解

JDBC(Java Database Connectivity)是⼀个独⽴于特定数据库管理系统(DBMS)、通⽤的SQL数据库存取和操作的公共接⼝(⼀组API),定义了⽤来访问数据库的标准Java类库,使⽤这个类库可以以⼀种标准的⽅法、⽅便地访问数据库资源

JDBC为访问不同的数据库提供了⼀种统⼀的途径,为开发者屏蔽了⼀些细节问题。

JDBC的⽬标是使Java程序员使⽤JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员⽆需对特定的数据库系统的特点有过多的了解,从⽽⼤⼤简化和加快了开发过程。

如果没有JDBC,那么Java程序访问数据库时是这样的:

在这里插入图片描述

有JDBC,那么Java程序访问数据库时是这样的:

在这里插入图片描述

三、JDBC API

JDBC API是⼀系列的接⼝,它统⼀和规范了应⽤程序与数据库的连接、执⾏SQL语句,并到得到返回结果等各类操作。声明在java.sql与javax.sql包中。

1、DriverManager类 管理不同的驱动

2、Connection 接⼝ 应⽤和数据库的连接

3、Statement 接⼝ ⽤于执⾏sql语句

4、 ResultSet 接⼝ 保存查询的结果

四、JDBC的使用

1、下载驱动:

驱动程序由数据库提供商提供下载。 MySQL的驱动下载地址:http://dev.mysql.com/downloads/

2、创建项⽬导⼊jar包

3、 使⽤:

① 注册驱动(加载驱动)

② 获取连接对象

③ 创建命令对象

④ 编写sql命令

⑤ 执⾏sql命令 返回结果

⑥ 处理结果

⑦ 释放资源

 private static void queryAll() throws ClassNotFoundException, SQLException {
    
    
        //  1、加载驱动
        // DriverManager.registerDriver(new com.mysql.jdbc.Driver());
        Class.forName("com.mysql.jdbc.Driver");
        //  2、获取连接  参数1:连接路径    参数2:用户名  参数3:密码
        //  https://downloads.mysql.com/archives/c-j/
        Connection connection = DriverManager
                .getConnection("jdbc:mysql://localhost:3306/java0210", "root", "123456");

        System.out.println(connection);
        System.out.println(connection==null?"连接失败":"连接成功");

        //3、 编写sql语句
        String sql = "select * from user";

        //4、创建命令对象
        Statement statement = connection.createStatement();

        //5、执行sql语句 返回结果
        ResultSet rs = statement.executeQuery(sql);


        //6、处理结果    rs.next()如果为true 集合中还有内容 如果为false 数据获取完毕
        while(rs.next()){
    
    
            String name = rs.getString("name");
            int age = rs.getInt("age");
            System.out.println("姓名:"+name+"\t姓名:"+age);
           // System.out.println(rs.getString("name")+" 年龄:"+rs.getInt("age"));
        }

        //7、释放资源  遵循 先开后关原则
        rs.close();
        statement.close();
        connection.close();
    }

五、连接池

5.1、为什么使用连接池

1、数据库连接是⼀种关键的有限的昂贵的资源,传统数据库连接每发出⼀个请求都要创建⼀个连接对象,使⽤完直接关闭不能重复利⽤;

2、关闭资源需要⼿动完成,⼀旦忘记会造成内存溢出;

3、请求过于频繁的时候,创建连接极其消耗内存;

4、⽽且⼀旦⾼并发访问数据库,有可能会造成系统崩溃。

为了解决这些问题,我们可以使⽤连接池。

5.2、连接池原理

数据库连接池负责分配、管理和释放数据库连接,它的核⼼思想就是连接复⽤,通过建⽴⼀个数据库连接池,这个池中有若⼲个连接对象,当⽤户想要连接数据库,就要先从连接池中获取连接对象,然后操作数据库。⼀旦连接池中的连接对象被⽤完了,判断连接对象的个数是否已达上限,如果没有可以再创建新的连接对象,如果已达上限,⽤户必须处于等待状态,等待其他⽤户释放连接对象,直到连接池中有被释放的连接对象了,这时候等待的⽤户才能获取连接对象,从⽽操作数据库。这样就可以使连接池中的连接得到⾼效、安全的复⽤,避免了数据库连接频繁创建、关闭的开销。这项技术明显提⾼对数据库操作的性能。

5.3、连接池的好处

1、程序启动时提前创建好连接,不⽤⽤户请求时创建,给服务器减轻压⼒

2、连接关闭的时候不会直接销毁connection,这样能够重复利⽤

3、如果超过设定的连接数量但是还没有达到最⼤值,那么可以再创建

4、如果空闲了,会默认销毁(释放)⼀些连接,让系统性能达到最优

5.4、常见的开源连接池

1、 【DBCP】是Apache提供的数据库连接池,速度相对c3p0较快,但因⾃身存在BUG,Hibernate3已不再提供⽀持

2、【C3P0】是⼀个开源组织提供的⼀个数据库连接池,速度相对较慢,稳定性还可以

3、【Druid】是阿⾥提供的数据库连接池,据说是集DBCP 、C3P0 、Proxool 优点于⼀身的数据库连接池,但是速度不知道是否有BoneCP快

5.5、连接池的使用

5.5.1、c3p0连接池

1、下载导包 c3p0-0.9.5.2.jar mchange-commons-java-0.2.11.jar

代码配置⽅式

① 创建c3p0连接池对象

 //1、创建连接池对象
        ComboPooledDataSource cpds = new ComboPooledDataSource();

② 配置信息 (必配、选配) 【创建 c3p0.properties 放在src⽬录下

#必配信息
c3p0.driverClass = com.mysql.jdbc.Driver
c3p0.jdbcUrl = jdbc:mysql://localhost:3306/java0210
c3p0.user = root
c3p0.password = 123456

#选配
c3p0.InitialPoolSize = 10   #初始连接数
c3p0.MaxPoolSize = 200		#最大连接数
c3p0.MinPoolSize = 15		#最小连接数
c3p0.MaxIdleTime = 30		#最大空闲时间

③ 从池⼦中获取连接

 //从池子中获取连接
        Connection connection = cpds.getConnection();

④ sql 操作

		//1、编写sql
        String sql = "select * from user where age = 23";
        //2、创建命令对象
        Statement statement = connection.createStatement();
        //3、执行命令 返回结果
        ResultSet resultSet = statement.executeQuery(sql);
        //4、处理结果
        if (resultSet.next()){
    
    
            String name = resultSet.getString("name");
            int age = resultSet.getInt("age");
            System.out.println("姓名:"+name+"\t姓名:"+age);
        }
        //5、把连接对象放回连接池
        connection.close();

5.5.2、Druid连接池

1、下载导包 druid-1.1.10.jar 在lib目录下

2、 编写druid.properties 放在src⽬录下

#必配
driver.ClassName = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/java0210
username = root
password = 123456
#选配
initialSize = 15		#初始连接数
maxActive = 100			#最大连接数
minIdle = 5				#最小连接数
maxWait = 30000			#最大空闲时间

3、读取配置文件

// 一、读取配置文件
        Properties properties = new Properties();

        // 根据当前线程对象的上下文类加载器 以流的方式 读取src目录下的文件
        InputStream asStream = Thread.currentThread()
                .getContextClassLoader().getResourceAsStream("druid.properties");

        properties.load(asStream);

4、创建druid连接池对象

// 二、创建druid连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

5、从连接池中获取连接

 //从池子中获取连接
        Connection connection = dataSource.getConnection();

6、sql 操作

		//1、编写sql
        String sql = "select * from user where age = 23";
        //2、创建命令对象
        Statement statement = connection.createStatement();
        //3、执行命令 返回结果
        ResultSet resultSet = statement.executeQuery(sql);
        //4、处理结果
        if (resultSet.next()){
    
    
            String name = resultSet.getString("name");
            int age = resultSet.getInt("age");
            System.out.println("姓名:"+name+"\t姓名:"+age);
        }
        //5、把连接对象放回连接池
        connection.close();

5.6、封装JDBCTools

ThreadLocal类

理解】JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了⼀种新的思路。使⽤这个⼯具类可以很简洁地编写出优美的多线程程序。

原理

ThreadLocal⽤于保存某个线程共享变量,原因是在Java中,每⼀个线程中都有⼀个ThreadLocalMap<ThreadLocal, Object>,其key就是⼀个ThreadLocal,⽽Object即为该线程的共享变量。⽽这个map是通过ThreadLocal的set和get⽅法操作的。对于同⼀个static ThreadLocal,不同线程只能从中get,set,remove⾃⼰的变量,⽽不会影响其他线程的变量。

使⽤

1、ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值。

2、ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值。

3、ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。

public class JDBCPoolTools2 {
    
    
    static DataSource dataSource;
    // 实例化ThreadLocal类
    private static ThreadLocal<Connection> t = new ThreadLocal<>();
    static {
    
    
        try{
    
    
            // 一、读取配置文件
            Properties properties = new Properties();

            // 根据当前线程对象的上下文类加载器 以流的方式 读取src目录下的文件
            InputStream asStream = Thread.currentThread()
                    .getContextClassLoader().getResourceAsStream("druid.properties");
            properties.load(asStream);
            //2、创建连接池
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    // 定义一个获取连接的静态方法
    public static Connection getConnection(){
    
    
        try {
    
    
            //1、从连ThreadLocal中获取连接
            Connection connection = t.get();
            if (connection==null){
    
    
                //2、如果连接为空,从连接池中获取一个连接对象
                t.set(dataSource.getConnection());
                //3、把这个连接对象绑定到ThreadLocal类
                connection = t.get();
            }
            return connection;
        } catch (SQLException e) {
    
    
            throw new RuntimeException(e);
        }
    }

    //封装释放连接对象的方法
    public static void release(){
    
    
        // 1、将连接对象 和 ThreadLocal类 解绑
        Connection connection = t.get();
        t.remove();
        // 2、释放资源
        if (connection!=null){
    
    
            try {
    
    
                connection.close();
            } catch (SQLException e) {
    
    
                throw new RuntimeException(e);
            }
        }
    }
}

测试类

public static void main(String[] args) {
    
    
        //    建立连接  从JDBCPoolTools2中调用 getConnection()方法
        Connection connection = JDBCPoolTools2.getConnection();
        try {
    
    
        //     sql操作
            String sql = "select * from admin_user";
            Statement statement = connection.createStatement();
            ResultSet resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
    
    
                String username = resultSet.getString("username");
                String password = resultSet.getString("password");
                System.out.println("账号:"+username+"\t密码:"+password);
            }
        } catch (SQLException e) {
    
    
            throw new RuntimeException(e);
        }finally {
    
    
        //     必须必须【解绑】和【释放资源】,从JDBCPoolTools2中调用 release()方法
            if (connection!=null){
    
    
                Up_DruidPool_03.release();
            }
        }
    }

六、juint

6.1、概述

JUnit是⼀个Java语⾔的单元测试框架。测试分为:⿊盒测试和⽩盒测试。

⿊盒测试⼜称功能测试,主要检测每个功能是否都能正常使⽤。在测试中,把程序看作⼀个不能打开的⿊盒⼦,在完全不考虑程序内部结构和内部特性的情况下,进⾏测试,主要针对软件界⾯和软件功能进⾏测试。 ⽩盒测试⼜称结构测试、透明盒测试、逻辑驱动测试或基于代码的测试,主要检测程序内部逻辑是否正常。在测试中测试者必须检查程序的内部结构,从检查程序的逻辑着⼿,得出测试数据。按照程序内部的结构进⾏测试。这⼀⽅法是把测试对象看作⼀个打开的盒⼦,测试⼈员清楚盒⼦内部的东⻄以及⾥⾯是如何运作的单元测试Junit就属于⽩盒测试.

6.2、使用

1、把junit4.x的测试jar,添加到该项⽬中来;

2、定义⼀个测试类 测试类的名字: XxxTest,如EmployeeDAOTest

3、 在EmployeeDAOTest中编写测试⽅法:如

@BeforeClass
    public static void beforeClass(){
     
     
        
}

@Before
public void bef(){
     
     
        
}

@Test
public void testXxx() throws Exception {
     
     

 }

@After
public void aft(){
     
     
       
}

@AfterClass
public static void afterClass(){
     
     

}

注意:⽅法是public修饰的,⽆返回的,该⽅法上必须贴有@Test标签,XXX表示测试的功能名字

4、选择某⼀个测试⽅法,⿏标右键选择 [run as junit],或则选中测试类,表示测试该类中所有的测试⽅法.

6.3、常见注解

1、@Test:要执⾏的测试⽅法

2、@Before:每次执⾏测试⽅法之前都会执⾏

3、@After: 每次执⾏测试⽅法之后都会执⾏

4、 @BeforeClass:在所有的Before⽅法之前执⾏,只在最初执⾏⼀次. 只能修饰静态⽅法

5、@AfterClass:在所有的After⽅法之后执⾏,只在最后执⾏⼀次. 只能修饰静态⽅法

七、SQL注入

7.1、理解

SQL 注⼊是利⽤某些系统没有对⽤户输⼊的数据进⾏充分的检查,⽽在⽤户输⼊数据中注⼊⾮法的 SQL 语句段或命令,从⽽利⽤系统的 SQL 引擎完成恶意⾏为的做法。对于 Java ⽽⾔,要防范 SQL 注⼊,只要⽤

PreparedStatement 取代 Statement 就可以了。

7.2、解决

SQL注入问题:sql语句中拼接了一些特殊字符 导致sql语句发生变化的现象

  • 引发原因:特殊字符导致
    
  • 解决:将特殊字符转义为普通字符  将传递的字符作为一个整体 Statement命令对象 换成PreparedStatement
    
  • PreparedStatement 原理:预编译命令对象
    
  • 1、sql语句时 使用?作为占位符 如果里面有特殊符号 自动转义

  • 2、先编译sql语句 执行时再传递参数

    PreparedStatement 好处:

  •         1. 不用拼接字符串 避免了拼接字符串产生的问题
    
  •         2. 自检特殊字符
    
  •         3. 可以复用sql语句
    

【案例】

模拟用户登录的功能

  •      1. 输入账户和密码
    
  •      2. 查询数据库中是否有该用户
    
  •          有 登录成功
    
  •          没有 登录失败
    
public class JDBCTest2 {
    
    
    String username;
    String pwd;
    Connection connection;
    @Before
    public void bef(){
    
    
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名:");
        username = input.nextLine();
        System.out.println("请输入密码:");
        pwd = input.nextLine();

        connection = JDBCTools.getConnection();
    }
    @Test  // 使用Statement
    public void testLogin1(){
    
    

        // 根据用户名和密码查询用户
        try {
    
    

            // select * from user where name='大洋洋' and password='123321';
            String sql = "select * from user where name='"+username+"' and password='"+pwd+"'";

            Statement statement = connection.createStatement();

            ResultSet resultSet = statement.executeQuery(sql);

            System.out.println(resultSet.next()?"登录成功!":"登录失败!");

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }

    }

    @Test  // 使用PreparedStatement
    public void testLogin2(){
    
    
        try {
    
    
            // 1. 编写sql语句
            String sql = "select * from user where name=? and password=?";

            // 2. 创建命令对象 预编译sql语句
            PreparedStatement preparedStatement = connection.prepareStatement(sql);

            // 3. 传递sql中的参数
            preparedStatement.setString(1, username);
            preparedStatement.setString(2, pwd);

            // 4. 执行sql命令
            ResultSet resultSet = preparedStatement.executeQuery();

            // 5. 处理结果
            System.out.println(resultSet.next()?"登录成功!":"登录失败!");

        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }

    }
    @After
    public void aft(){
    
    
        JDBCTools.release();
    }
}

八、事务实现

1、 ⼿动开启事务 setAutoCommit(false)

2、 成功 提交 commit()

3、失败 回滚 rollback()

public class JDBCTxTest {
    
    
    Connection connection;
    @Before
    public void bef(){
    
    
        connection = JDBCTools.getConnection();
    }

    @Test  // 使用事务
    public void textUseTx(){
    
    
        try {
    
    
            // 1. 设置事务提交为手动  2. 开启一个新的事务
            connection.setAutoCommit(false);

            String sql = "update user set money=? where uid=?";

            PreparedStatement preparedStatement = connection.prepareStatement(sql);

            preparedStatement.setDouble(1, 900);
            preparedStatement.setInt(2, 1);

            preparedStatement.executeUpdate();

            // 模拟异常
            int i = 10/0;

            preparedStatement.setDouble(1, 1100);
            preparedStatement.setInt(2, 2);

            preparedStatement.executeUpdate();

            connection.commit();
            System.out.println("转账成功!");
        } catch (SQLException throwables) {
    
    
            try {
    
    
                connection.rollback();
            } catch (SQLException e) {
    
    
                e.printStackTrace();
            }
            throwables.printStackTrace();
        }
    }

    @After
    public void aft(){
    
    
        JDBCTools.release();
    }
}

九、批处理

9.1、概述

JDBC操作数据库的时候,需要⼀次性插⼊⼤量的数据的时候,如果每次只执⾏⼀条SQL语句,效率可能会⽐较低。这时可以使⽤batch操作,每次批量执⾏SQL语句,调⾼效率。

9.2、实现

1、 添加批处理 addBacth();

2、执⾏批处理 executeBacth();

3、清除批处理 clearBatch();

public class JDBCBatchTest {
    
    
    Connection connection;
    @Before
    public void bef(){
    
    
        connection = JDBCTools.getConnection();
    }

    @Test  // 使用批处理
    public void textUseBatch(){
    
    
        try {
    
    
            String sql = "insert into user(name, password, money) values(?,?,?)";
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            long start = System.currentTimeMillis();

            for(int i=1; i<=10000; i++){
    
    
                preparedStatement.setString(1,"root"+i);
                preparedStatement.setString(2, i+"");
                preparedStatement.setDouble(3, i);
                // 保存到批处理中
                preparedStatement.addBatch();

                if(i%100==0){
    
    
                    // 执行批处理
                    preparedStatement.executeBatch();

                    // 清除批处理  便于下一次使用
                    preparedStatement.clearBatch();
                }
            }

            long end = System.currentTimeMillis();
            System.out.println("插入10000条花费的时间:"+(end-start)); // 6080
        } catch (SQLException throwables) {
    
    
            throwables.printStackTrace();
        }
    }

    @After
    public void aft(){
    
    
        JDBCTools.release();
    }
}

十、DBUtils

10.1、简介

commons-dbutils 是 Apache 组织提供的⼀个开源 JDBC⼯具类库,它是对JDBC的简单封装,学习成本极低,并且使⽤dbutils能极⼤简化jdbc编码的⼯作量,同时也不会影响程序的性能。

10.2、作用

DbUtils :提供如关闭连接、装载JDBC驱动程序等常规⼯作的⼯具类,⾥⾯的所有⽅法都是静态的。

该包封装了SQL的执⾏,是线程安全的。

1、可以实现增、删、改、查、批处理、

2、考虑了事务处理需要共⽤Connection。

3、该类最主要的就是简单化了SQL查询,它与ResultSetHandler组合在⼀起使⽤可以完成⼤部分的数据库操作,能够⼤⼤减少编码量。

10.2、常用方法

1、操作:update()

public int update(Connection conn, String sql, Object… params) throws SQLException:

⽤来执⾏⼀个更新(插⼊、更新或删除)操作。

2、 查询:query()

public Object query(Connection conn, String sql, ResultSetHandler rsh,Object…

params) throws SQLException:执⾏⼀个查询操作,在这个查询中,对象数组中的每个元素值被⽤来作为查询语句的置换参数。该⽅法会⾃⾏处理 PreparedStatement 和 ResultSet 的创建和关闭。

【注】:该接⼝⽤于处理 java.sql.ResultSet,将数据按要求转换为另⼀种形式。ResultSetHandler 接⼝提供了⼀个单独的⽅法:Object handle (java.sql.ResultSet rs)该⽅法的返回值将作为QueryRunner类的query()⽅法的返回值

【⽅法】:

ArrayHandler:把结果集中的第⼀⾏数据转成对象数组。

ArrayListHandler:把结果集中的每⼀⾏数据都转成⼀个数组,再存放到List中。

BeanHandler:将结果集中的第⼀⾏数据封装到⼀个对应的JavaBean实例中。

BeanListHandler:将结果集中的每⼀⾏数据都封装到⼀个对应的JavaBean实例中,存放到List⾥。

ColumnListHandler:将结果集中某⼀列的数据存放到List中。

KeyedHandler(name):将结果集中的每⼀⾏数据都封装到⼀个Map⾥,再把这些map再存到⼀个map⾥,其

key为指定的key。

MapHandler:将结果集中的第⼀⾏数据封装到⼀个Map⾥,key是列名,value就是对应的值。

MapListHandler:将结果集中的每⼀⾏数据都封装到⼀个Map⾥,然后再存放到List

10.4、使用

1、下载导包 commons-dbutils-1.7.jar

2、创建核⼼对象

QueryRunner qr = new QueryRunner();

3、执⾏命令

// 执⾏增删改
int update = qr.update(connection,sql,params); 
// 查询单条数据
T t = qr.query(connection,sql,new BeanHandler,params);
// 查询多条数据
List t = qr.query(connection,sql,new BeanListHandler,params);
// 查询特殊数据类型,如返回值为数量等等
Object t = qr.query(connection,sql,new ScalerHandler,params);

十一、Dao封装

11.1、介绍

Data Access Object访问数据信息的类和接⼝,包括了对数据的CRUD(Create、Retrival、Update、Delete),⽽不包含任何业务相关的信息

11.2、作用

为了实现功能的模块化,更有利于代码的维护和升级。

11.3、封装

封装通用的类:可以对任何表都能实现 增删改查的功能

  •     1. 增 删 改的方法
    
  •     2. 查询的方法[单查、多查、查询个数]
    
public class BasicDao<T> {
    
    
    QueryRunner qr;
    {
    
    
        qr = new QueryRunner();
    }
    // 1. 增删改方法
    public int update(String sql, Object...params){
    
    
        try {
    
    
            return qr.update(JDBCTools.getConnection(), sql, params);
        } catch (SQLException e) {
    
    
            throw new RuntimeException(e);
        }
    }

    // 2. 查询单个
    public T querySingle(String sql, Class<T> clazz, Object...params){
    
    
        try {
    
    
            return qr.query(JDBCTools.getConnection(), sql, new BeanHandler<>(clazz), params);
        } catch (SQLException e) {
    
    
            throw new RuntimeException(e);
        }
    }

    // 3. 查询多个
    public List<T> queryMore(String sql, Class<T> clazz, Object...params){
    
    
        try {
    
    
            return qr.query(JDBCTools.getConnection(), sql, new BeanListHandler<>(clazz), params);
        } catch (SQLException e) {
    
    
            throw new RuntimeException(e);
        }
    }

    // 4. 查询个数
    public Object scale(String sql, Object...params){
    
    
        try {
    
    
            return qr.query(JDBCTools.getConnection(), sql, new ScalarHandler<>(), params);
        } catch (SQLException e) {
    
    
            throw new RuntimeException(e);
        }
    }

}

十二、项目三层架构

12.1、理解

三层架构】 通常意义上的三层架构就是将整个业务应⽤划分为:界⾯层、业务逻辑层、数据访问层。区分层次的⽬的即为了 “⾼内聚低耦合” 的思想。在软件体系架构设计中,分层式结构是最常⻅,也是最重要的⼀种结构。微软推荐的分层式结构⼀般分为三层,从下⾄上分别为:数据访问层、业务逻辑层(⼜或称为领域层)、表示层。

表示层(JSP)

表现层也称为界⾯层,位于最外层(最上层),离⽤户最近。⽤于显示数据和接收⽤户输⼊的数据,为⽤户提供⼀种交互式操作的界⾯。

业务层(service)

  • 业务层在体系架构中的位置很关键,它处于数据访问层与表示层中间,起到了数据交换中承上启下的作⽤。

  • 由于层是⼀种弱耦合结构,层与层之间的依赖是向下的,底层对于上层⽽⾔是“⽆知”的,改变上层的设计对于其调⽤的底层⽽⾔没有任何影响。如果在分层设计时,遵循了⾯向接⼝设计的思想,那么这种向下的依赖也应该是⼀种弱依赖关系。

持久层(DAO)

持久层,有时候也称为是数据访问层,其功能主要是负责数据库的访问,可以访问数据库系统

12.2、特点

1、上⼀层可以调⽤下⼀层 但是 下⼀层不能调⽤上⼀层

2、不可以隔层调⽤

     return qr.query(JDBCTools.getConnection(), sql, new ScalarHandler<>(), params);
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}

}


## 十二、项目三层架构

### 12.1、理解

> 【**三层架构**】 通常意义上的三层架构就是将整个业务应⽤划分为:界⾯层、业务逻辑层、数据访问层。区分层次的⽬的即为了 “⾼内聚低耦合” 的思想。在软件体系架构设计中,分层式结构是最常⻅,也是最重要的⼀种结构。微软推荐的分层式结构⼀般分为三层,从下⾄上分别为:数据访问层、业务逻辑层(⼜或称为领域层)、表示层。
>
>  **表示层(JSP)**
>
>  表现层也称为界⾯层,位于最外层(最上层),离⽤户最近。⽤于显示数据和接收⽤户输⼊的数据,为⽤户提供⼀种交互式操作的界⾯。
>
>  **业务层(service)**
>
> * 业务层在体系架构中的位置很关键,它处于数据访问层与表示层中间,起到了数据交换中承上启下的作⽤。
>
> * 由于层是⼀种弱耦合结构,层与层之间的依赖是向下的,底层对于上层⽽⾔是“⽆知”的,改变上层的设计对于其调⽤的底层⽽⾔没有任何影响。如果在分层设计时,遵循了⾯向接⼝设计的思想,那么这种向下的依赖也应该是⼀种弱依赖关系。
>
>  **持久层(DAO)**
>
>  持久层,有时候也称为是数据访问层,其功能主要是负责数据库的访问,可以访问数据库系统

### 12.2、特点

> 1、上⼀层可以调⽤下⼀层 但是 下⼀层不能调⽤上⼀层
>
> 2、不可以隔层调⽤

![在这里插入图片描述](https://img-blog.csdnimg.cn/4b4814e9b2d54fbb9cab16991b7b31ff.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAUElLYXBpa2FhYWE=,size_20,color_FFFFFF,t_70,g_se,x_16)

猜你喜欢

转载自blog.csdn.net/PIKapikaaaa/article/details/124113065