【JavaWeb】一篇文章复习JDBC、DAO及相关实现类(一)

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
RDS AI 助手,专业版
简介: 【JavaWeb】一篇文章复习JDBC、DAO及相关实现类(一)

一、JDBC实现数据库的连接


1、IEDA引入JDBC.jar包


在工程目录下,创建一个lib文件夹,将jar包复制到该文件夹下,然后如图进行引入。


3ad8a5e6b7e15b319df0692f9ae47ce6_image-20220909113810598.png


2、连接方式


首先我们先写一个配置文件jdbc.properties


使用配置文件的好处:


实现了代码和数据的分离,如果需要修改配置信息,直接在配置文件中修改,不需要深入代码

如果修改了 配置信息,省去重新编译的过程。


user=root
password=sm1208
url=jdbc:mysql://localhost:3306/javaweb?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
driverClass=com.mysql.cj.jdbc.Driver


package com.sun.jdbc;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
 * @author JumperSun
 * @date 2022-09-08-19:57
 */
public class ConnectionTest {
    // 非读取配置文件方式
    @Test
    public void testConnection1(){
        try {
            // 1.数据库连接的4个基本要素
            String url = "jdbc:mysql://localhost:3306/javaweb?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true";
            String driverName = "com.mysql.cj.jdbc.Driver";
            String user = "root";
            String password = "sm1208";
            // 2.加载驱动(实例化Driver 注册驱动)
            Class.forName(driverName);
            // 3.获取连接
            Connection conn = DriverManager.getConnection(url, user, password);
            System.out.println(conn);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
  // 读取配置文件方式
    @Test
    public void testConnection2() throws Exception {
        // 1.加载配置文件
        InputStream is = ConnectionTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        // 2.读取配置信息
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");
        // 3.加载驱动
        Class.forName(driverClass);
        // 4.获取连接
        Connection conn = DriverManager.getConnection(url, user, password);
        System.out.println(conn);
    }
}



3、JDBCUtils工具类封装数据库连接和关闭操作


package com.sun.jdbc;
import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**
 * @author JumperSun
 * @date 2022-09-08-20:53
 * 封装的JDBC工具类
 */
public class JDBCUtils {
    public static Connection getConnection() throws Exception {
        // 1.读取配置文件的信息
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");
        // 2.加载驱动
        Class.forName(driverClass);
        // 3.返回获取连接
        return DriverManager.getConnection(url, user, password);
    }
    public static void closeResources(Connection conn, PreparedStatement ps) {
        try {
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    public static void closeResources(Connection conn, PreparedStatement ps, ResultSet rs) {
        try {
            if (rs != null) {
                rs.close();
            }
            if (ps != null) {
                ps.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}


二、使用PreparedStatement实现CRUD操作


PreparedStatement是什么?


PreparedStatement用来执行SQL查询语句的API之一,数据库连接被用于向数据库服务器发送命令和 SQL 语句,并接受数据库服务器返回的结果。

数据库操作对象都有哪些?


Statement:用于执行静态 SQL 语句并返回它所生成结果的对象。

PrepatedStatement:SQL 语句被预编译并存储在此对象中,可以使用此对象多次高效地执行该语句。

CallableStatement:用于执行 SQL 存储过程

为什么使用PreparedStatement?


使用Statement操作数据表存在弊端

存在拼串操作、繁琐

存在SQL注入问题

PreparedStatement表示一条预编译过的 SQL 语句

能最大可能提高性能

能最大可能提高性能:

综上:


b9f21dd938953a814f92f62caf197734_image-20220909114829848.png


1、PreparedStatement实现增、删、改操作


// 通用的增、删、改操作(体现一:增、删、改 体现二:针对不同的表)
public boolean update(String sql,Object ...args) {
    Connection conn = null;
    PreparedStatement ps = null;
    boolean flag = false;
    try {
        // 1.获取数据库的连接
        conn = com.sun.jdbc.JDBCUtils.getConnection();
        // 2.获取PreparedStatement实例
        ps = conn.prepareStatement(sql);
        // 3.填充占位符
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i+1,args[i]);
        }
        // 4.执行sql语句
        flag = ps.execute();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 5.关闭资源
        JDBCUtils.closeResources(conn,ps);
        return flag;
    }
}


2、PreparedStatement实现查询操作


// 通用的针对于不同表的查询:返回一个对象
public <T> T getBean(Class<T> clazz,String sql,Object ...args) {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        // 1.获取数据库连接
        conn = JDBCUtils.getConnection();
        // 2.预编译sql语句,得到PrepareStatement对象
        ps = conn.prepareStatement(sql);
        // 3.填充占位符
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i+1,args[i]);
        }
        // 4.执行executeQuery(),得到结果:ResultSet
        rs = ps.executeQuery();
        // 5.得到结果集的元数据:ResultSetMetaData
        ResultSetMetaData rsmd = rs.getMetaData();
        // 6.通过ResultSetMetaData得到columnCount,columLable;通过ResultSet得到列值
        int columnCount = rsmd.getColumnCount();
        if (rs.next()) {
            // 通过反射,创建指定类的对象,获取指定的属性并赋值
            T t = clazz.newInstance();
            for (int i = 0; i < columnCount; i++) { // 遍历每一个列
                // 获取列值
                Object columnval = rs.getObject(i + 1);
                // 获取列的别名:列的别名,使用类的属性名充当
                String columnLabel = rsmd.getColumnLabel((Integer) columnval);
                // 使用反射,给对象的相应属性赋值
                Field field = clazz.getDeclaredField(columnLabel);
                field.setAccessible(true);
                field.set(t,columnval);
            }
            return t;
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 7.关闭资源
        JDBCUtils.closeResources(conn,ps,rs);
    }
    return null;
}



// 通用的针对于不同表的查询:返回对象集合
public <T> List<T> getBeanList(Class<T> clazz, String sql, Object ...args) {
    Connection conn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
        // 1.获取数据库连接
        conn = com.sun.jdbc.JDBCUtils.getConnection();
        // 2.预编译sql语句,得到PrepareStatement对象
        ps = conn.prepareStatement(sql);
        // 3.填充占位符
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i+1,args[i]);
        }
        // 4.执行executeQuery(),得到结果:ResultSet
        rs = ps.executeQuery();
        // 5.得到结果集的元数据:ResultSetMetaData
        ResultSetMetaData rsmd = rs.getMetaData();
        // 6.通过ResultSetMetaData得到columnCount,columLable;通过ResultSet得到列值
        int columnCount = rsmd.getColumnCount();
        // 创建集合对象
        ArrayList<T> list = new ArrayList<>();
        while (rs.next()) {
            T t = clazz.newInstance();
            // 处理结果集一行数据中的每一列:给
            for (int i = 0; i < columnCount; i++) {
                // 获取列值
                Object columnval = rs.getObject(i + 1);
                // 获取列的别名:列的别名,使用类的属性名充当
                String columnLabel = rsmd.getColumnLabel((Integer) columnval);
                // 使用反射,给对象的相应属性赋值
                Field field = clazz.getDeclaredField(columnLabel);
                field.setAccessible(true);
                field.set(t,columnval);
            }
            list.add(t);
        }
        return list;
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        // 7.关闭资源
        JDBCUtils.closeResources(conn,ps,rs);
    }
    return null;
}



