• 高效掌握JDBC技术(三)| 三层架构理念 | 书写符合事务特性的工具类 | JUnit测试框架 | JDBC项目开发步骤


    ✅作者简介:热爱后端语言的大学生,CSDN内容合伙人
    ✨精品专栏:C++面向对象
    🔥系列专栏:JDBC快速入门

    1、三层架构

    • 一种合理的项目分层理念,好处为可以简化设计、各司其职、更容易扩展内容
    • 三层架构分为:
      • 表示层(UI、WEB):跟用户对接
      • 业务逻辑层(service):书写功能的整体逻辑
      • 数据访问层(dao):对接数据库

    1.1、数据访问层

    • DAO:和数据库交接、内存放着对数据库内容增删改查的方法

    1.2、业务逻辑层

    • Service:存放着代表主要功能的方法,内部内容主要为调用DAO+逻辑控制代码

    1.2.1、组成

    Service接口:

    1. 一张表对应一个Service
    2. Service中存放着与该表相关的所有功能方法
    3. 命名与表名相关:PersonService
    4. 包:须存放在service包下 com.xxx.service

    Service实现类:

    1. 一个实现类实现一个service接口
    2. 命名为接口名+Impl:PersonServiceImpl
    3. 包:须存放在service.impl下 com.xxx.service.impl

    1.3、表示层

    • view:负责跟用户对接

    1.3.1、实现

    1. 一个功能一个视图类
    2. 命名:功能+View
    3. 包:须放在view包下 com.xxx.view
    4. 内容:调用service+Scanner

    1.4、完整实现步骤

    1. 书写实体类

      package com.bz.entity;
      
      import java.io.Serializable;
      
      public class User implements Serializable {
          private Integer id;
          private String username;
          private String pwd;
      
          @Override
          public String toString() {
              return "User{" +
                      "id=" + id +
                      ", username='" + username + '\'' +
                      ", pwd='" + pwd + '\'' +
                      '}';
          }
      
          public User(Integer id, String username, String pwd) {
              this.id = id;
              this.username = username;
              this.pwd = pwd;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
    2. 书写DAO

      package com.bz.dao;
      
      import com.bz.entity.User;
      
      /**
       * 跟数据库对接:从数据库中查找user信息
       */
      public interface UserDao {
          /**
           * 查询用户信息是否存在
           * @param username  用户名
           * @param pwd 密码
           * @return  用户对象
           */
          User selectUser(String username,String pwd) throws Exception;
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
    3. 书写DaoImpl

      package com.bz.dao.impl;
      
      import com.bz.dao.UserDao;
      import com.bz.entity.User;
      import com.bz.util.JDBCUtils;
      
      import java.sql.Connection;
      import java.sql.PreparedStatement;
      import java.sql.ResultSet;
      
      public class UserDaoImpl implements UserDao {
          @Override
          public User selectUser(String username, String pwd) throws Exception {
              User user=null;//用来返回
      
              Connection conn= JDBCUtils.getConnection();
              String sql = "select * from t_user where u_username=? and u_pwd=?";
              PreparedStatement ps=conn.prepareStatement(sql);
              ps.setString(1,username);
              ps.setString(2, pwd);
      
              ResultSet rs=ps.executeQuery();
              if (rs.next()) {
                  Integer id = rs.getInt("u_id");
                  String name = rs.getString("u_username");
                  String password = rs.getString("u_pwd");
                  user = new User(id, name, password);
              }
      
              JDBCUtils.close(rs,ps,conn);
      
              return user;
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
    4. 书写Service

      package com.bz.service;
      
      public interface UserService {
          /**
           * 用户登录
           * @param username  用户输入的账号名
           * @param pwd 用户输入的密码
           * @return 是否登录成功
           */
          boolean login(String username,String pwd) throws Exception;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    5. 书写ServiceImpl

      package com.bz.service.impl;
      
      import com.bz.dao.UserDao;
      import com.bz.dao.impl.UserDaoImpl;
      import com.bz.service.UserService;
      
      public class UserServiceImpl implements UserService {
          //创建Dao对象
          private UserDao ud=new UserDaoImpl();
      
          @Override
          public boolean login(String username, String pwd)throws Exception {
              if (ud.selectUser(username, pwd)!=null) {
                  return true;
              }else{
                  return false;
              }
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
    6. 书写view

      package com.bz.view;
      
      import com.bz.service.UserService;
      import com.bz.service.impl.UserServiceImpl;
      
      import java.util.Scanner;
      
      /**
       * 用户登录
       */
      public class UserloginTest {
          public static void main(String[] args) throws Exception{
      
              UserService us=new UserServiceImpl();
      
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入用户名:");
              String username=sc.next();
              System.out.println("请输入密码:");
              String pwd=sc.next();
      
              //调用Service方法判断登录是否成功
              if (us.login(username,pwd)){
                  System.out.println("登录成功!");
              }else {
                  System.out.println("登录失败");
              }
      
      
          }
      }
      
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32

    2、事务及JDBCUtils最终版

    • 回顾事务概念:将多个操作步骤归为同一个原子操作,要么同时成功,要么同时失败

      开启事务

      执行操作

      结束事务:commit rollback

    • 通常需要添加在Service层,Service层的所有功能方法都应该配套事务

    2.1、事务基本操作与问题解决

    1. 开启事务:Connection对象.setAutoCommit(false)
    2. 结束事务:
      • 提交:Connection对象.commit();
      • 回滚:Connection对象.rollback();

    2.1.1、存在问题

    操作事务和操作数据库数据的数据库连接不是同一个,或导致事务回滚不会影响数据库内容

    2.1.2、解决方案:ThreadLocal

    • 思路: 放入线程的存储空间中,ServiceDAO不再自行创建conn,如有需要,直接从线程存储空间中取出

    • 实现:

      1. 确保工具类只会创建一个conn对象

      2. 使用ThreadLocal将工具类创建的conn对象放入存储空间

        ThreadLocal:可以操作线程存储空间的工具,可以对空间的数据进行添加、获取、删除

        添加:ThreadLocal对象.set(数据)

        获取:ThreadLocal对象.get()

        删除:ThreadLocal对象.remove()

    • 使用:

      • 由于DAO和Service共用同一个conn,并且Service一定晚于DAO执行结束,所以为了确保Service的执行,DAO中不能关闭conn,该操作应由Service完成

    2.2、JDBCUtils-最终版

    package com.bz.util;
    
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    /**
     * 工具类:方便方法调用,所有方法都应为静态方法
     */
    public class JDBCUtils {
        //提升集合的作用范围,确保getConnection方法中也能使用
        private static Properties p=null;
        //创建操作线程存储空间的工具对象
        private static ThreadLocal<Connection> tl=new ThreadLocal<>();
    
        //把流对象的创建放入静态初始代码块,确保在工具类类加载时执行
        static{
            try(
                    //通过类对象.getResourseAsStream()获取一个字节输入流对象
                    //当前配置文件在src之下
                    InputStream is=JDBCUtils.class.getResourceAsStream("/jdbc.properties");
            ){
                //创建用来接收的Properties集合
                p=new Properties();
                //调用方法加载配置文件的内容至集合中
                p.load(is);
                //1. 加载驱动
                Class.forName(p.getProperty("driverClassName"));
            }catch (ClassNotFoundException e) {
                System.out.println("驱动路径不正确");
            } catch (Exception e){
                e.printStackTrace();
            }
    
        }
    
        /**
         * 获取Connection连接
         * @return
         */
        public static Connection getConnection(){
            Connection conn =tl.get();
            try {
                if (conn==null) {//这里如果线程存储空间里没有conn就创建conn并存入线程空间
                    //2. 获取连接
                    //连接的url
                    String url = p.getProperty("url");
                    //用户名
                    String username = p.getProperty("username");
                    //密码
                    String pwd = p.getProperty("password");
                    conn = DriverManager.getConnection(url, username, pwd);
                    //将新创建的conn放入线程的存储空间
                    tl.set(conn);
                }
            } catch (SQLException e) {
                System.out.println("获取连接失败");
            } catch (Exception e) {
                System.out.println("未知异常");
                e.printStackTrace();
            }
            return conn;
        }
        /**
         * 关闭资源连接  非空判断:防止空指针
         * @param rs
         * @param ps
         * @param conn
         */
        public static void close(ResultSet rs, PreparedStatement ps,Connection conn){
            if (rs!=null){
                try {
                    rs.close();
                } catch (SQLException e) {
                    System.out.println("关闭rs失败");
                }
            }
            if (ps!=null){
                try {
                    ps.close();
                } catch (SQLException e) {
                    System.out.println("关闭ps失败");
                }
            }
            if (conn!=null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    System.out.println("关闭conn失败");
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    3、JUnit测试框架

    • 作用:DAO层和Service层中的方法通常需要经过测试JUnit可以通过@Test注解完成执行测试,大大减少测试成本

    3.1、使用步骤

    1. 导入jar包:

      • hamcrest-core-1.3.jar

      • junit-4.12.jar

    2. 创建测试类

      • 命名:被测试的类/接口+Test
      • 包:须放在test包下
    3. 使用

      • @Test注解必须写在方法上方
      • 方法必须为公开、非静态、无参、无返回值的最普通的普通方法
      • 一个测试方法中只能测试一个方法
      • 通常情况下,测试方法名应与被测试方法一致,目的更为清晰

    3.2、使用示例

    package com.bz.test;
    
    import com.bz.dao.AccountDao;
    import com.bz.dao.impl.AccountDaoImpl;
    import com.bz.entity.Account;
    import org.junit.Test;
    
    public class AccountDaoImplTest {
    
        //创建被测试的对象
        AccountDao ad=new AccountDaoImpl();
    
        @Test
        public void selectAccountByName(){
            Account a = ad.selectAccountByName("张三");
            System.out.println(a);
        }
        @Test
        public void updateAccountByName(){
            int n = ad.updateAccountByName("张三", 100);
            System.out.println(n);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    4、JDBC项目开发步骤总结

    首先要根据要求来建库建表(数据库的内部操作)

    1. 导入jar包:

      hamcrest-core-1.3.jar
      junit-4.12.jar
      mysql-connector-java-8.0.23.jar

    2. 添加工具类(JDBCUtils最终版)

    3. 在src下添加工具类所需的jdbc.properties

    4. 书写实体类

    5. 搭建DAO

      • 必须测试
    6. 搭建Service

      • 最好也进行测试
    7. 书写view(不需要过多关注,实际开发中该层对接的应该是浏览器页面

    项目结构图示:

    在这里插入图片描述


    高效掌握JDBC的分享到此结束,希望对大家有所帮助,如有疑问欢迎大家交流指正。

  • 相关阅读:
    【Redis学习笔记】第二章【2.3】Redis数据类型--list
    Vue.js 2—插槽 Slots
    为让学生顺利毕业, 导师研究出著名的研究生 20 条法则: 第一, 不要有任何度假休息的打算……
    《智谋故事》收纳
    java生成数据库数据到excel当做下拉选择,copy就完事~
    带你快速掌握Linux最常用的命令(图文详解)- 最新版(面试笔试常考)
    Go 语言的垃圾回收机制:自动化内存管理
    android linkToDeath内存泄露分析
    Android单元测试
    量化交易:10000资金起步,五年看看能做到多少?
  • 原文地址:https://blog.csdn.net/m0_58618795/article/details/126826472