JDBC(powernode CD2206)详尽版(内含教学视频、源代码、SQL文件)

导读:本篇文章讲解 JDBC(powernode CD2206)详尽版(内含教学视频、源代码、SQL文件),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

JDBC(powernode CD2206)详尽版(内含教学视频、源代码、SQL文件)

包含:教学视频、源代码(与博客同步)、SQL文件

下载链接地址: https://download.csdn.net/download/weixin_46411355/87399872

目录

一、介绍

JDBC:(Java DataBase Connectivity): java 数据库连接。 也就是java操作数据库。

在这里插入图片描述

二、JDBC常用的接口和类

JDBC常用的接口和类位于java.sql包下。

2.1 Driver接口

每个驱动程序类必须实现的接口。

每个驱动程序都应该提供一个实现 Driver 接口的类。

2.2 DriverManager类

管理一组 JDBC 驱动程序的基本服务。

2.3 Connection接口

与特定数据库的连接(会话)。在连接上下文中执行 SQL 语句并返回结果。

2.4 Statement接口

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

静态 SQL 语句: 就是不需要动态拼接参数的SQL语句。

2.5 PreparedStatement接口

表示预编译的 SQL 语句的对象。

2.6 ResultSet接口

表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。

ResultSet 对象具有指向其当前数据行的光标。最初,光标被置于第一行之前。next 方法将光标移动到下一行;因为该方法在 ResultSet 对象没有下一行时返回 false,所以可以在 while 循环中使用它来迭代结果集。

2.7 DataSource接口

该工厂用于提供到此 DataSource 对象所表示的物理数据源的连接。作为 DriverManager 工具的替代项,DataSource 对象是获取连接的首选方法。

DataSource 接口由驱动程序供应商实现。共有三种类型的实现:

  1. 基本实现 – 生成标准的 Connection 对象
  2. 连接池实现 – 生成自动参与连接池的 Connection 对象。此实现与中间层连接池管理器一起使用。
  3. 分布式事务实现 – 生成一个 Connection 对象,该对象可用于分布式事务,大多数情况下总是参与连接池。此实现与中间层事务管理器一起使用,大多数情况下总是与连接池管理器一起使用。

三、JDBC操作数据库的步骤

在这里插入图片描述
JDBC操作数据库的步骤:

  1. 加载驱动
  2. 创建连接
  3. 获取Statement语句对象
  4. 执行SQL语句
  5. 解析结果集ResultSet(查询语句)
  6. 释放资源

四、编写第一个JDBC程序

数据库sql
student.sql

/*
 Navicat Premium Data Transfer

 Source Server         : MySQL80_3306
 Source Server Type    : MySQL
 Source Server Version : 80030
 Source Host           : localhost:3306
 Source Schema         : powernode_jdbc

 Target Server Type    : MySQL
 Target Server Version : 80030
 File Encoding         : 65001

 Date: 27/01/2023 19:02:32
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `age` int NULL DEFAULT NULL,
  `sex` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES (6, '小明3', 4, '女', '武汉3');
INSERT INTO `student` VALUES (7, '小明4', 51, '女', '武汉4');
INSERT INTO `student` VALUES (8, '小明5', 39, '女', '武汉5');
INSERT INTO `student` VALUES (9, '小明6', 38, '女', '武汉6');
INSERT INTO `student` VALUES (10, '小明7', 67, '男', '武汉7');
INSERT INTO `student` VALUES (11, '小明8', 73, '女', '武汉8');
INSERT INTO `student` VALUES (12, '小明9', 64, '男', '武汉9');
INSERT INTO `student` VALUES (13, '小明10', 74, '男', '武汉10');
INSERT INTO `student` VALUES (14, '小明11', 56, '男', '武汉11');
INSERT INTO `student` VALUES (15, '小明12', 50, '男', '武汉12');
INSERT INTO `student` VALUES (16, '小明13', 68, '男', '武汉13');
INSERT INTO `student` VALUES (17, '小明14', 47, '男', '武汉14');
INSERT INTO `student` VALUES (18, '小明15', 96, '女', '武汉15');
INSERT INTO `student` VALUES (19, '小明16', 86, '女', '武汉16');
INSERT INTO `student` VALUES (20, '小明17', 73, '女', '武汉17');
INSERT INTO `student` VALUES (21, '小明18', 31, '女', '武汉18');
INSERT INTO `student` VALUES (22, '小明19', 61, '女', '武汉19');
INSERT INTO `student` VALUES (23, '小明20', 30, '女', '武汉20');

SET FOREIGN_KEY_CHECKS = 1;

添加驱动jar包 mysql-connector-j-8.0.32.jar

代码

- package _01编写第一个JDBC程序;

import com.mysql.cj.jdbc.Driver;
import java.sql.*;
/**
 * 编写第一个JDBC程序
 */
