JDBC BasicDAO详解(通俗易懂)

news2024/11/26 7:42:46

目录

一、前言

二、BasicDAO的引入

        1.为什么需要BasicDAO?

        2.BasicDAO示意图 : 

三、BasicDAO的分析

        1.基本说明 : 

        2.简单设计 : 

四、BasicDAO的实现

        0.准备工作 : 

        1.工具类 : 

        2.JavaBean类 : 

        3.BasicDAO类 / StusDAO类 : 

        4.测试类 : 


一、前言

  • 第七节内容,up打算和大家分享一下JDBC——BasicDAO相关的内容。
  • 注意事项——代码中的注释也很重要;不要眼高手低,自己跟着过一遍才有收获;点击文章的侧边栏目录或者文章开头的目录可以进行跳转。
  • 良工不示人以朴,所有文章都会适时补充完善。大家如果有问题都可以在评论区进行交流或者私信up。 感谢阅读!

二、BasicDAO的引入

        1.为什么需要BasicDAO?

        在传统JDBC程序的基础上,为了优化连接,我们引入了连接池的概念,并且学习了Druid(德鲁伊)连接池的使用;而在此基础上,为了优化对结果集的操作,我们又引入了ApacheDBUtils工具类。靠着DBUtils + Druid,JDBC程序的编写流程和效率得到了极大优化。

        但是,即便如此,"DBUtils + Druid"依然存在了一些不可忽视的问题。如下——

        在JDBC四部曲的“执行SQL”步骤中,SQL是已经写死的,要操作的表和字段均已固定,而不能通过参数传入,通用性差

        对于DQL,如果有返回结果集的需要,返回值类型是无法确定的,需要使用泛型

        很多情况下,需要同时操作多张表业务需求复杂,不可能只靠一个Java类来实现

        2.BasicDAO示意图 : 

                示意图如下 : (从下往上看!

                初看时可能会感觉这张图复杂,这里稍微解读一下。
                先看最下面,这一块区域 : (Domain, POJO, JavaBean)

                在上一小节DBUtils详解中我们说过这个JavaBean,就是把每个要操作的表都对应一个JavaBean类,类中的属性是表中字段的映射。这么做是为了将来把多个保存了表数据信息的JavaBean实例封装到一个集合中,便于数据的管理和复用。

               再看中间那一部分 : (DAO)

                其实这里的DAO就是指“数据访问对象”(Data Access Object),当然我们后面是会讲到的。 DAO的设计理念是为每一张要操作的表都单独设置一个对应的DAO,以完成对该表的CRUD操作,不同DAO只完成它对应那张表的操作,以达到“各司其职,各尽其责”的效果,使表的操作更具有针对性,业务更清晰。
                由于不同的DAO都存在共有的操作,例如获取连接,释放资源。因此根据OOP的设计理念,我们将这些共有的操作单独再封装到一个DAO中,也就是BasicDAO了,然后让操作表的DAO去继承BasicDAO。

                再看最上面,最右上方这一块区域 : (应用区)

                有了DAO之后,我们想访问那张表,直接去操作该表对应的DAO即可(复读机)。
                当然,up画的示意图中只划分了三部分,因为咱们还是基础入门阶段,实际上可能会有5个,6个甚至更多部分(比如业务层,界面层等等),大家了解一下即可。


三、BasicDAO的分析

        1.基本说明 : 

        DAO(Data Access Object),指数据访问对象,用于完成对表中数据的访问。

        BasicDAO作为这样的一个通用类,专门用于和数据库交互,即完成对数据库中表的crud操作;在BasicDAO的基础上,可以实现一张表对应一个DAO,以更好地完成功能。
        eg : employee表 <=> Employee.java类(JavaBean)<=> EmployeeDAO.java。

        2.简单设计 : 

        如果我们想设计并使用一个BasicDAO,可以在同一包下建多个子包,不同的子包存放不同功能的类或接口,此处我们只建立4个子包,up以src目录下的dao_ex包为演示包,如下图所示 : 

        在dao包下分别建立domain, dao, utils, test四个子包,它们的功能如下——

        dao_ex.domain : 用于存放相关JavaBean类;

        dao_ex.dao : 用于存放XxxDAO 和 BasicDAO;

        dao_ex.utils : 用于存放相关工具类;

        dao_ex.test : 用于存放DAO的测试类。

        建立子包情况如下图所示 : 


四、BasicDAO的实现

        0.准备工作 : 

                up就以stus表为例,如下图所示 : 

                我们来逐个完成stus表对应的工具类,JavaBean类,DAO类和测试类。

        1.工具类 : 

                此处的“工具类”其实就是我们之前在“连接池”小节中讲过的德鲁伊连接池的工具类,我们直接拿来用就行。

                工具类JDBCUtilsDruid类,代码如下 : 

package dao_ex.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

public class JDBCUtilsDruid {
    private static DataSource dataSource;

    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\druid.properties"));
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //释放资源
    public static void close(ResultSet resultSet, Statement statement, Connection connection) {
        try {
            if (resultSet != null) {
                resultSet.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

        2.JavaBean类 : 

                对应于stus表中的id,name,sex,score四个字段,我们可以创建其对应的JavaBean类Stus类,并在其中建立四个字段,并给出它们的getter和setter方法,同时重写toString方法。
                Stus类代码如下 :

package dao_ex.domain;

/**
    stus表对应的JavaBean类
 */
public class Stus {
    private Integer id;
    private String name;
    private String sex;
    private Double score;

    public Stus() {
    }
    public Stus(Integer id,String name,String sex,Double score) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }
    @Override
    public String toString() {
        return "Stus{" +
                "id = " + id +
                ", name '= " + name + '\'' +
                ", sex = '" + sex + '\'' +
                ", score = " + score +
                '}';
    }
}

        3.BasicDAO类 / StusDAO类 : 

                因为XxxDAO类是在BasicDAO类的基础上实现的,因此我们要先开发BasicDAO。
                BasicDAO类代码如下 : (注意看注释!

package dao_ex.dao;

import connection_pool.druid.JDBCUtilsDruid;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
    (1)因为不确定将来会操作哪张表的DAO类,因此BasicDAO要使用泛型。
    (2)设置形参后,可以指定地传入一个要执行的SQL.
    (3)注意:实现不同功能DQL的不同方法内,调用query方法时,传入的ResultSetHandle接口的实现类不同。
 */
public class BasicDAO<T> {
    //定义一个QueryRunner属性
    private QueryRunner queryRunner = new QueryRunner();

    //1.执行DML的方法
    /**
     * @param sql : 要执行的SQL
     * @param parameters : 为SQL中的?进行赋值的可变参数
     * @return : 返回受影响的行数
     */
    public int update(String sql, Object... parameters) {
        //获取链接
        Connection connection = null;

        try {
            connection = JDBCUtilsDruid.getConnection();
            int affectedRows = queryRunner.update(connection,sql,parameters);
            return affectedRows;
        } catch (SQLException e) {
            throw new RuntimeException(e);  //编译异常转换为运行异常
        } finally {
        //释放资源
            JDBCUtilsDruid.close(null, null, connection);
        }
    }

    //2.执行“返回多条记录的”DQL的方法(同样使用泛型)
    /**
     * @param sql : 要执行的SQL
     * @param clazz : 根据传入的Class对象类型进行反射,
     *                以确定对应的JavaBean实例类型,即List集合中存放什么类型。
     * @param parameters : 为SQL中的?赋值的可变参数
     * @return : 返回一个ArrayList类对象(eg : 返回了一个存放Stus实例的ArrayList集合)
     */
    public List<T> queryMultiply(String sql, Class<T> clazz, Object... parameters) {
        //获取连接
        Connection connection = null;

        try {
            connection = JDBCUtilsDruid.getConnection();

            List<T> query = queryRunner.query(connection,sql,new BeanListHandler<T>(clazz),parameters);
            return query;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
        //释放资源
            JDBCUtilsDruid.close(null,null,connection);
        }
    }

    //3.执行“返回单条记录的”DQL的方法
    /**
     * @param sql : 同上
     * @param clazz : 同上,但只是作为单个实例来接收表中的一行数据(一条记录),没有集合
     * @param parameters : 同上
     * @return : 返回一个对应的JavaBean实例(该实例的属性保存了表中某一条记录的全部信息)
     */
    public T querySingle(String sql, Class<T> clazz, Object... parameters) {
        //获取连接
        Connection connection = null;
        try {
            connection = JDBCUtilsDruid.getConnection();
            return queryRunner.query(connection, sql, new BeanHandler<T>(clazz), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
        //释放资源
            JDBCUtilsDruid.close(null,null,connection);
        }
    }

    //4.执行“返回单行单列的”DQL的方法(即返回单值)
    /**
     * @param sql : 同上
     * @param parameters : 同上
     * @return : 由于仅返回单行单列,其实就是某一个具体的值,因此只需要使用Object类型做接受即可。
     */
    public Object queryScalar(String sql, Object... parameters) {
        //获取连接
        Connection connection = null;
        try {
            connection = JDBCUtilsDruid.getConnection();
            return queryRunner.query(connection,sql, new ScalarHandler(), parameters);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
        //释放资源
            JDBCUtilsDruid.close(null,null,connection);
        }
    }
}

                BasicDAO开发完毕后,我们可以创建负责stus表操作的StusDAO,并令其去继承BasicDAO。StusDAO代码如下 : 

package dao_ex.dao;

import dao_ex.domain.Stus;

/**
    StusDAO————负责管理stus表的DAO
 */
public class StusDAO extends BasicDAO<Stus> {
    /*
        StusDAO继承BasicDAO之后,便拥有了BasicDAO的全部非私有成员。
        若业务需求复杂,也可以在StusDAO下自定义特有方法。
     */
}

        4.测试类 : 

                在test包下创建用于测试DAO的TestDAO类,在TestDAO类中完成对StusDAO的访问。
                TestDAO类代码如下 : 

package dao_ex.test;

import dao_ex.dao.StusDAO;
import dao_ex.domain.Stus;
import org.testng.annotations.Test;

import java.util.List;

/**
    (1)关闭连接的操作封装在了BasicDAO的方法中;
    (2)关闭PreparedStatement和ResultSet的操作封装在了query方法中;
 */
public class TestDAO {
    @Test
    public void testStusDAO() {
    //1.测试“返回多条记录”的DQL的执行
        String sql1 = "SELECT * FROM stus " +
                        "WHERE `id` >= ?;";
        StusDAO stusDAO = new StusDAO();
        List<Stus> stusData = stusDAO.queryMultiply(sql1, Stus.class, 1);
        for (Stus stusDatum : stusData) {
            System.out.println(stusDatum);
        }
        System.out.println("------------------------------------------------");

    //2.测试“返回单条记录”的DQL的执行
        String sql2 = "SELECT * FROM stus " +
                        "WHERE `id` = ?;";
        Stus stus = stusDAO.querySingle(sql2, Stus.class, 1);
        System.out.println(stus);
        System.out.println("------------------------------------------------");

    //3.测试“返回单行单列(即返回单值)”的DQL的执行
        String sql3 = "SELECT name FROM stus " +
                        "WHERE `id` = ?;";
        Object o = stusDAO.queryScalar(sql3, 1);
        System.out.println(o);
        System.out.println("------------------------------------------------");

    //4.测试DML的执行(INSERT, DELETE, UPDATE)
        String sql4 = "INSERT INTO stus " +
                            "VALUES " +
                            "(NULL, ?, ?, ?);";
        String sql5 = "UPDATE stus " +
                            "SET `name` = ? " +
                            "WHERE `name` = ?;";
        String sql6 = "DELETE FROM stus " +
                            "WHERE `id` = ?;";
        int update1 = stusDAO.update(sql4, "Wood", "male", 399.0);
        int update2 = stusDAO.update(sql5, "Karry", "Cyan");
        int update3 = stusDAO.update(sql6, 4);

        System.out.println("插入操作的DML执行成功了吗?" + (update1 > 0 ? "yes!" : "no!"));
        System.out.println("修改操作的DML执行成功了吗?" + (update2 > 0 ? "yes!" : "no!"));
        System.out.println("删除操作的DML执行成功了吗?" + (update3 > 0 ? "yes!" : "no!"));
    }
}

                运行结果 : 

                我们再来查询一下stus表,看看DML操作有没有对stus造成影响,如下图所示 : 

                OK,没有问题。


五、总结

  • 🆗,以上就是JDBC系列博文第七节的全部内容了。
  • 总结一下,我们先是围绕“德鲁伊连接池 + 工具类”存在的弊端——即“SQL的优化”引入了DAO的概念;接着,又画出了BasicDAO的基本示意图;然后,进行了BasicDAO的基本设计,主要分为DAO, Domain, Utils, Test四部分;最后,我们以stus表为例,演示了BasicDAO的具体使用。大家一定要掌握BasicDAO的基本示意图,以及BasicDAO的设计逻辑。
  • 下一节内容——JDBC 望舒客栈项目,我们不见不散。感谢阅读!               

        System.out.println("END-----------------------------------------------------------------------------"); 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/649868.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文读懂物联网平台如何搞定80%以上的物联网项目

太卷了&#xff01;一套物联网平台就能搞定80%以上的项目&#xff1f;&#xff01; 在刚刚结束的AIRIOT4.0物联网平台发布会上&#xff0c;航天科技控股集团股份有限公司智慧物联事业部总经理田淼给出答案。 在主题演讲环节&#xff0c;田总以【80%的物联网项目服务商都会面临…

分组函数group by使用技巧

一、需求&#xff1a;获取销售版本组合 颜色&#xff08;属性名&#xff09; (黑色&#xff0c;白色…) 属性值集合 Datapublic static class ItemSaleAttrsVo{private Long attrId;private String attrName;//当前属性有多少种版本&#xff1a;黑色,白色,蓝色&#xff0c;这里…

奇妙敏捷之旅·青岛站,真的太酷啦!

高手的世界里&#xff0c;一块小小的积木&#xff0c;也能立刻感受敏捷的乐趣&#xff01; 2023奇妙敏捷之旅青岛站&#xff0c;希望将理论知识、实践应用融入互动过程&#xff0c;实现思维的交流、碰撞以及面对面的沟通。因此&#xff0c;大家看到的奇妙敏捷之旅的现场&#…

Linux:课后习题及其答案

第一章 Linux系统初步了解 Q1&#xff1a;简述Linux系统的应用领域 Linux服务器、嵌入式Linux系统、软件开发平台、桌面应用 Q2&#xff1a;Linux系统的特点 开放性、多用户、多任务、良好的用户界面、设备独立性、丰富的网络功能、可靠的系统安全、良好的可移植性 Q3&#…

oracle19c rac、nfs部署教程

本文基于19c进行部署&#xff0c;使用centos7.9,nfs做共享存储 一、首先进行网络规划和配置 该实验一共三台机器一台是nfs,另外两台做rac 1.每台机器至少2块网卡,网卡名字必须一样&#xff08;publicip和VIP使用的是同一张网卡&#xff0c;privilegeip是另外一张网卡改ip 仅做r…

C语言中断言库与断言函数assert()的用法总结

断言库与断言函数的相关使用总结&#xff01; 断言函数的使用断言函数及断言库总结#define NDEBUG 断言函数在实现常见算法中的使用 断言函数的使用 话不多说&#xff0c;先来个例子感受一番断言函数assert()到底有什么功能。 由上面例子可知&#xff0c;assert()函数中在z的…

快速开发框架:一招解锁企业流程化管理!

在流程化管理时代&#xff0c;什么样的平台可以帮助企业实现高效率发展&#xff1f;在信息化爆炸式发展的今天&#xff0c;有很多企业期望能通过专用的快速开发框架实现提质增效发展。目前&#xff0c;低代码技术平台是较为盛行的平台&#xff0c;拥有易操作、灵活、增效等优势…

AntDB数据库灾备方案介绍

AntDB灾备方案(双中心方案) AntDB数据库节点分布于两个机房&#xff0c;并使用 patroni etcd 组件进行HA管理&#xff0c;主节点故障时能自动切换。切换时优先选择同机房的同步slave节点选举为new master。 部署图中相关组件说明&#xff1a; ⚫patroni&#xff1a;通过参…

Revit中楼梯该怎么画?包教包会!

绘制楼梯是室内装修中必不可少的一部分&#xff0c;因为楼梯的安装不仅仅是为了连接不同楼层&#xff0c;更是装饰整个室内空间的重要组成部分。 在楼梯的绘制过程中&#xff0c;需要结合实际情况进行设计&#xff0c;包括楼层高度、楼梯数量、台阶宽度、扶手高度等因素&#…

AntDB数据冷热分离方案

数据冷热分离 数据的存在价值&#xff0c;在于其被使用的程度&#xff0c;即被查询或更新的频率。在不同的业务系统中&#xff0c;人们对处于不同时期的数据有着不同的使用需求。比如&#xff0c;在网络流量行为分析系统中&#xff0c;客户会对最近一个月公司发生的安全事件和…

树莓派系统卸载桌面环境及系统瘦身

在我们刚入门树莓派时使用都是带桌面环境的系统&#xff0c;系统自带了非常多的实用软件&#xff0c;在学习和使用了一段时间后&#xff0c;我发现已经完全用不到桌面环境了&#xff0c;平时几乎都是通过 ssh 远程工具进行交互&#xff0c;并以命令形式来对系统进行操作。 Ras…

PHP日期时间函数date() 详解

**date()函数是我们在php开发中常碰到并且会使用到的一个日期函数&#xff0c;下面我来给大家介绍date()函数的一些基本扮靓和方法&#xff0c;有需要了解的朋友可进入参考. 日期时间函数是PHP 的核心组成部分。无需安装即可使用这些函数。下面来详细说说date函数的具体用法&a…

Python(request)爬虫有多强大?

requests是Python中的一种HTTP客户端库&#xff0c;用于发送HTTP请求并获取服务器响应。使用requests库可以轻松地进行常见的HTTP操作&#xff0c;如GET、POST、PUT、DELETE等&#xff0c;支持HTTPS和HTTP连接以及摘要验证、基本认证等身份验证方式。 因此&#xff0c;Python的…

嵌入式QT 树形浏览 - navListView

目录 1、什么是树形浏览 2、示例 3、树形浏览设计依赖文件 4、navListView 使用过程 4.1 添加文件 4.2 QListView提升为树形浏览 4.3 树形浏览设计 4.4 树形浏览功能实现 4.5 界面切换 4.6 树形浏览实现界面切换 1、什么是树形浏览 像下图这种左侧带有可以点击切换…

“小白“如何理解数据库

目录 前言 1.什么是数据库 2.数据库的用处 2.1数据库与文件的对比 3.使用数据库 3.1建立数据库 3.2建立表 3.3存储数据 4.服务器&#xff0c;数据库&#xff0c;表关系 5.数据库的分类 5.1MySQL架构 5.2SQL分类 5.3存储引擎 5.3.1什么是存储引擎 5.3.2如何查看存…

Lucene(9):Lucene优化

1 解决大量磁盘IO config.setMaxBufferedDocs(100000); 控制写入一个新的segment前内存中保存的document的数目,设置较大的数目可以加快建索引速度。 数值越大索引速度越快, 但是会消耗更多的内存 indexWriter.forceMerge(文档数量); 设置N个文档合并为一个段 …

easyexcel多行不同的表头导出

easyexcel多行不同的表头导出&#xff08;多表格不同表头&#xff09; 一、效果展示 二、代码 /*** 导出月度报表数据信息*/ApiOperation(value "导出月度报表数据信息")Log(title "导出月度报表", businessType BusinessType.EXPORT)RequestMapping(…

linux 下 sqlserver 连接 与开发准备

最近需要再linux下开发一个服务链接SQLserver。但是没有相关经验&#xff0c;然后参考了网上的一些博客。有点心得记录如下。 主要参考了这个&#xff1a;linux连接到sqlserver命令行,Linux 下连接sqlserver (上)_廖俊涛的博客-CSDN博客linux连接到sqlserver命令行,Linux 下连…

【网络安全】这份近 200 页应急响应文档,不会还有人没看过吧?

前言 成为伟大黑客的关键在于做自己喜爱的事&#xff0c;要把一件事情做好&#xff0c;你必须热爱它。所以只要你能坚持对安全技术的热爱&#xff0c;到了这种程度&#xff0c;你就会做得更好。 本文档注重理论与实战结合&#xff0c;不仅提供关键源代码供读者快速实践&#…

UnityVR--UIManager--UI管理1

目录 前言 UI节点的结构 需要用到的组件 1. CanvasGroup 2. Button等控件的OnClick()监听 3. EventTrigger 建立UI工具集 1. 管理UI节点 2. UIBase包含了以下的工具 建立分面板的管理工具——以主面板MainUi为例 前言 UI在项目中的重要性不言而喻&#xff0c;并且UI控件的…