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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 【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;
    }
}


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
16天前
|
Java
颠覆认知:一向主张可扩展性的Java,为何要推出封闭类?
本文介绍了Java的Sealed Classes(封闭类)功能,探讨了为何Java在强调可扩展性的同时引入这一特性。文章基于JDK 17.0.5,详细解释了Sealed Classes的概念及其作用。通过对比final类和package-private类,阐述了封闭类在提高安全性和控制扩展性方面的优势。最后,通过具体示例展示了如何使用sealed关键字以及相关语法。了解这一新特性有助于我们更好地把握Java未来的发展趋势。
37 2
|
1天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其“不重复性”要求,彻底改变了处理唯一性数据的方式。HashSet基于哈希表实现,提供高效的元素操作;TreeSet则通过红黑树实现元素的自然排序,适合需要有序访问的场景。本文通过示例代码详细介绍了两者的特性和应用场景。
14 6
|
3天前
|
IDE Java 编译器
Java:如何确定编译和运行时类路径是否一致
类路径(Classpath)是JVM用于查找类文件的路径列表,对编译和运行Java程序至关重要。编译时通过`javac -classpath`指定,运行时通过`java -classpath`指定。IDE如Eclipse和IntelliJ IDEA也提供界面管理类路径。确保编译和运行时类路径一致,特别是外部库和项目内部类的路径设置。
|
2天前
|
安全 Java 测试技术
Java零基础-StringBuffer 类详解
【10月更文挑战第9天】Java零基础教学篇,手把手实践教学!
10 2
|
3天前
|
算法 Java 数据处理
从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其独特的“不重复性”要求,彻底改变了处理唯一性约束数据的方式。
【10月更文挑战第14天】从HashSet到TreeSet,Java集合框架中的Set接口及其实现类以其独特的“不重复性”要求,彻底改变了处理唯一性约束数据的方式。本文深入探讨Set的核心理念,并通过示例代码展示了HashSet和TreeSet的特点和应用场景。
9 2
|
3天前
|
存储 Java 索引
Java 中集合框架的常见接口和类
【10月更文挑战第13天】这些只是集合框架中的一部分常见接口和类,还有其他一些如 Queue、Deque 等接口以及相关的实现类。理解和掌握这些集合的特点和用法对于高效编程非常重要。
|
8天前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
21 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
10天前
|
存储 安全 Java
Java零基础-Java类详解
【10月更文挑战第2天】Java零基础教学篇,手把手实践教学!
13 2
|
13天前
|
Java 数据安全/隐私保护
java类和对象
java类和对象
19 5
|
13天前
|
Java 编译器 C语言
【一步一步了解Java系列】:类与对象的联系
【一步一步了解Java系列】:类与对象的联系
16 4