public class LoadDriverByThreeWays {
    public static void main(String[] args) {
        ResultSet resultSet = null;
        Statement statement = null;
        Connection connection = null;
        try {
            // 1. 加载驱动


            //第一种方式
//            DriverManager.registerDriver(new Driver());
            //第二种方式
//            new Driver();
            //第三种方式
//            Class.forName("com.mysql.cj.jdbc.Driver");
            //第四种方式:直接不写
            /*
             *  JDBC 4.0 Drivers 必须包括 META-INF/services/java.sql.Driver 文件。此文件包含 java.sql.Driver 的 JDBC 驱动程序实现的名称。
             * 应用程序不再需要使用 Class.forName() 显式地加载 JDBC 驱动程序。
             *
             */

            // 2. 创建连接
            /*
             * JDBC连接数据库的url格式是:
             *   jdbc:子协议://subname
             *
             * JDBC连接MySQL数据库的url格式是:
             *    jdbc:mysql://主机名:端口号/数据库名 -----> jdbc:mysql://localhost:3306/db02
             * 如果主机名:端口号是 localhost:3306 那么主机名:端口号可以省略  -----> jdbc:mysql:///db02
             */
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/powernode_jdbc", "root", "root");
            // 3. 获取Statement语句对象
            statement = connection.createStatement();
            // 4. 执行SQL语句
            String sql = "select id,name as xxx,age from student";
            resultSet = statement.executeQuery(sql);
            // 5. 解析ResultSet结果集
            /*
             * java.sql.SQLException: Before start of result set
             * 出现该异常的原因是:目前ResultSet对象具有指向其当前数据行的光标,光标位于第一行数据之前
             *
             */
            while (resultSet.next()) {
                /*
                 * resultSet中获取数据的方法getXXXX()都有两个重载方法。
                 * 一个是根据投影字段的索引获取数据;一个是根据投影字段的名称(别名)获取数据
                 *
                 * 注意:数据库索引从1开始
                 */
                // 根据投影字段的名称(别名)获取数据
                String name = resultSet.getString("xxx");
                /*
                 * 根据投影字段的索引获取数据  -- 不推荐使用
                 * 弊端:就是投影字段的顺序调整后,获取数据就就不对了
                        */
//               String name = resultSet.getString(2);
                System.out.println("name= " + name);
            }
        } catch (Exception throwables) {
            throwables.printStackTrace();
        } finally {
            // 6. 释放资源
            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                resultSet = null;
            }

            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                statement = null;
            }

            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                connection = null;
            }
        }

    }
}

五、注册案例

数据库sql
sys_user.sql

/*
 Navicat Premium Data Transfer

 Source Server         : MySQL80_3306
 Source Server Type    : MySQL
 Source Server Version : 80030
 Source Host           : localhost:3306
 Source Schema         : powernode_jdbc

 Target Server Type    : MySQL
 Target Server Version : 80030
 File Encoding         : 65001

 Date: 27/01/2023 19:04:21
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, 'admin', '123456');
INSERT INTO `sys_user` VALUES (2, 'zhangsan', '123');
INSERT INTO `sys_user` VALUES (3, '张三', '123456');
INSERT INTO `sys_user` VALUES (4, 'hhh', '123');
INSERT INTO `sys_user` VALUES (5, 'hhh', '123456');

SET FOREIGN_KEY_CHECKS = 1;

代码

package _02注册案例;

        import java.sql.Connection;
        import java.sql.DriverManager;
        import java.sql.SQLException;
        import java.sql.Statement;
        import java.util.Scanner;

/**
 * 注册案例
 */
public class RegisterDemo {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String username = scanner.nextLine();
        System.out.println("请输入密码:");
        String password = scanner.nextLine();

        Connection connection = null;
        Statement statement = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/powernode_jdbc", "root", "root");
            statement = connection.createStatement();
            /*
             *DML语句使用:executeUpdate --> 返回受影响的行数
             * DQL语句使用:executeQuery --> 返回查询到的结果集(虚拟表)
             */
            String sql = "insert into sys_user VALUES(null,'"+username+"','"+password+"')";
            System.out.println("sql = " + sql);
            int rows = statement.executeUpdate(sql);
            if(rows>0){
                System.out.println("插入成功");
            }else{
                System.out.printf("插入失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                statement = null;
            }

            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                connection = null;
            }
        }

    }


}

六、登录案例

6.1 Statement

package _03登录案例SQL注入._31Statement;

import java.sql.*;
import java.util.Scanner;

/**
 * 登录案例
 *
 */
public class LoginDemo {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String inputUsername = scanner.nextLine();
        System.out.println("请输入密码:");
        String inputPassword = scanner.nextLine();

        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/powernode_jdbc", "root", "root");
            statement = connection.createStatement();
            /*
             *DML语句使用:executeUpdate --> 返回受影响的行数
             * DQL语句使用:executeQuery --> 返回查询到的结果集(虚拟表)
             */
            String sql = "select * from sys_user where username= '"+inputUsername+"'and password ='"+ inputPassword+"'";
            System.out.println("sql = " + sql);
            resultSet = statement.executeQuery(sql);
            if(resultSet.next()){
                String username = resultSet.getString("username");
                String password = resultSet.getString("password");
                System.out.println(username+"登录成功");
            }else {
                System.out.println("登录失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                resultSet = null;
            }

            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                statement = null;
            }

            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                connection = null;
            }
        }

    }


}

正常情况
在这里插入图片描述
异常情况
在这里插入图片描述
分析:
在这里插入图片描述
而这里用的是 if(resultSet.next())游标只向下移动一位,指向数据库表的第一个数据,所以结果查询出来的结果只有表中的第一条

我们发现以上输入的密码不是正确的密码,但是登录成功了。原因是以上代码出现了SQL注入的问题。引出SQL注入。

七、SQL注入

7.1 SQL注入

SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步得到相应的数据信息。

SQL注入: 就是SQL语句中接收的参数包含有SQL语句的关键字,破坏了SQL语句原有的功能。

7.2 出现SQL注入的原因

出现SQL注入的原因:是包含SQL语句关键字的的参数当做SQL语句进行编译了

7.3 解决方案

就是将SQL语句接收的参数当做普通的字符串参数使用,而不当做SQL语句,参与SQL语句的编译。Java中提供了PreparedStatement接口来解决SQL注入问题。

7.4 PreparedStatement接口

public interface PreparedStatement extends Statement

