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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 【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;
相关文章
|
11月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第17天】本文详细介绍了Java编程中Map的使用,涵盖Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的并发处理和性能优化技巧,适合初学者和进阶者学习。
515 3
|
6月前
|
SQL Java 中间件
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
在BeetISQL 2.13.8版本中,客户使用batch insert向yashandb表插入数据并尝试获取自动生成的sequence id时,出现类型转换异常。原因是beetlsql在prepareStatement时未指定返回列,导致yashan JDBC驱动返回rowid(字符串),与Java Bean中的数字类型tid不匹配。此问题影响业务流程,使无法正确获取sequence id。解决方法包括:1) 在batchInsert时不返回自动生成的sequence id;2) 升级至BeetISQL 3,其已修正该问题。
【YashanDB知识库】yasdb jdbc驱动集成BeetISQL中间件,业务(java)报autoAssignKey failure异常
|
Java 关系型数据库 数据库连接
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
JDBC:Java与数据库的“黄金搭档”,为何它如此重要?
105 8
|
6月前
|
SQL druid Oracle
【YashanDB知识库】yasdb jdbc驱动集成druid连接池,业务(java)日志中有token IDENTIFIER start异常
客户Java日志中出现异常,影响Druid的merge SQL功能(将SQL字面量替换为绑定变量以统计性能),但不影响正常业务流程。原因是Druid在merge SQL时传入null作为dbType,导致无法解析递归查询中的`start`关键字。
|
9月前
|
Java 数据库连接 数据库
springboot java.lang.ClassNotFoundException: dm.jdbc.driver.DmDriver应该如何解决
通过上述步骤,可以有效解决Spring Boot项目中遇到的 `java.lang.ClassNotFoundException: dm.jdbc.driver.DmDriver`问题。确保在项目中正确添加达梦数据库的JDBC驱动依赖,并在配置文件中正确配置数据源信息,是解决此问题的关键。通过这些方法,可以确保Spring Boot项目能够正确连接达梦数据库并正常运行。
1718 31
|
8月前
|
SQL Java 关系型数据库
使用 JDBC 实现 Java 数据库操作
JDBC(Java Database Connectivity)是 Java 提供的数据库访问技术,允许通过 SQL 语句与数据库交互。本文详细介绍了 JDBC 的使用方法,包括环境准备、编程步骤和完整示例。
769 7
|
8月前
|
SQL Java 数据库连接
【潜意识Java】Java中JDBC过时方法的替代方案以及JDBC为什么过时详细分析
本文介绍了JDBC中一些常见过时方法及其替代方案。
158 5
|
11月前
|
存储 安全 Java
从入门到精通:Java Map全攻略,一篇文章就够了!
【10月更文挑战第19天】本文介绍了Java编程中重要的数据结构——Map,通过问答形式讲解了Map的基本概念、创建、访问与修改、遍历方法、常用实现类(如HashMap、TreeMap、LinkedHashMap)及其特点,以及Map在多线程环境下的使用和性能优化技巧,适合初学者和进阶者学习。
390 4
|
SQL Java 数据库连接
JDBC之旅:从陌生到熟悉的Java数据库连接之路
JDBC之旅:从陌生到熟悉的Java数据库连接之路
80 9
|
SQL Java 关系型数据库
探索Java数据库连接的奥秘:JDBC技术全攻略
探索Java数据库连接的奥秘:JDBC技术全攻略
151 8