3、ResultSet与ResultSetMetaData


我们进行查询操作需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象。


ResultSet

ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现

ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。

ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象 的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。 相当于Iterator对象的 hasNext() 和 next() 方法的结合体。

当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值。

例如: getInt(1), getString(“name”)

注意:Java与数据库交互涉及到的相关Java API中的索引都从1开始。

ResultSet 接口的常用方法: boolean next()、getString()

ResultSetMetaData

可用于获取关于 ResultSet 对象中列的类型和属性信息的对象


ResultSetMetaData meta = rs.getMetaData();


getColumnName(int column):获取指定列的名称


getColumnLabel(int column):获取指定列的别名


getColumnCount():返回当前 ResultSet 对象中的列数。


getColumnTypeName(int column):检索指定列的数据库特定的类型名称。


getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。


isNullable(int column):指示指定列中的值是否可以为 null。


isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是只读的。


如何获取 ResultSetMetaData: 调用 ResultSet 的 getMetaData() 方法即可


获取 ResultSet 中有多少列:调用 ResultSetMetaData 的 getColumnCount() 方法


获取 ResultSet 每一列的列的别名是什么:调用 ResultSetMetaData 的getColumnLabel() 方法


4、ORM思想(object relational mapping)


一个数据表对应一个java类

表中的一条记录对应java类的一个对象

表中的一个字段对应java类的一个属性


162a134bc8ef197d5aa37b6d2b4a45c3_image-20220909100808922.png


5、资源的释放


释放ResultSet, Statement,Connection。

数据库连接(Connection)是非常稀有的资源,用完后必须马上释放,如果Connection不能及时正确的关闭将 导致系统宕机。Connection的使用原则是尽量晚创建,尽量早的释放。

可以在finally中关闭,保证及时其他代码出现异常,资源也一定能被关闭。

6、PsUtils封装PrepareStatement操作

package com.sun.util;



import com.sun.util.JDBCUtils;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
/**
 * @author JumperSun
 * @date 2022-09-08-20:29
 */
