BaseDao封装JavaWeb的增删改查

news2024/12/25 14:42:26

目录

什么是BaseDao?

为什么需要BaseDao?

BaseDao的实现逻辑

什么是BaseDao?

Basedao 是一种基于数据访问对象(Data Access Object)模式的设计方法。它是一个用于处理数据库操作的基础类,负责封装数据库访问的底层操作,提供通用的数据库访问方法。

Basedao 主要用于简化数据库操作的代码开发,并提供一致性可维护性。它通常包含有对数据库的增加、删除、修改和查询等操作方法,以及一些基本的事务处理功能。

Basedao 可以通过继承来扩展具体的数据库操作方法,使得在具体的业务实现中可以更加专注于业务逻辑的实现,而不需要关注底层数据库的细节。

通过使用 Basedao,开发人员可以更加高效地进行数据库操作的开发,减少了重复的代码编写,提高了代码的可维护性可读性

为什么需要BaseDao?

BaseDao 的优点包括:

  1. 代码复用(共性抽取):BaseDao 封装了常见的数据库操作方法,可以被不同的业务逻辑类多次调用,避免了重复编写相同的数据库操作代码,提高了代码的复用性。
  2. 提高开发效率:BaseDao 提供了高级的数据库操作方法,开发人员可以直接调用这些方法,减少了重复的开发工作,提高了开发效率。
  3. 降低代码耦合度:BaseDao 封装了底层数据库的细节,通过调用 BaseDao 的方法,业务逻辑类可以和具体的数据库实现解耦,减少了业务逻辑类和数据库之间的直接依赖,提高了代码的可维护性和可扩展性。
  4. 提供事务支持:BaseDao 通常会提供事务处理的功能,可以保证数据库操作的一致性。开发人员可以通过 BaseDao 来处理事务,确保在一次操作中,要么全部成功,要么全部失败,避免了数据不一致的情况。

总的来说,BaseDao 通过封装数据库操作,提供高级的数据库操作方法,降低代码耦合度,提供事务支持等优点,可以提高开发效率,简化数据库操作,提高代码的可维护性和可扩展性。

BaseDao的实现逻辑

简单来说BaseDao就是对数据库底层操作业务进行共性抽取,下面就以学生信息为例~

1、在学生信息管理系统中,不论增删改查还是特殊业务都离不开每次访问数据库的配置驱动以及获取连接关闭连接,所以这两步是必然封装的

/**
 * 获取数据库连接对象
 */
public Connection getConnection() throws Exception {  //获取连接对象方法
    //加载配置文件
    Properties properties = new Properties();
    properties.load(Files.newInputStream(Paths.get("D:\\druid.properties")));

    //创建一个指定参数的数据库连接池
    DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
    return dataSource.getConnection();  //返回连接对象
}

因为当时博主访问数据库是采用Druid连接池,所以配置驱动就使用配置文件的方式,配置文件( .properties )代码如下:

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/student?useServerPrepStmts=true
username = root
password = root
initialSize = 10
maxActive = 30
maxWait = 1000

关闭连接方法封装代码如下:

/**
 * 关闭数据库连接
 * @param conn 数据库连接
 * @param stmt PreparedStatement预处理对象
 * @param rs 结果集
 */
