【Java Web】DAO模式及单例模式(含代码示例)
文章目录
- JDBC封装
- DAO模式
- 实体类
- DAO接口
- DAO实现类
- 数据源配置
- 基础DAO类
- 业务逻辑层
- 单例模式
- 饿汉式
- 懒汉式
JDBC封装
JDBC(Java Database Connectivity)封装是一种将 JDBC 的基本操作和常见的数据库访问逻辑封装成易于使用的工具类或框架的方法。这样做的目的是为了减少重复代码,提高代码的可读性和可维护性,并且简化数据库访问的过程。

隔离业务逻辑代码和数据访问代码
隔离不同数据库的实现
实现 JDBC 封装
- 将所有增删改查操作抽取成接口
- 定义实体类传输数据
- 将通用的操作(打开、关闭连接等)封装到工具类
- 数据库工具类BaseDao:增、删、改、查的通用方法
DAO模式
DAO(Data Access Object 数据存取对象)模式:将数据访问逻辑封装在单独的类中,使得业务逻辑层不需要关心具体的数据库操作细节。
- DAO接口:定义了对数据库进行访问的方法
- DAO实现类:实现了DAO接口,提供了具体的数据访问逻辑
- 实体类:表示数据库中的表或记录
- 数据源配置:配置数据库连接信息
- 业务逻辑层:使用DAO接口来处理业务逻辑,而不需要关心具体的数据库操作
DAO 起着转换器的作用,将数据在实体类和数据库记录之间进行转换