表示预编译的 SQL 语句的对象。

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

注意:用于设置 IN 参数值的设置方法(setShortsetString 等等)必须指定与输入参数的已定义 SQL 类型兼容的类型。例如,如果 IN 参数具有 SQL 类型 INTEGER,那么应该使用 setInt 方法。

如果需要任意参数类型转换,使用 setObject 方法时应该将目标 SQL 类型作为其参数。

7.5 PreparedStatement如何解决SQL注入

PreparedStatement会事先对SQL语句进行预编译。预编译后的SQL语句保存在PreparedStatement对象中。

预编译完成后再使用SQL接收的参数,所以此时SQL接收的参数是不会参与SQL编译了

PreparedStatement是先编译,后使用参数。所以参数中即使有SQL关键字也只能当做普通字符串使用了。

7.6 使用PreparedStatement改进代码,解决SQL注入问题

package _03登录案例SQL注入._32PreparedStatement;

import java.sql.*;
import java.util.Scanner;

/**
 * 登录案例
 *      使用PreparedStatement改进代码,解决SQL注入问题
 *
 */
public class LoginDemo {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String inputUsername = scanner.nextLine();
        System.out.println("请输入密码:");
        String inputPassword = scanner.nextLine();

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");

            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/powernode_jdbc", "root", "root");

            /*
             *DML语句使用:executeUpdate --> 返回受影响的行数
             * DQL语句使用:executeQuery --> 返回查询到的结果集(虚拟表)
             */
            /*
             * ? 表示参数占位符
             * SQL语句进行预编译的时候,是还没有给具体参数的,而是使用?来对参数进行占位
             */
            String sql = "select * from sys_user where username = ? and password = ?";

            //获取PreparedStatement对象
             preparedStatement = connection.prepareStatement(sql);

            // 预编译完后成,再使用参数替换占位符
            // 第一个参数:表示第几个?
            preparedStatement.setString(1,inputUsername);
            preparedStatement.setString(2,inputPassword);


            /*
             * PreparedStatement的executeQuery()和executeUpdate()是无参的
             * 因为PreparedStatement对象preparedStatement中就保存有SQL语句
             */
            resultSet = preparedStatement.executeQuery();