public void closeAll(Connection conn, PreparedStatement stmt, ResultSet rs) {  //关闭连接方法
        // 若结果集对象(RresuleSet)不为空,则关闭
        if (rs != null) {
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 若预处理对象(PreparedStatement)不为空,则关闭
        if (stmt != null) {
            try {
                stmt.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        // 若数据库连接对象(Connection)不为空,则关闭
        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

2、通过第一步的调用能够返回一个连接对象,那么接下来就可以进行基本的增删改查操作, 增删改都属于对数据做更新,所以先做增删改

/**
 * 增、删、改的操作
 * @param preparedSql 预编译的 SQL 语句
 * @param param 参数的字符串数组
 * @return 影响的行数
 */
public int updateRow (String preparedSql, Object[] param) throws Exception {  //增删改操作的方法
    PreparedStatement preparedStatement = null;  //创建预处理对象并初始为空(通过预处理可以防止SQL恶意注入)
    int row = 0;  //初始受影响行数(当受影响行数大于0时,说明执行成功数据则更新)
    Connection connection = getConnection();  //调用getConnection()方法获取数据库连接
    try {
        preparedStatement = connection.prepareStatement(preparedSql);  //对sql形参预处理
        if (param != null) {  //形参数组(注入参数)不为空时,循环遍历对预处理sql注入参数
            for (int i = 0; i < param.length; i++) {
                //为预编译sql设置参数
                preparedStatement.setObject(i + 1, param[i]);
            }
        }
        row = preparedStatement.executeUpdate();  //执行sql语句并得到受影响的行数
        closeAll(connection,preparedStatement,null);  //调用closeAll()方法关闭资源,因为执行操作不含查询,则将结果集的实参传空
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return row;  //返回受影响行数
}

因为sql语句中需要的参数类型是不确定的,则用Object类型数组作为容器

3、至此就剩查询操作了,在封装前需要创建一个实体类,以至于后续每个实体类都可以代表为一行数据,代码如下:

public class Student {
    //初始字段
    private int id;
    private String name;
    private int age;

    public Student(int id, String name, int age) {  //构造函数
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {  //toString方法
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

实体对象有了,那么走你:

public List<Student> queryData (String sql, Object[] param) throws Exception {  //查询操作的方法
    PreparedStatement preparedStatement = null;  //创建预处理对象并初始为空(通过预处理可以防止SQL恶意注入)
    Connection connection = getConnection();  //调用getConnection()方法获取数据库连接
    preparedStatement = connection.prepareStatement(sql);  //调用getConnection()方法获取数据库连接
    if (param != null) {  //形参数组(注入参数)不为空时,循环遍历对预处理sql注入参数
        for (int i = 0; i < param.length; i++) {
            //为预编译sql设置参数
            preparedStatement.setObject(i + 1, param[i]);
        }
    }
    ResultSet resultSet = preparedStatement.executeQuery();  //得到返回的结果集
    List<Student> list = new ArrayList<Student>();  //创建List接口对象,泛型为指定Student对象类型,代表每个实体对象都是一行数据
    while (resultSet.next()) {  //循环遍历结果集,将每行数据封装成Student对象,并添加到List集合中
        Student student= new Student(resultSet.getInt(1), resultSet.getString(2), resultSet.getInt(3));  //获取结果集中的数据存入Student对象中
        list.add(student);  //将Student对象存入list接口中
    }
    closeAll(connection,preparedStatement,resultSet);  //调用closeAll()方法关闭数据库连接
    return list;  //返回List集合对象 
}

接下来创建一个测试类进行检查:

1、增删改测试

//增删改测试
BaseDao baseDao = new BaseDao();  //创建BaseDao对象
String sql = "insert into student(id,name,age) values(?,?,?)";  //定义预处理sql
Object[] list = {6, "老八", 35};  //将sql需要的参数存入至Object类型的数组
int add = baseDao.updateRow(sql, list); //调用增删改的方法并接收返回的受影响行数
if (add > 0) {  //受影响行数大于0则说明数据更新成功
    System.out.println("新增成功!受影响行数:" + add);
}
/* 删除、修改也是一样 */

控制台:

2、查询测试 

//查询测试
BaseDao baseDao = new BaseDao();  //创建BaseDao对象
String sql = "select * from student";  //定义预处理sql
List<Student> list = baseDao.queryData(sql, null);  //创建List接口,泛型为Student对象类型,用于存储查询返回的数据
for (Student student : list) {
    System.out.println(student.getId() + "\t\t" + student.getName() + "\t\t" + student.getAge());  //输出数据
}

控制台:

这么一来,JavaWeb中的每次增删改查都可以简明的实现,增删改查以外的特殊性业务功能可在BaseDao对象中具体实现方法

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

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

相关文章

大模型论文阅读:ADAPTIVE BUDGET ALLOCATION FOR PARAMETEREFFICIENT FINE-TUNING

大模型论文阅读:ADAPTIVE BUDGET ALLOCATION FOR PARAMETEREFFICIENT FINE-TUNING 论文链接:https://arxiv.org/pdf/2303.10512v1.pdf 当存在大量下游任务时,微调所有预训练模型的参数变得不可行。因此,为了以参数高效的方式学习预训练权重的增量更新,提出了许多微调方法,…

【Linux】进程状态(R运行状态、S睡眠状态、D磁盘休眠状态、T停止状态、X死亡状态)

目录 01.运行状态 02.睡眠状态 03.磁盘睡眠状态 04.停止状态 05.死亡状态 进程的状态会随着操作系统的调度和外部事件的发生而不断地发生转换。例如&#xff0c;一个新创建的进程经过初始化后会进入就绪态&#xff0c;等待被调度执行&#xff1b;当调度器分配处理器资源给…

AI+云平台|全闪云底座迎战

AI融万物之势席卷而来 人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI。它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。 行业特点 AI场景中80%以上是小文件&#xff0c;以非结构化数据为…

maya导入导出bvh 自动 脚本

目录 maya打开脚本编辑器 运行打开bvh脚本 maya导出bvh脚本 maya打开脚本编辑器 打开Maya软件,点击右下角 “脚本编辑器” 运行打开bvh脚本<

一款比 K8S 更好用的编排工具——Nomod 单机部署

上下文 最近公司需要调研类似 EMCHub 这样支持算力共享的服务。第一直觉是使用 K8S 或 K3S&#xff0c;作为 CNCF 孵化的顶级项目&#xff0c;同时也是当前云原生生态使用最广的编排系统。但是在学习 EMC Hub 源码过程中&#xff0c;偶然发现它是基于 Nomad 做的集群管理。 相…

如何清理释放群晖客户端缓存?

任正菲说&#xff1a;企业最大的浪费&#xff0c;是经验的浪费&#xff01; 而一个一个的经验&#xff0c;又都来自企业的每一个工作者。 因此当我们在工作过程中遇到一些问题时&#xff0c;我们就应该下意识的把解决问题的经验沉淀下来&#xff0c;从而可以与大家进行分享。…

耳目一新的滑块版登录注册界面~

又到了毕业季&#xff0c;大家做毕设的时候总会参考已有的案例&#xff0c;不过大多产品的样式非常单一雷同。本帖博主给大家分享一个比较别树一帜的登录界面&#xff0c;如下&#xff1a; 如果没有账号&#xff0c;点击“去注册”&#xff0c;则会产生如下的效果&#xff1a; …

django orm DateTimeField 6位小数精度问题

from django.db.backends.mysql.base import DatabaseWrapperDatabaseWrapper.data_types[DateTimeField] "datetime"意思就是重写源码里面的DateTimeField字段

如何在家中使用手机平板电脑 公司iStoreOS软路由实现远程桌面

文章目录 简介一、配置远程桌面公网地址二、家中使用永久固定地址 访问公司电脑**具体操作方法是&#xff1a;** 简介 软路由是PC的硬件加上路由系统来实现路由器的功能&#xff0c;也可以说是使用软件达成路由功能的路由器。 使用软路由控制局域网内计算机的好处&#xff1a…

C++ 控制语句(一)

一 顺序结构 程序的基本结构有三种&#xff1a; 顺序结构、分支结构、循环结构 大量的实际问题需要通过各种控制流程来解决。 1.1 顺序结构 1.2 简单语句和复合语句 二 循环 2.1 for循环 语句流程图 注意&#xff1a;使用for语句的灵活性 三 while语句 四 do while语句

线程 和 进程详解——以Java为例

一、概念 线程 线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中&#xff0c;是进程中的实际运作单位。 简单理解&#xff1a;应用软件中互相独立&#xff0c;可以同时运行的功能 进程 进程是程序的基本执行实体。 多线程中的两个概念&#xff1a;并发和并行…

鸿蒙OS开发实例:【工具类封装-emitter组件间通信】

import Emitter from ohos.events.emitter; import pasteboard from ohos.pasteboard; MyEmitterUtil 是一个针对 HarmonyOS 的事件驱动编程封装类&#xff0c;主要用于组件间的通信和数据传递。 使用要求&#xff1a; DevEco Studio 3.1.1 Release 或更高版本API 版本&…

vue3+threejs新手从零开发卡牌游戏(十六):初始化对方手牌

添加对方手牌区时注意位置调整&#xff0c;以及手牌应该是背面朝上&#xff0c;加个rotateX翻转即可&#xff0c;其他代码和p1.vue代码一致&#xff0c;game/hand/p2.vue代码如下&#xff1a; <template><div></div> </template><script setup lan…

C++:关键字(4)

在c中的关键字就是我们各个写的各种代码 这些就是关键字&#xff0c;这些东西是无法当参数的&#xff0c;比如在给变量名设置为int那就不行 这就是个错的 在写其他的参数时候&#xff0c;不可以使用关键词作为参数

Vue 与 React:前端框架对比分析

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

C语言程序编译与链接(拓宽视野的不二之选)

文章目录 翻译环境和运行环境翻译环境预处理编译汇编链接 运行环境 翻译环境和运行环境 1&#xff0c;在ANSI C的任何⼀种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执⾏的机器指 令&#xff08;⼆进制指令&#…

AI Agent(LLM Agent)入门解读

1. 什么是AI Agent&#xff1f; AI Agent可以理解为一个智能体&#xff0c;包括感知模块、规划决策模块和行动模块&#xff0c;类似于人类的五官、大脑和肢体。它能帮助人类处理复杂的任务&#xff0c;并能根据环境反馈进行学习和调整。 五官可以理解为感知模块&#xff0c;大…

2024年上半年数学建模竞赛一览表(附赠12场竞赛的优秀论文+格式要求)[电工、妈杯、数维、五一等12场]

为了帮助大家更好地备战今年上半年十二场数学建模竞赛&#xff0c;我们为大家收集到了这十二场相关竞赛的优秀论文以及格式要求&#xff0c;具体内容如下所示。 资料获取 在文末 文中资料来源 名称竞赛官方网站天府杯https://www.tfmssy.org.cn/认证杯http://www.tzmcm.cn/i…

中国土壤厚度空间分布数据

土壤层次分为覆盖层 林溶层 淀积层 母质层&#xff0c;其中在林溶层中的最上面那层就是我们通常说的土壤厚度在这一层中&#xff0c;这一层也被称为腐殖层&#xff0c;是肥力性质最好的一层&#xff0c;植物根系和微生物也集中在这一层。至于覆盖层在森林土壤中比较常见&#x…

零基础学python之高级编程(6)---Python中进程的Queue 和进程锁,以及进程池的创建 (包含详细注释代码)

Python中进程的Queue 和进程锁,以及进程池的创建 文章目录 Python中进程的Queue 和进程锁,以及进程池的创建前言一、进程间同步通信(Queue)二、进程锁&#xff08;Lock&#xff09;三、创建进程池Poorpool 类方法: End! 前言 大家好,上一篇文章,我们初步接触了进程的概念及其应…