创建包
com.dao ----放接口文件 UserDao BaseDao(数据库工具类)com.dao.impl ----放接口实现类 UserDaoImpl
com.entity||pojo ----放实体类 User
实体类
代表数据库中的表或记录。每个实体类通常对应一个数据库表,并且包含与表字段相对应的属性。
public class SmbmsUser {private Integer id; // idprivate String userCode; // 用户编码private String userName; // 用户名称private String userPassword; // 用户密码private Integer gender; // 性别private Date birthday; // 出生日期private String phone; // 电话private String address; // 地址private Integer userRole; // 用户角色private Integer createdBy; // 创建者private Date creationDate; // 创建时间private Integer modifyBy; // 更新者private Date modifyDate; // 更新时间@Overridepublic String toString() {// 重写 toString() 方法...}// get&set 方法...
}
DAO接口
定义了对数据库进行访问的方法,通常是增删改查等基本操作。
公共接口
public interface PublicInterface<E> {/*** 根据ID获取单一实体。* @param id 实体的唯一标识* @return 返回Optional包装的实体,如果没有找到则返回空的Optional*/E findById(Integer id);/*** 获取所有实体。* @return 返回包含所有实体的列表*/List<E> findAll();/*** 保存或更新实体。* 如果实体已存在,则执行更新操作;如果不存在,则执行插入操作。* @param e 要保存或更新的实体* @return 操作后的实体*/int save(E e);/*** 删除指定ID的实体。* @param id 要删除的实体ID*/int deleteById(Integer id);
}
SmbmsUser 类接口
public interface SmbmsUserDao extends PublicInterface<SmbmsUser>{/*** 登录* @param name 用户名* @param pwd 密码* @return 用户对象*/public SmbmsUser login(String name, String pwd);
}
DAO实现类
实现了DAO接口,提供了具体的数据访问逻辑。这个类中包含了与数据库交互的具体代码。
public class SmbmsUserDaoImpl extends BaseDao implements SmbmsUserDao {@Overridepublic SmbmsUser login(String name, String pwd) {try{if(getConnection()){// 3.准备 SQL 语句String sql = "select id,userCode,userName,userPassword from smbms_user " +"where userCode = ? and userPassword = ?";ResultSet res = query(sql,name,pwd);// 6.处理 resultSet 结果集SmbmsUser smbmsUser = null;while(res.next()){smbmsUser = new SmbmsUser();smbmsUser.setId(res.getInt("id"));smbmsUser.setUserCode(res.getString("userCode"));smbmsUser.setUserName(res.getString("userName"));smbmsUser.setUserPassword(res.getString("userPassword"));}return smbmsUser;}} catch (Exception e) {e.printStackTrace();} finally {closeResources(); // 释放资源}return null;}@Overridepublic SmbmsUser findById(Integer id) {// ...}@Overridepublic List<SmbmsUser> findAll() {try{if(getConnection()){String sql = "select id,userCode,userName,userPassword from smbms_user";ResultSet res = query(sql);List<SmbmsUser> list = new ArrayList<>();while(res.next()){SmbmsUser smbmsUser = new SmbmsUser();smbmsUser.setId(res.getInt("id"));smbmsUser.setUserCode(res.getString("userCode"));smbmsUser.setUserName(res.getString("userName"));smbmsUser.setUserPassword(res.getString("userPassword"));list.add(smbmsUser);}return list;}} catch (Exception e) {e.printStackTrace();} finally {closeResources(); // 释放资源}return null;}@Overridepublic int save(SmbmsUser smbmsUser) {try {if (getConnection()) {String sql = "INSERT INTO smbms_user (userCode, userName, userPassword) " +"VALUES (?, ?, ?)";return update(sql, smbmsUser.getUserCode(), smbmsUser.getUserName(), smbmsUser.getUserPassword());}} catch (Exception e) {e.printStackTrace();} finally {closeResources(); // 释放资源}return 0;}@Overridepublic int deleteById(Integer id) {try {if (getConnection()) {return update("DELETE FROM smbms_user WHERE id = ?",id);}} catch (Exception e) {e.printStackTrace();} finally {closeResources(); // 释放资源}return 0;}
}
数据源配置
数据源配置通常在单独的文件中定义,例如 jdbc.properties 或 application.properties。
使用属性文件来管理数据库连接信息,需要创建 .properties文件存储配置,并在 Java 代码中读取这些属性。
# jdbc.properties 数据格式为 " 键 = 值 "
mysql.driver = com.mysql.cj.jdbc.Driver
mysql.url = jdbc:mysql://127.0.0.1:3306/smbms?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
mysql.username = root
mysql.userpwd = root
Java 中提供了 Properties 类来读取配置文件
/*** @Description: 读取JDBC.properties文件* 饿汉模式*/
public class ConfigManager {private static Properties properties = new Properties();// 只运行一次static {try {InputStream is = ConfigManager.class.getClassLoader().getResourceAsStream("jdbc.properties");// 将字节流转换为 properties 对象properties.load(is);System.out.println(properties.getProperty("mysql.driver"));} catch (IOException e) {throw new RuntimeException(e);}}public static String getString(String key){return properties.getProperty(key);}
}
基础DAO类
BaseDao 类封装了与数据库连接、执行查询和更新操作以及释放资源相关的通用功能。是一个基础的数据访问对象类。
提供了以下功能:
- 获取数据库连接。
- 执行查询操作并返回结果集。
- 执行增删改操作并返回受影响的行数。
- 释放数据库连接和
PreparedStatement对象。
public class BaseDao {protected Connection conn = null;protected PreparedStatement stat = null;/*** 获得 conn 对象* @return*/public boolean getConnection() {try {// 1.加载驱动Class.forName(ConfigManager.getString("mysql.driver"));// 2.创建 Connection 对象(通过 DriverManager)conn = DriverManager.getConnection(ConfigManager.getString("mysql.url"), ConfigManager.getString("mysql.username"), ConfigManager.getString("mysql.userpwd"));return true;} catch (Exception e) {e.printStackTrace();}return false;}/*** 查询*/public ResultSet query(String sql, Object... objs) throws Exception{// 4.赋值 PreparedStatement 对象(通过 Connection)stat = conn.prepareStatement(sql);// 5.执行 SQL 语句(通过 PreparedStatement)if(objs != null){for (int i = 0; i < objs.length; i++) {stat.setObject((i + 1),objs[i]);}}return stat.executeQuery();}/*** 增删改*/public int update(String sql,Object... objs) throws Exception{// 4.赋值 PreparedStatement 对象(通过 Connection)stat = conn.prepareStatement(sql);// 5.执行 SQL 语句(通过 PreparedStatement)if(objs != null){for (int i = 0; i < objs.length; i++) {stat.setObject((i + 1),objs[i]);}}return stat.executeUpdate();}/*** 释放资源*/public void closeResources(){// 7. 关闭资源try {if(stat != null) stat.close();if(conn != null) conn.close();} catch (SQLException e) {throw new RuntimeException(e);}}
}
业务逻辑层
使用DAO接口来处理业务逻辑,而不需要关心具体的数据库操作。
public class Main {public static void main(String[] args) {SmbmsUserDao smbmsUserDao = new SmbmsUserDaoImpl();// 测试登录SmbmsUser smbmsUser = smbmsUserDao.login("liming","0000000");if(smbmsUser != null){System.out.println("登录成功!"+smbmsUser.getUserName()+"欢迎您!");} else {System.out.println("账号或密码错误,登录失败!");}// 测试添加用户SmbmsUser newUser = new SmbmsUser();newUser.setUserCode("yier");newUser.setUserName("yier");newUser.setUserPassword("1234567");int addResult = smbmsUserDao.save(newUser);if (addResult > 0) {System.out.println("新用户添加成功!");} else {System.out.println("新用户添加失败!");}// 测试查询所有List<SmbmsUser> allUsers = smbmsUserDao.findAll();System.out.println(allUsers);// 测试根据 ID 查询// 假设我们要查询刚刚添加的用户SmbmsUser foundUser = smbmsUserDao.findById(newUser.getId());if (foundUser != null) {System.out.println("该用户为: " + foundUser);} else {System.out.println("该用户不存在");}// 测试删除用户// 假设我们要删除刚刚添加的用户int i = smbmsUserDao.deleteById(newUser.getId());if (i > 0) {System.out.println("用户删除成功!");} else {System.out.println("用户删除失败!");}}
}
单例模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁实例化然后销毁的对象,或者创建对象需要消耗大量资源的情况。单例模式可以确保系统中某个类的唯一性,避免由于多实例导致的数据不一致等问题。
- 单一实例:整个系统运行期间,只存在一个该类的实例。
- 私有构造器:防止外部通过
new关键字直接创建实例。 - 自行创建实例:在类内部自行创建唯一的实例。
- 静态私有对象:定义一个静态私有的成员变量来保存这个唯一的实例。
- 全局访问点:提供一个公共的方法,使外界能够获取到这个实例。
饿汉式
(Eager Initialization)
这种方式在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。这是线程安全的实现。
/*** @Description: 读取JDBC.properties文件* 饿汉模式*/
public class ConfigManager {private static Properties properties = new Properties();// 只运行一次static {try {InputStream is = ConfigManager.class.getClassLoader().getResourceAsStream("jdbc.properties");// 将字节流转换为 properties 对象properties.load(is);System.out.println(properties.getProperty("mysql.driver"));} catch (IOException e) {throw new RuntimeException(e);}}public static String getString(String key){return properties.getProperty(key);}
}
懒汉式
(Lazy Initialization, 线程不安全)
这种方式延迟了实例的创建,直到第一次使用时才进行初始化。但是这种方法不是线程安全的,在多线程环境下可能会产生多个实例,因此需要用到 synchronized 关键字。
/*** @Description: 读取JDBC.properties文件* 懒汉模式*/
public class ConfigManager1 {private static ConfigManager1 configManager1 = null;private static Properties properties = new Properties();public ConfigManager1(){try {InputStream is = ConfigManager1.class.getClassLoader().getResourceAsStream("jdbc.properties");// 将字节流转换为 properties 对象properties.load(is);System.out.println(properties.getProperty("mysql.driver"));} catch (IOException e) {throw new RuntimeException(e);}}public synchronized static ConfigManager1 getConfigManager1(){if(configManager1 == null){configManager1 = new ConfigManager1();}return configManager1;}public String getString(String key){return properties.getProperty(key);}
}public class Singleton {private static Singleton instance;// 私有构造函数private Singleton() {}// 提供一个全局访问点public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
在整个程序运行期间,有且仅有一个实例。若违背这一点,所设计的类就不是单例类。
| 单例模式 | 懒汉模式 | 饿汉模式 |
|---|---|---|
| 概念 | 在类加载时不创建实例,采用延迟加载的方式,在运行调用时创建实例 | 在类加载的时候就完成初始化 |
| 特点 | 类加载速度快,但是运行时获取对象的速度较慢(时间换空间) | 类加载较慢,但获取对象速度快(空间换时间) |
| 延迟加载(lazy loading) | 具备 | 不具备 |
| 线程安全 | 线程不安全 | 线程安全 |
相关文章:
【Java Web】DAO模式及单例模式(含代码示例)
文章目录 JDBC封装DAO模式实体类DAO接口DAO实现类数据源配置基础DAO类业务逻辑层 单例模式饿汉式懒汉式 JDBC封装 JDBC(Java Database Connectivity)封装是一种将 JDBC 的基本操作和常见的数据库访问逻辑封装成易于使用的工具类或框架的方法。这样做的目…...
深入探讨SEO分析技巧助力网站流量提升
内容概要 在当前的数字化时代,SEO分析的重要性不言而喻。它是提升网站流量的关键工具,帮助站长有效地优化网站内容和结构。通过系统的SEO分析,站长可以掌握用户搜索行为和需求,从而制定出更具针对性的内容策略。例如,…...
Chrome 130 版本开发者工具(DevTools)更新内容
Chrome 130 版本开发者工具(DevTools)更新内容 一、网络(Network)面板更新 1. 重新定义网络过滤器 网络面板获新增了一些过滤条件,这些过滤条件是根据反馈重新设计的,特定于类型的过滤条件保持不变&…...
深度学习基础知识-残差网络ResNet
目录 一、ResNet 的核心思想:残差学习(Residual Learning) 二、ResNet 的基本原理 三、ResNet 网络结构 1. 残差块(Residual Block) ResNet 的跳跃连接类型 2. 网络结构图示 四、ResNet 的特点和优势 五、ResNe…...
Linux云计算个人学习总结(二)
高级文件系统 一、RSYNC概述 1、作用:快速的文件复制工具(支持本地和远程),以及删除、查看等基本功能。 2、特点:支持实时(inotify、sersync)的增量备份工具3、模式:检查模式&#…...
Java入门(7)--网络编程
Java网络编程:构建网络应用的基石 🌐 🎯 掌握Java网络编程,打造强大的网络应用! 在上一篇文章中,我们探讨了Java的I/O操作和反射机制。今天,让我们深入学习Java网络编程,了解如何构建…...
[思考记录]思维局限,以为懂了
最近配合整理一些内容,找到较早期的某些产品设计资料在翻阅回顾。在这次回顾过程中,发现当时自己的理解存在很多局限。 以资源体系的设计为例,那时自认为已经“懂了”,对相关的概念、作用关系、组成及实现等都有一定的了解&#x…...
力扣题目解析--最长公共前缀
题目 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 ""。 示例 1: 输入:strs ["flower","flow","flight"] 输出:"fl"示例 2ÿ…...
不画饼——研究生学习和赚钱的平衡点
在现代社会中,年轻人面临着学习和赚钱之间的矛盾。尤其是在经济压力日益增大的背景下,如何在这两者之间找到合适的平衡点,成为了许多学生和职场新人面临的重要问题。本文将探讨在何种情况下应该听从老师的建议,专注于学习…...
华为实时视频使用FLV播放RTSP流
import flvjs from ‘flv.js’; 安装flv <video style"width:100%;height:100%;" ref"videoHWRef" ></video>// src 华为rtsp流 rtsp://admin:Huaweivideo10.10.8.151:554/xxx/trackID1// url 需要后端提供视频源地址playVideo() {if (fl…...
JAVA设计模式之【建造者模式】
1 定义 建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 2 类图 产品类(Product):表示被创建的复杂…...
【jvm】为什么Xms和Xmx的值通常设置为相同的?
目录 1. 说明2. 避免性能开销3. 提升稳定性4. 简化配置5. 优化垃圾收集6. 获取参数6.1 代码示例6.2 结果示例 1. 说明 1.-Xms 和 -Xmx 参数分别用于设置堆内存的初始大小(最小值)和最大大小。2.在开发环境中,开发人员可能希望快速启动应用程…...
windows查看net网络监听端口命令和工具(ipconfig、netstat、tasklist、TCPView)
文章目录 使用命令提示符(CMD)查看网络连接和配置使用 netstat 命令查看监听端口查看特定的端口查看TCP监听端口tasklist查看对应进程ID的程序Get-NetTCPConnection 命令使用 TCPView工具使用命令提示符(CMD) 查看网络连接和配置 ipconfig :显示所有网络 适配器的当前 TC…...
JAVA-数据结构- 二叉搜索树
1.搜索树 前面我们已经使用C语言学习完了二叉树,懂得了一些二叉树的基本性质已经实现方法 https://mp.csdn.net/mp_blog/creation/editor/139572374,本文我们来一起进行二叉树的衍生-二叉搜索树 1.1 概念 二叉搜索树又称二叉排序树,它或者是…...
深入研究 RAG 流程中的关键组件
我们已经看到了整个RAG流程,并获得了第一手的实践经验,您可能会对RAG流程中一些组件的使用和目的存在很多疑惑,比如RunnablePassthrough。在本节中,我们将进一步了解这些关键组件。 RAG的核心模型思想是将一个复杂的任务分解为多…...
新手如何学习python并快速成为高手
英雄Python入门到精通链接:https://pan.quark.cn/s/57162ec366a9 学习Python作为新手,有以下几个步骤: 学习基本概念和语法:首先,你需要学习Python的基本概念和语法。可以通过在线教程、书籍或者视频教程来学习。了解…...
Linux历史命令history增加执行时间显示
Centos系统默认历史命令显示如下 为了更好的溯源,获取执行命令的准确时间,需要增加一些配置 设置环境变量 vim /etc/profile 在最下面添加以下环境配置 export HISTTIMEFORMAT"%Y-%m-%d %H:%M:%S " 立即刷新该环境变量 source /etc/pro…...
从 vue 源码看问题 — 你知道 Hook Event 吗?
前言 在之前的几篇文章中,都有提到 vue 中调用生命周期钩子时是通过 callHook() 方法进行调用的,比如在初始化篇章中调用 beforeCreate 和 created 生命周期钩子方式如下: 那么接下来一起来了解下到底什么是 Hook Event ? Hook Event 是什…...
信息安全工程师(68)可信计算技术与应用
前言 可信计算技术是一种计算机安全体系结构,旨在提高计算机系统在面临各种攻击和威胁时的安全性和保密性。 一、可信计算技术的定义与原理 可信计算技术通过包括硬件加密、受限访问以及计算机系统本身的完整性验证等技术手段,确保计算机系统在各种攻击和…...
每日OJ题_牛客_相差不超过k的最多数_滑动窗口_C++_Java
目录 牛客_相差不超过k的最多数_滑动窗口 题目解析 C代码 Java代码 牛客_相差不超过k的最多数_滑动窗口 相差不超过k的最多数_牛客题霸_牛客网 (nowcoder.com) 描述: 给定一个数组,选择一些数,要求选择的数中任意两数差的绝对值不超过 …...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)
上一章用到了V2 的概念,其实 Fiori当中还有 V4,咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务),代理中间件(ui5-middleware-simpleproxy)-CSDN博客…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...
【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
WebRTC从入门到实践 - 零基础教程
WebRTC从入门到实践 - 零基础教程 目录 WebRTC简介 基础概念 工作原理 开发环境搭建 基础实践 三个实战案例 常见问题解答 1. WebRTC简介 1.1 什么是WebRTC? WebRTC(Web Real-Time Communication)是一个支持网页浏览器进行实时语音…...