            if(resultSet.next()){
                String username = resultSet.getString("username");
                String password = resultSet.getString("password");
                System.out.println(username+"登录成功");
            }else {
                System.out.println("登录失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

            if (resultSet != null) {
                try {
                    resultSet.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                resultSet = null;
            }

            if (preparedStatement != null) {
                try {
                    preparedStatement.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                preparedStatement = null;
            }

            if (connection != null) {
                try {
                    connection.close();
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                }
                connection = null;
            }
        }

    }


}

测试结果
在这里插入图片描述

八、编写JDBC工具类

resources文件夹下

jdbc.properties

# JDBC四要素
# 驱动类名
driverClassName=com.mysql.cj.jdbc.Driver
# 数据库连接地址
url=jdbc:mysql://localhost:3306/powernode_jdbc
# 用户名
username=root
# 密码
password=root

代码:

package _04编写JDBC工具类;

import javax.print.DocFlavor;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * JDBC工具类
 *   作用:
 *       1. 获取连接
 *           使用配置文件解决硬编码
 *       2. 释放资源
 *
 *
 */
public class JDBCUtils {

    private static String driverClassName;
    private static String url;
    private static String username;
    private static String password;

    private JDBCUtils(){

    }

    /**
     * 配置文件只需要获取一次即可,所以编写在静态代码块中
     * 驱动只需要加载一次即可,所以编写在静态代码块中
     */
    static {
        try {
            InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("jdbc.properties");
            Properties properties = new Properties();
            properties.load(inputStream);

            driverClassName = properties.getProperty("driverClassName");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            Class.forName(driverClassName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     * @return 数据库连接
     */
    public static Connection getConnection(){
        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            return connection;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 释放资源
      * @param autoCloseable 需要释放的资源
     */
    public static void close(AutoCloseable ...autoCloseable){
        if(autoCloseable!=null){
            for (AutoCloseable closeable : autoCloseable) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

九、CRUD操作

添加单元测试的jar包hamcrest-core-1.3.jarjunit-4.13.2.jar
我的jar包的下载地址链接:https://download.csdn.net/download/weixin_46411355/87398726
怎么导入jar包,可查看笔者的另一篇博客《IDEA导入和删除第三方jar包》链接:https://huanghaoheng.blog.csdn.net/article/details/126332558

数据库sql
t_student.sql

/*
 Navicat Premium Data Transfer

 Source Server         : MySQL80_3306
 Source Server Type    : MySQL
 Source Server Version : 80030
 Source Host           : localhost:3306
 Source Schema         : powernode_jdbc

 Target Server Type    : MySQL
 Target Server Version : 80030
 File Encoding         : 65001

 Date: 27/01/2023 19:07:45
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_student
-- ----------------------------
DROP TABLE IF EXISTS `t_student`;
CREATE TABLE `t_student`  (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `sid` int NULL DEFAULT NULL,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
  `age` int NULL DEFAULT NULL,
  `gender` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
  `province` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
  `create_time` datetime NULL DEFAULT NULL,
  `update_time` datetime NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_student
-- ----------------------------
INSERT INTO `t_student` VALUES (1, 1001, '张三', 20, 'male', '四川省', '2022-12-27 19:48:52', '2023-01-25 19:49:34');
INSERT INTO `t_student` VALUES (2, 1002, '李四', 20, 'female', '四川省', '2023-01-25 19:50:18', '2023-01-26 19:50:21');
INSERT INTO `t_student` VALUES (3, 1003, '王五', 23, 'male', '云南省', '2023-01-19 19:51:01', '2023-01-04 19:51:03');
INSERT INTO `t_student` VALUES (4, 2001, 'hhh', 24, 'male', '四川省', '2023-01-26 00:00:00', '2023-01-26 14:12:00');
SET FOREIGN_KEY_CHECKS = 1;

javaBean

package javabean;

import java.util.Objects;

/**
 * 实体类 -- 对应数据表t_student
 *
 * 和数据表对应的实体类,成员变量的数据类型使用包装类,不使用基本类型
 *
 * 因为数据库中字段没有值是null,
 * int类型的基本数据类型的默认值是0,0不能表示没有值
 * 但是引用数据类型的默认值是null,符合数据库中字段没有值是null
 *
 */
public class Student {
    private Long id;
    private Integer sid;
    private String name;
    // tinyint unsignd --> 使用Integer
    private Integer age;
    private String gender;
    private String province;
    private String create_time;
    private String update_time;

    public Student() {
    }

    public Student(Long id, Integer sid, String name, Integer age, String gender) {
        this.id = id;
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public Student(Long id, Integer sid, String name, Integer age, String gender, String province, String create_time, String update_time) {
        this.id = id;
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.province = province;
        this.create_time = create_time;
        this.update_time = update_time;
    }




    public Long getId() {
        return id;
    }

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

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCreate_time() {
        return create_time;
    }

    public void setCreate_time(String create_time) {
        this.create_time = create_time;
    }

    public String getUpdate_time() {
        return update_time;
    }

    public void setUpdate_time(String update_time) {
        this.update_time = update_time;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", sid=" + sid +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", province='" + province + '\'' +
                ", create_time='" + create_time + '\'' +
                ", update_time='" + update_time + '\'' +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id) &&
                Objects.equals(sid, student.sid) &&
                Objects.equals(name, student.name) &&
                Objects.equals(age, student.age) &&
                Objects.equals(gender, student.gender) &&
                Objects.equals(province, student.province) &&
                Objects.equals(create_time, student.create_time) &&
                Objects.equals(update_time, student.update_time);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, sid, name, age, gender, province, create_time, update_time);
    }
}

CRUDDemo.java

package _05CRUD;

import _04编写JDBC工具类.JDBCUtils;
import javabean.Student;
import org.junit.Test;

        import java.sql.Connection;
        import java.sql.Date;
        import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * CRUD:增删查改
 */
public class CRUDDemo {

    /**
     * 插入数据
     */
    @Test
    public void testInsert(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "insert into t_student values(null,?,?,?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,2002);
            preparedStatement.setString(2,"罗龙江");
            preparedStatement.setInt(3,24);
            preparedStatement.setString(4,"male");
            preparedStatement.setString(5,"贵州省");
            preparedStatement.setDate(6,new Date(System.currentTimeMillis()));
            //MySQL日期类型的数据可以使用String格式的时间表示
//            preparedStatement.setString(7,"2023-1-26 14:12");
            preparedStatement.setString(7,"2023/1/26 14:12");

            int row = preparedStatement.executeUpdate();
            System.out.println(row);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(preparedStatement,connection);
        }
    }

    /**
     * 更新数据
     */
    @Test
    public void testUpdate(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "update t_student set name = ? where sid = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"黄浩恒");
            preparedStatement.setInt(2,2001);

            int row = preparedStatement.executeUpdate();
            System.out.println(row);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(preparedStatement,connection);
        }
    }

    /**
     * 删除数据
     */
    @Test
    public void testDelete(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "delete from t_student where name = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"罗龙江");

            int row = preparedStatement.executeUpdate();
            System.out.println(row);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(preparedStatement,connection);
        }
    }

    /**
     * 查询一条数据
     */
    @Test
    public void testSelectOne(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "select * from t_student where sid = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,1002);
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){


                Long id = resultSet.getLong("id");
                int sid = resultSet.getInt("sid");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                String province = resultSet.getString("province");
                String create_time = resultSet.getString("create_time");
                String update_time = resultSet.getString("update_time");

                Student student = new Student(id,sid,name,age,gender);
                student.setProvince(province);
                student.setCreate_time(create_time);
                student.setUpdate_time(update_time);

                System.out.println(student);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(resultSet,preparedStatement,connection);
        }
    }

    /**
     * 查询多条数据
     */
    @Test
    public void testSelectList(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<Student> studentList = new ArrayList<>();
        try {
            connection = JDBCUtils.getConnection();
            String sql = "select * from t_student";
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){


                Long id = resultSet.getLong("id");
                int sid = resultSet.getInt("sid");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                String province = resultSet.getString("province");
                String create_time = resultSet.getString("create_time");
                String update_time = resultSet.getString("update_time");

                Student student = new Student(id,sid,name,age,gender);
                student.setProvince(province);
                student.setCreate_time(create_time);
                student.setUpdate_time(update_time);

               studentList.add(student);
            }

            //遍历集合
            studentList.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            JDBCUtils.close(resultSet,preparedStatement,connection);
        }
    }
}

十、事务操作

数据库sql
t_account.sql

/*
 Navicat Premium Data Transfer

 Source Server         : MySQL80_3306
 Source Server Type    : MySQL
 Source Server Version : 80030
 Source Host           : localhost:3306
 Source Schema         : powernode_jdbc

 Target Server Type    : MySQL
 Target Server Version : 80030
 File Encoding         : 65001

 Date: 27/01/2023 19:09:51
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_account
-- ----------------------------
DROP TABLE IF EXISTS `t_account`;
CREATE TABLE `t_account`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
  `money` int NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of t_account
-- ----------------------------
INSERT INTO `t_account` VALUES (1, '张三', 1000);
INSERT INTO `t_account` VALUES (2, '李四', 1000);

SET FOREIGN_KEY_CHECKS = 1;

 package _06事务操作;

import _04编写JDBC工具类.JDBCUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
 * 演示事务转账
 * 转账的案例
 */
public class TransactionDemo {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement  = null;

        //张三给李四转100元 -- 整体是一个事务
        try{
            connection = JDBCUtils.getConnection();
            //1.关闭自动提交:开启事务,手动提交
            connection.setAutoCommit(false);
            //张三的账户减少100
            String sql = "update t_account set money = money - ? where name = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,100);
            preparedStatement.setString(2,"张三");
            preparedStatement.executeUpdate();

//            System.out.println( 1/0 );

            //李四的账户增加100
            sql = "update t_account set money = money + ? where name = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,100);
            preparedStatement.setString(2,"李四");

            preparedStatement.executeUpdate();

            //2.提交事务
            connection.commit();
        }catch (Exception e){
              e.printStackTrace();
              //3.回滚事务
            try {
                connection.rollback();
            } catch (SQLException ex) {
                ex.printStackTrace();
            }
        }finally {
            JDBCUtils.close(preparedStatement,connection);
        }
    }
}

十一、批处理

批处理的配置文件中的url必须要配置一个参数?rewriteBatchedStatements=true

resources目录下的

11.1 jdbc.properties

# JDBC四要素
# 驱动类名
driverClassName=com.mysql.cj.jdbc.Driver
# 数据库连接地址
# ?rewriteBatchedStatements=true批处理必须添加该参数
url=jdbc:mysql://localhost:3306/powernode_jdbc?rewriteBatchedStatements=true
# 用户名
username=root
# 密码
password=root

11.2 BatchDemo.java

package _07批处理;

import _04编写JDBC工具类.JDBCUtils;
import org.junit.Test;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;

/**
 * JDBC批处理
 */
public class BatchDemo {

    /**
     * 不使用批处理来 插入1000条数据
     */
    @Test
    public void testNoBatch() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "insert into t_student values(null,?,?,?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);

            long start = System.currentTimeMillis();

            for (int i = 1; i <= 1000; i++) {
                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "hhh" + i);
                preparedStatement.setInt(3, 24 + i);
                preparedStatement.setString(4, "male" + i);
                preparedStatement.setString(5, "贵州省" + i);
                preparedStatement.setDate(6, new Date(System.currentTimeMillis()));
                //MySQL日期类型的数据可以使用String格式的时间表示
//            preparedStatement.setString(7,"2023-1-26 14:12");
                preparedStatement.setString(7, "2023/1/26 14:12");

                preparedStatement.executeUpdate();
            }
            long end = System.currentTimeMillis();
            System.out.println("耗时:" + (end - start));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(preparedStatement, connection);
        }
    }

    /**
     *使用批处理来 插入1000条数据
     */
    @Test
    public void testBatch(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = JDBCUtils.getConnection();
            String sql = "insert into t_student values(null,?,?,?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);

            long start = System.currentTimeMillis();

            for (int i = 1; i <= 1000; i++) {
                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "hhh" + i);
                preparedStatement.setInt(3, 24 + i);
                preparedStatement.setString(4, "male" + i);
                preparedStatement.setString(5, "贵州省" + i);
                preparedStatement.setDate(6, new Date(System.currentTimeMillis()));
                //MySQL日期类型的数据可以使用String格式的时间表示
//            preparedStatement.setString(7,"2023-1-26 14:12");
                preparedStatement.setString(7, "2023/1/26 14:12");

                //添加到批处理中
                preparedStatement.addBatch();
            }
            //执行批处理
            preparedStatement.executeBatch();

            long end = System.currentTimeMillis();
            System.out.println("耗时:" + (end - start));

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.close(preparedStatement, connection);
        }
    }

}