public class PsUtils {
    // 通用的增、删、改操作(体现一:增、删、改 体现二:针对不同的表)
    public boolean update(String sql,Object ...args) {
        Connection conn = null;
        PreparedStatement ps = null;
        boolean flag = false;
        try {
            // 1.获取数据库的连接
            conn = com.sun.jdbc.JDBCUtils.getConnection();
            // 2.获取PreparedStatement实例
            ps = conn.prepareStatement(sql);
            // 3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            // 4.执行sql语句
            flag = ps.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 5.关闭资源
           JDBCUtils.closeResources(conn,ps);
           return flag;
        }
    }
    // 通用的针对于不同表的查询:返回一个对象
    public <T> T getBean(Class<T> clazz,String sql,Object ...args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1.获取数据库连接
            conn = com.sun.jdbc.JDBCUtils.getConnection();
            // 2.预编译sql语句,得到PrepareStatement对象
            ps = conn.prepareStatement(sql);
            // 3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            // 4.执行executeQuery(),得到结果:ResultSet
            rs = ps.executeQuery();
            // 5.得到结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            // 6.通过ResultSetMetaData得到columnCount,columLable;通过ResultSet得到列值
            int columnCount = rsmd.getColumnCount();
            if (rs.next()) {
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) { // 遍历每一个列
                    // 获取列值
                    Object columnval = rs.getObject(i + 1);
                    // 获取列的别名:列的别名,使用类的属性名充当
                    String columnLabel = rsmd.getColumnLabel((Integer) columnval);
                    // 使用反射,给对象的相应属性赋值
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t,columnval);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 7.关闭资源
            JDBCUtils.closeResources(conn,ps,rs);
        }
        return null;
    }
    // 通用的针对于不同表的查询:返回对象集合
    public <T> List<T> getBeanList(Class<T> clazz, String sql, Object ...args) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            // 1.获取数据库连接
            conn = com.sun.jdbc.JDBCUtils.getConnection();
            // 2.预编译sql语句,得到PrepareStatement对象
            ps = conn.prepareStatement(sql);
            // 3.填充占位符
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            // 4.执行executeQuery(),得到结果:ResultSet
            rs = ps.executeQuery();
            // 5.得到结果集的元数据:ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            // 6.通过ResultSetMetaData得到columnCount,columLable;通过ResultSet得到列值
            int columnCount = rsmd.getColumnCount();
            // 创建集合对象
            ArrayList<T> list = new ArrayList<>();
            while (rs.next()) {
                T t = clazz.newInstance();
                // 处理结果集一行数据中的每一列:给
                for (int i = 0; i < columnCount; i++) {
                    // 获取列值
                    Object columnval = rs.getObject(i + 1);
                    // 获取列的别名:列的别名,使用类的属性名充当
                    String columnLabel = rsmd.getColumnLabel((Integer) columnval);
                    // 使用反射,给对象的相应属性赋值
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t,columnval);
                }
                list.add(t);
            }
            return list;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 7.关闭资源
            JDBCUtils.closeResources(conn,ps,rs);
        }
        return null;
    }
}


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
8月前
|
Java 编译器 API
Java 密封类:精细化控制继承关系
Java 密封类:精细化控制继承关系
431 83
|
6月前
|
安全 Java 数据建模
Java记录类:简化数据载体的新选择
Java记录类:简化数据载体的新选择
346 101
|
6月前
|
安全 Java 开发者
Java记录类:简化数据载体的新方式
Java记录类:简化数据载体的新方式
337 100
|
9月前
|
IDE Java 数据挖掘
Java 基础类从入门到精通实操指南
这份指南专注于**Java 17+**的新特性和基础类库的现代化用法,涵盖开发环境配置、数据类型增强(如文本块)、字符串与集合处理进阶、异常改进(如密封类)、IO操作及实战案例。通过具体代码示例,如CSV数据分析工具,帮助开发者掌握高效编程技巧。同时提供性能优化建议和常用第三方库推荐,适合从入门到精通的Java学习者。资源链接:[点此下载](https://pan.quark.cn/s/14fcf913bae6)。
401 37
|
7月前
|
安全 IDE Java
Java记录类型(Record):简化数据载体类
Java记录类型(Record):简化数据载体类
564 143
|
5月前
|
存储 Java 索引
用Java语言实现一个自定义的ArrayList类
自定义MyArrayList类模拟Java ArrayList核心功能,支持泛型、动态扩容(1.5倍)、增删改查及越界检查,底层用Object数组实现,适合学习动态数组原理。
225 4
|
5月前
|
IDE JavaScript Java
在Java 11中,如何处理被弃用的类或接口?
在Java 11中,如何处理被弃用的类或接口?
293 5
|
5月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
370 5
|
5月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
277 1
|
5月前
|
Java Go 开发工具
【Java】(8)正则表达式的使用与常用类分享
正则表达式定义了字符串的模式。正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。
401 1