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

✅作者简介:定制开发小程序热爱后端语言的大学生,CSDN定制开发小程序内容合伙人
✨精品专栏:
🔥系列专栏:

文章目录

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、测试框架

  • 作用: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的分享到此结束,希望对大家有所帮助,如有疑问欢迎大家交流指正。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发