11.3 没有进行批处理的耗时在这里插入图片描述

11.4 进行批处理的耗时在这里插入图片描述

十二、连接池

连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用。

连接池是装有连接的容器,使用连接的话,可以从连接池中进行获取,使用完成之后将连接归还给连接池。

使用连接池可以减少数据库连接的频繁创建和销毁,提升效率。

12.1 连接池原理

在这里插入图片描述

12.2 DataSource接口

该工厂用于提供到此 DataSource 对象所表示的物理数据源的连接。作为 DriverManager 工具的替代项,DataSource 对象是获取连接的首选方法。

DataSource 接口由驱动程序供应商实现。共有三种类型的实现:

  1. 基本实现 – 生成标准的 Connection 对象
  2. 连接池实现 – 生成自动参与连接池的 Connection 对象。此实现与中间层连接池管理器一起使用。
  3. 分布式事务实现 – 生成一个 Connection 对象,该对象可用于分布式事务,大多数情况下总是参与连接池。此实现与中间层事务管理器一起使用,大多数情况下总是与连接池管理器一起使用。

在IDEA中导入druid的jar包
笔者druid的jar包下载链接:https://download.csdn.net/download/weixin_46411355/87399287
怎么导入jar包,可查看笔者的另一篇博客《IDEA导入和删除第三方jar包》链接:https://huanghaoheng.blog.csdn.net/article/details/126332558

12.3 druid.properties

# 约定大于配置
driverClassName=com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/powernode_jdbc?rewriteBatchedStatements=true
username=root
password=root

12.4 DruidUtils.java

package _08连接池;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.alibaba.druid.sql.dialect.odps.ast.OdpsAddTableStatement;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;

/**
 * 数据库连接池 Druid工具类
 */
public class DruidUtils {
    private static Properties properties = new Properties();

    private DruidUtils(){

    }

    static {
        InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("druid.properties");
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从连接池中获取连接
     * DruidDataSource默认是非公平锁
     * @return 连接
     */
    public static Connection getConnection() {
        try {
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            return dataSource.getConnection();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 释放资源
     * @param autoCloseable 需要释放的资源
     */
    public static void close(AutoCloseable ...autoCloseable){
        if(autoCloseable!=null){
            for (AutoCloseable closeable : autoCloseable) {
                try {
                    closeable.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

12.5 使用Druid连接池完成CRUD

CRUDDemo.java

package _08连接池;

import _04编写JDBC工具类.JDBCUtils;
import javabean.Student;
import org.junit.Test;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

/**
 * CRUD:增删查改
 */
public class CRUDDemo {

    /**
     * 插入数据
     */
    @Test
    public void testInsert(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = DruidUtils.getConnection();
            String sql = "insert into t_student values(null,?,?,?,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,2002);
            preparedStatement.setString(2,"罗龙江");
            preparedStatement.setInt(3,24);
            preparedStatement.setString(4,"male");
            preparedStatement.setString(5,"贵州省");
            preparedStatement.setDate(6,new Date(System.currentTimeMillis()));
            //MySQL日期类型的数据可以使用String格式的时间表示
//            preparedStatement.setString(7,"2023-1-26 14:12");
            preparedStatement.setString(7,"2023/1/26 14:12");

            int row = preparedStatement.executeUpdate();
            System.out.println(row);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            DruidUtils.close(preparedStatement,connection);
        }
    }

    /**
     * 更新数据
     */
    @Test
    public void testUpdate(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = DruidUtils.getConnection();
            String sql = "update t_student set name = ? where sid = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"HHH");
            preparedStatement.setInt(2,2001);

            int row = preparedStatement.executeUpdate();
            System.out.println(row);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            DruidUtils.close(preparedStatement,connection);
        }
    }

    /**
     * 删除数据
     */
    @Test
    public void testDelete(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;

        try {
            connection = DruidUtils.getConnection();
            String sql = "delete from t_student where name = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"罗龙江");

            int row = preparedStatement.executeUpdate();
            System.out.println(row);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            DruidUtils.close(preparedStatement,connection);
        }
    }

    /**
     * 查询一条数据
     */
    @Test
    public void testSelectOne(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = DruidUtils.getConnection();
            String sql = "select * from t_student where sid = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,1002);
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){


                Long id = resultSet.getLong("id");
                int sid = resultSet.getInt("sid");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                String province = resultSet.getString("province");
                String create_time = resultSet.getString("create_time");
                String update_time = resultSet.getString("update_time");

                Student student = new Student(id,sid,name,age,gender);
                student.setProvince(province);
                student.setCreate_time(create_time);
                student.setUpdate_time(update_time);

                System.out.println(student);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            DruidUtils.close(resultSet,preparedStatement,connection);
        }
    }

    /**
     * 查询多条数据
     */
    @Test
    public void testSelectList(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<Student> studentList = new ArrayList<>();
        try {
            connection = DruidUtils.getConnection();
            String sql = "select * from t_student";
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){


                Long id = resultSet.getLong("id");
                int sid = resultSet.getInt("sid");
                String name = resultSet.getString("name");
                int age = resultSet.getInt("age");
                String gender = resultSet.getString("gender");
                String province = resultSet.getString("province");
                String create_time = resultSet.getString("create_time");
                String update_time = resultSet.getString("update_time");

                Student student = new Student(id,sid,name,age,gender);
                student.setProvince(province);
                student.setCreate_time(create_time);
                student.setUpdate_time(update_time);

               studentList.add(student);
            }

            //遍历集合
            studentList.forEach(System.out::println);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            DruidUtils.close(resultSet,preparedStatement,connection);
        }
    }
}

十三、BaseDAO的封装

13.1 什么是DAO

DAO:数据访问对象(Data Access Object)

13.2 封装DML语句

BaseDAO.java类中代码

/**
     * DML语句操作的模板
     *
     * @param sql  DML语句
     * @param args sql语句的参数
     * @return 受影响的函数
     */
    public static int executeDMLSQL(String sql, Object... args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        int row = 0;
        try {
            connection = DruidUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            row = preparedStatement.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DruidUtils.close(preparedStatement, connection);
        }
        return row;
    }

测试类中代码
.

@Test
    public void testDML(){
        String updateSql = "update t_student set name = ? where sid = ?";
        int row = BaseDAO.executeDMLSQL(updateSql, "hhh", 2001);
        System.out.println("row = " + row);
    }

13.3 封装DQL语句

13.3.1 思路

在这里插入图片描述

13.3.2 API

13.2.1 ResultSet

getMetaData()方法
在这里插入图片描述
在这里插入图片描述

ResultSetMetaData getMetaData() throws SQLException

获取此 ResultSet 对象的列的编号、类型和属性。

返回:
此 ResultSet 对象的列的描述
抛出:
SQLException – 如果发生数据库访问错误或在已关闭的结果集上调用此方法

13.2.2 ResultSetMetaData接口
①getColumnCount()方法

在这里插入图片描述
在这里插入图片描述

int getColumnCount() throws SQLException

返回此 ResultSet 对象中的列数。

返回:
列数
抛出:
SQLException – 如果发生数据库访问错误

②getColumnLabel(int column) 和 getColumnName(int column) 方法

在这里插入图片描述
在这里插入图片描述
getColumnLabel方法

String getColumnLabel(int column) throws SQLException

获取用于打印输出和显示的指定列的建议标题建议标题通常由 SQL AS 子句来指定如果未指定 SQL AS,则从 getColumnLabel 返回的值将和 getColumnName 方法返回的值相同

参数:
column – 第一列是 1,第二个列是 2,……
返回:
建立列标题
抛出:
SQLException – 如果发生数据库访问错误

getColumnName方法

String getColumnName(int column) throws SQLException

获取指定列的名称

参数:
column – 第一列是 1,第二个列是 2,……
返回:
列名称
抛出:
SQLException – 如果发生数据库访问错误

用代码测试出这两个方法的区别
BaseDAO.java中的代码片段

 @Test
    public void testexecuteDQLSQLHalf() {
        String selectSql = "select * from t_student";
        executeDQLSQLHalf(selectSql);
    }

    /**
     * 这个测试代码可以测试出metaData.getColumnName和metaData.getColumnLabel的区别
     */
    @Test
    public void testDifferenceBetweenGetColumnNameAndGetColumnLabel() {
        String selectSql = "select sid,name as xxx ,age from t_student";
        executeDQLSQLHalf(selectSql);
    }

    public static <T> List<T> executeDQLSQLHalf(String sql, Object... args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        List list = new ArrayList();
        try {
            connection = DruidUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            /*
             * 思考:怎么做到表中数据和Java变量进行绑定(通用性)
             * select-->虚拟表-->投影字段
             * 投影字段和成员变量的名称一致的话,就可以使用反射来操作对象的字段
             */
            /*
             * resultSet是查询语句得到的虚拟表结果集
             * 所以resultSet中有字段的信息
             */
            /*
             *  resultSet.getMetaData()获取此 ResultSet 对象的列的编号、类型和属性。
             */
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取投影字段的数量
            int columnCount = metaData.getColumnCount();
            while (resultSet.next()) {
                //获取字段
                for (int i = 1; i <= columnCount; i++) {
                    //获取表中投影字段的名称
//                    String columnName = metaData.getColumnName(i);
//                    System.out.println("columnName = " + columnName);
                    //获取表中投影字段的名称,如果投影字段有别名,获取的是别名
                    String columnLabel = metaData.getColumnLabel(i);
                    System.out.println("columnLabel = " + columnLabel);
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DruidUtils.close(resultSet, preparedStatement, connection);
        }
        return list;

    }

运行效果:
getColumnName
在这里插入图片描述
getColumnLabel
在这里插入图片描述

小结:
getColumnName:获取表中投影字段的名称
getColumnLabel:获取表中投影字段的名称,如果投影字段有别名,获取的是别名

13.3.3 javaBean

Student.java
注意:create_time和update_time均为LocalDateTime 类型

package _09BaseDAO的封装.javabean;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * 实体类 -- 对应数据表t_student
 *
 * 和数据表对应的实体类,成员变量的数据类型使用包装类,不使用基本类型
 *
 * 因为数据库中字段没有值是null,
 * int类型的基本数据类型的默认值是0,0不能表示没有值
 * 但是引用数据类型的默认值是null,符合数据库中字段没有值是null
 *
 */
public class Student {
    private Long id;
    private Integer sid;
    private String name;
    private Integer age;
    private String gender;
    private String province;
    private LocalDateTime create_time;
    private LocalDateTime update_time;

    public Student() {
    }

    public Student(Long id, Integer sid, String name, Integer age, String gender) {
        this.id = id;
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public Student(Long id, Integer sid, String name, Integer age, String gender, String province, LocalDateTime create_time, LocalDateTime update_time) {
        this.id = id;
        this.sid = sid;
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.province = province;
        this.create_time = create_time;
        this.update_time = update_time;
    }

    public Long getId() {
        return id;
    }

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

    public Integer getSid() {
        return sid;
    }

    public void setSid(Integer sid) {
        this.sid = sid;
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

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

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public LocalDateTime getCreate_time() {
        return create_time;
    }

    public void setCreate_time(LocalDateTime create_time) {
        this.create_time = create_time;
    }

    public LocalDateTime getUpdate_time() {
        return update_time;
    }

    public void setUpdate_time(LocalDateTime update_time) {
        this.update_time = update_time;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", sid=" + sid +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", province='" + province + '\'' +
                ", create_time=" + create_time +
                ", update_time=" + update_time +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return Objects.equals(id, student.id) &&
                Objects.equals(sid, student.sid) &&
                Objects.equals(name, student.name) &&
                Objects.equals(age, student.age) &&
                Objects.equals(gender, student.gender) &&
                Objects.equals(province, student.province) &&
                Objects.equals(create_time, student.create_time) &&
                Objects.equals(update_time, student.update_time);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, sid, name, age, gender, province, create_time, update_time);
    }
}

13.3.4 封装DQLSQL的方法

在BaseDAO中

/**
     * DQL语句的模板:
     * 1.对象成员变量的数据类型要和表中字段的数据类型一致
     * 2.对象成员变量的名称要和投影字段的名称(别名)一样
     * @param clazz 对象的Class
     * @param sql sql语句
     * @param args sql语句的参数
     * @param <T> 对象的Class的类型
     * @return 集合
     */
    public static <T> List<T> executeDQLSQL(Class<T> clazz, String sql, Object... args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        List list = new ArrayList();
        try {
            connection = DruidUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                preparedStatement.setObject(i + 1, args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            /*
             * 思考:怎么做到表中数据和Java变量进行绑定(通用性)
             * select-->虚拟表-->投影字段
             * 投影字段和成员变量的名称一致的话,就可以使用反射来操作对象的字段
             */
            /*
             * resultSet是查询语句得到的虚拟表结果集
             * 所以resultSet中有字段的信息
             */
            /*
             *  resultSet.getMetaData()获取此 ResultSet 对象的列的编号、类型和属性。
             */
            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取投影字段的数量
            int columnCount = metaData.getColumnCount();
            //while执行一次,就是获取表中一行的数据
            while (resultSet.next()) {
                //一行数据对应一个对象
                //使用反射 创建javaBean对象
                T t = clazz.newInstance();
                /*
                 *getColumnName(i):获取表中投影字段的名称
                 * getColumnLabel(i):获取表中投影字段的名称,如果投影字段有别名,获取的是别名
                 */
                for (int i = 1; i <= columnCount; i++) {
                    //获取每一行的字段名称和字段值

                    //获取表中投影字段的名称
//                    String columnName = metaData.getColumnName(i);
//                    System.out.println("columnName = " + columnName);
                    //获取表中投影字段的名称,如果投影字段有别名,获取的是别名
                    String columnLabel = metaData.getColumnLabel(i);
//                    System.out.println("columnLabel = " + columnLabel);

                    //获取 结果集中 表字段对应的值
                    Object columnValue = resultSet.getObject(columnLabel);

                    //使用反射 根据投影字段的名称 对应的 获取JavaBean已声明的成员变量
                    Field field = clazz.getDeclaredField(columnLabel);//javabean的成员变量
                    //暴力破解,因为javabean的成员变量是由private修饰的
                    field.setAccessible(true);

                    //给javabean的成员变量赋值
                    field.set(t, columnValue);
                }
                list.add(t);

            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DruidUtils.close(resultSet, preparedStatement, connection);
        }
        return list;

    }

13.3.5 测试类

  @Test
    public void testDQL(){
        String selectSql = "select * from t_student";
        List<Student> studentList = BaseDAO.executeDQLSQL(Student.class, selectSql);
        studentList.forEach(System.out::println);
    }

13.3.6运行效果

在这里插入图片描述

13.3.7 万能SQL模板(将DML语句和DQL语句同时封装)

在BaseDAO中

  public static void executeSQL(Class<?>clazz,String sql,Object...args){
        String[] sqlArray = sql.split(" ");
        String sqlMethod = sqlArray[0];

        if("select".equalsIgnoreCase(sqlMethod)){
            if(clazz==null){
                throw new RuntimeException("执行查询语句必须需要javaBean的Class对象");
            }
            List<?> list = executeDQLSQL(clazz, sql, args);
            list.forEach(System.out::println);

        }
        else{
            int row = executeDMLSQL(sql, args);
            System.out.println("row = " + row);
        }
    }

测试类

/**
     * 测试万能 先测试DML
     */
    @Test
    public void testSQL(){
        String updateSql = "update t_student set name = ? where sid = ?";
        BaseDAO.executeSQL(Student.class,updateSql,"hhh",2001);
    }

    /**
     * 测试万能 后测试DQL
     */
    @Test
    public void testSQL2(){
        String selectSql = "select * from t_student";
        BaseDAO.executeSQL(null,selectSql);
    }

十四、分页的封装

14.1 分页结果封装类 PageInfo

package _10分页的封装;

import java.util.List;

/**
 * 分页结果封装类
 * @param <T>
 */
public class PageInfo<T> {
    private List<T> data;//每页具体的数据
    private Long count;//符合条件的数据总条数

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }
}

14.2 修改BaseDAO

分页查询的方法

 /**
     * 分页查询
     * @param clazz 查询的数据封装的对象对应的Class
     * @param sql sql语句
     * @param  currentPage 当前页数,也就是第几页
     * @param pageSize 每页显示的条数
     * @return 分页封装的对象
     */
    public static <T> PageInfo<T> selectByPage(Class<T> clazz,String sql,int currentPage,int pageSize){
        //分页的时候limit跳过的条数
        int index = 0;
        index = (currentPage-1)*pageSize;
        String selectSql = sql+" limit "+index+","+pageSize;
        // 查询获取当前指定页数的数据
        List<T> list = executeDQLSQL(clazz, selectSql);

        //获取总的条数
        // select * from student
        Long totalCount = getTotalCount(sql);

        PageInfo<T> pageInfo  = new PageInfo<>();
        pageInfo.setData(list);
        pageInfo.setCount(totalCount);

        return pageInfo;
    }

统计条数的方法

 /**
     * 获取总的条数
     * @param sql sql语句
     * @return 返回条数
     */
    private static Long getTotalCount(String sql){
        //子查询
        //select count(1) from ( select * from student ) as s
        String countSql = "select count(1) from ("+sql+") as s";

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = DruidUtils.getConnection();
            preparedStatement = connection.prepareStatement(countSql);
            resultSet = preparedStatement.executeQuery();
            resultSet.next();//先让光标指向数据的第一行
            long totalCount = resultSet.getLong(1);
            return totalCount;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtils.close(resultSet,preparedStatement,connection);
        }
        return 0L;
    }

14.3 测试类

package _10分页的封装;

import _09BaseDAO的封装.BaseDAO;

import newJavaBean.Student;
import org.junit.Test;

public class PageTest {
    @Test
    public void testPaging(){
        String sql = "select * from t_student where id > 4";
        PageInfo<Student> pageInfo = BaseDAO.selectByPage(Student.class, sql, 1, 2);
        //总条数
        System.out.println(pageInfo.getCount());
        // 第一页显示的数据
        System.out.println(pageInfo.getData());
}

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/85499.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!