首页 > 其他分享 >day46-JDBC和连接池02

day46-JDBC和连接池02

时间:2022-10-14 22:44:13浏览次数:41  
标签:02 JDBC java String import PreparedStatement sql day46 properties

JDBC和连接池02

3.ResultSet[结果集]

  • 基本介绍
  1. 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成
  2. ResultSet对象保持一个光标指向其当前的数据行,最初,光标位于第一行的之前
  3. next方法将光标移动到下一行,并且由于在ResultSet对象中没有更多行时返回false,因此可以在while循环中使用循环来遍历结果集

例子

首先在数据库的actor表中添加两行数据

INSERT INTO actor VALUES(NULL,'刘德华','男','1970-12-12','110'),
			(NULL,'jack','男','1990-11-11','112')
image-20221014173529899
package li.jdbc.resultset_;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Date;
import java.util.Properties;

@SuppressWarnings("all")
public class ResultSet_ {
    public static void main(String[] args) throws Exception {
        //通过Properties对象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.注册驱动
        Class.forName(driver);//建议写上
        //2.得到连接
        Connection connection = DriverManager.getConnection(url, user, password);

        //3.得到statement
        Statement statement = connection.createStatement();
        //4.组织sql
        String sql = "select id,name,sex,borndate from actor";
        //执行给定的sql语句,该语句返回单个ResultSet对象

        /**
         +----+-----------+-----+----------------------+
         | id | name      | sex | borndate             |
         +----+-----------+-----+----------------------+
         |  1 | 刘德华    | 男  | 1970-12-12 00:00:00   |
         |  2 | jack     | 男  | 1990-11-11 00:00:00   |
         +----+-----------+-----+----------------------+
         */
        /**
         * resultset源码 ResultSet对象的结构
         *
         */
        ResultSet resultSet = statement.executeQuery(sql);

        //5.使用while循环取出数据
        //最开始时next指向表头(第一行之前)
        while (resultSet.next()) {//让光标向后移动,如果没有更多行,则返回false
            int id = resultSet.getInt(1);//获取该行的第1列数据
            String name = resultSet.getString(2);//获取该行的第2列数据
            String sex = resultSet.getString(3);//获取该行的第3列数据
            Date date = resultSet.getDate(4);//获取该行的第4列数据
            System.out.println(id+"\t"+name+"\t"+sex+"\t"+date);
        }

        //6.关闭连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}

运行结果如下:

image-20221014173656930

在语句ResultSet resultSet = statement.executeQuery(sql);旁打上断点,点击debug,点击step over,选择resultset数组,再选择rowdata。

image-20221014173946558

可以看到底层是arraylist的一个对象数组。

image-20221014173342335

4.Statement

  • 基本介绍
  1. Statement对象,用于执行静态SQL语句并返回其生成的结果的对象
  2. 在建立连接后,需要对数据库进行访问,执行命名或是SQL语句,可以通过
    • Statement [存在SQL注入问题]
    • PreparedStatement [预处理]
    • CallableStatement [存储过程]
  3. Statement对象执行SQL语句,存在SQL注入风险
  4. SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,恶意攻击数据库
  5. 要防范SQL注入,只要用PreparedStatement(从Statement扩展而来)取代Statement就可以了

例子1-sqlyog演示sql注入

-- 演示sql注入
-- 创建一张表
CREATE TABLE admin( -- 管理员表
	NAME VARCHAR(32) NOT NULL UNIQUE,
	pwd VARCHAR(32) NOT NULL DEFAULT ''
)CHARACTER SET utf8;

-- 添加数据
INSERT INTO admin VALUES('tom','123');

-- 正常情况下,查找某个管理是否存在
SELECT * FROM admin
	WHERE NAME = 'tom' AND pwd = '123';
	
-- SQL注入
-- 输入用户名为  1' or 
-- 输入密码为  or '1'='1
-- 这样就变成了下面的语句,可以将所有的数据都查找出来
SELECT * FROM admin
	WHERE NAME = '1' OR' AND pwd = 'OR '1'='1';

例子2-java程序演示SQL注入

package li.jdbc.statement;

//演示statement的注入问题

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
import java.util.Scanner;

public class Statement_ {
    public static void main(String[] args) throws Exception {

        Scanner scanner = new Scanner(System.in);

        //让用户输入管理员的名字和密码
        System.out.print("请输入管理员的名字:");
        String admin_name = scanner.nextLine();//如果希望看到SQL注入,这里需要使用nextLine,如果用next():当接收到空格或者 '就是表示结束
        System.out.print("请输入管理员的密码:");
        String admin_pwd = scanner.nextLine();

        //通过Properties对象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.注册驱动
        Class.forName(driver);
        //2.获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.得到Statement对象
        Statement statement = connection.createStatement();
        //4.组织SQL语句

        String sql = "select name,pwd from admin where name='"
                + admin_name + "' and pwd ='" + admin_pwd + "'";
        ResultSet resultSet = statement.executeQuery(sql);
        if (resultSet.next()) {//如果查询到一条记录,则说明该管理员存在
            System.out.println("恭喜,登录成功");
        } else {
            System.out.println("对不起,登录失败");
        }

        //5.关闭连接
        resultSet.close();
        statement.close();
        connection.close();
    }
}
image-20221014182719032

5.PreparedStatement[预处理查询]

image-20221014183841737
  • 基本介绍
  1. PreparedStatement执行的SQL语句中的 参数用问号(?)来表示,调用PreparedStatement对象的setXxx()方法来设置这些参数。

    setXxx()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个参数是设置的SQL语句中的参数的值

  2. 调用executeQuery(),返回ResultSet对象

  3. 调用executeUpdate():执行更新,包括增,删,修改

  • 预处理的好处
  1. 不再使用+拼接sql语句,减少语法错误
  2. 有效地解决了SQL注入问题
  3. 大大减少了编译次数,效率较高

例子-解决SQL注入问题

package li.jdbc.preparedstatement_;

import java.io.FileInputStream;
import java.sql.*;
import java.util.Properties;
import java.util.Scanner;

//演示PreparedStatement的使用
@SuppressWarnings("all")
public class PreparedStatement_ {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);

        //让用户输入管理员的名字和密码
        System.out.print("请输入管理员的名字:");
        String admin_name = scanner.nextLine();
        System.out.print("请输入管理员的密码:");
        String admin_pwd = scanner.nextLine();

        //通过Properties对象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.注册驱动
        Class.forName(driver);
        //2.获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.得到PreparedStatement对象
        //3.1组织SQL语句,sql语句的问号就相当于占位符
        String sql = "select name,pwd from admin where name= ? and pwd = ?";
        //3.2preparedStatement对象是实现了 PreparedStatement接口的 实现类的 对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //3.3给 ? 赋值
        preparedStatement.setString(1,admin_name);
        preparedStatement.setString(2,admin_pwd);

        //4.执行select语句使用 executeQuery
        // 如果执行的是dml(update,insert,delete)语句使用executeUpdate
        // 这里执行 executeQuery,不用再写sql进去了
        ResultSet resultSet = preparedStatement.executeQuery();
        if (resultSet.next()) {//如果查询到一条记录,则说明该管理员存在
            System.out.println("恭喜,登录成功");
        } else {
            System.out.println("对不起,登录失败");
        }

        //5.关闭连接
        resultSet.close();
        preparedStatement.close();
        connection.close();
    }
}
image-20221014190218693

5.1预处理DML

package li.jdbc.preparedstatement_;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Properties;
import java.util.Scanner;

//演示PreparedStatement的使用
@SuppressWarnings("all")
public class PreparedStatementDML_ {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);

        //让用户输入管理员的名字和密码
        System.out.print("请输入管理员的名字:");
        String admin_name = scanner.nextLine();
//        System.out.print("请输入管理员的密码:");
//        String admin_pwd = scanner.nextLine();

        //通过Properties对象拿到配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String url = properties.getProperty("url");
        String driver = properties.getProperty("driver");

        //1.注册驱动
        Class.forName(driver);
        //2.获取连接
        Connection connection = DriverManager.getConnection(url, user, password);
        //3.得到PreparedStatement对象
        //3.1组织SQL语句,sql语句的问号就相当于占位符
        //添加记录
        //String sql = "insert into admin values (?,?)";
        //更改
        //String sql = "update admin set pwd=? where name =?";
        //删除
        String sql = "delete from admin where name=?";

        //3.2preparedStatement对象是实现了 PreparedStatement接口的 实现类的 对象
        PreparedStatement preparedStatement = connection.prepareStatement(sql);
        //3.3给 ? 赋值
        preparedStatement.setString(1, admin_name);
        // preparedStatement.setString(2, admin_pwd);

        //4.执行dml(update,insert,delete)语句使用executeUpdate
        int rows = preparedStatement.executeUpdate();
        System.out.println(rows > 0 ? "执行成功" : "执行失败");

        //5.关闭连接
        preparedStatement.close();
        connection.close();
    }
}
image-20221014192148070
  • 练习

参考上面的代码

  1. 创建admin表
  2. 使用PreparedStatement添加5条数据
  3. 修改tom的记录,将name改成King
  4. 删除一条记录
  5. 查询全部记录,并显示在控制台

6.JDBC API

7.JDBCUtils开发

7.1封装JDBCUtils

  • 说明

在jdbc操作中,获取连接和释放资源是经常使用到的,可以将其封装为JDBC连接的工具类JDBCUtils

image-20221014213412387

例子

封装的工具类JDBCUtils:

package li.jdbc.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
 * 这是一个工具类,完成mysql的连接和关闭资源
 */
public class JDBCUtils {
    //定义相关的属性(4个),因为只需要一份,因此我们将其做成static属性
    private static String user;//用户名
    private static String password;//密码
    private static String url;//url
    private static String driver;//驱动名

    //在static代码块去初始化
    static {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream("src\\mysql.properties"));
            user = properties.getProperty("user");
            password = properties.getProperty("password");
            url = properties.getProperty("url");
            driver = properties.getProperty("driver");
        } catch (IOException e) {
            //在实际开发中往往会这样处理
            // 1.将 编译异常 转为 运行异常
            // 2.这时调用者可以选择捕获该异常,亦可以选择默认处理该异常,比较方便
            // (对于运行异常,程序中如果没有处理,默认就是throw的方式处理)
            throw new RuntimeException(e);
        }
    }

    //连接数据库,返回Connection
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            //将 编译异常 转为 运行异常,原因同上
            throw new RuntimeException(e);
        }
    }

    //关闭相关资源

    /**
     * 1.ResultSet 结果集
     * 2.Statement 或者 PreparedStatement
     * 3.Connection
     * 4.如果需要关闭资源,就传入对象,否则就传入null
     */
    //这里用Statement作为参数接收,是因为Statement是PreparedStatement的父接口,
    // 因此Statement参数既可以接收Statement的对象实现,也可以接收PreparedStatement类型的对象实现
    public static void close(ResultSet set, Statement statement, Connection connection) {
        //判断是否为null
        try {
            if (set != null) {
                set.close();
            }
            if (statement != null) {
                statement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            //将 编译异常 转为 运行异常,原因同上
            throw new RuntimeException(e);
        }
    }
}

使用测试JDBCUtils_Use:

package li.jdbc.utils;

import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

/**
 * 该类演示如何使用JDBCUtils工具类,完成 dml和 select
 */
public class JDBCUtils_Use {

    @Test
    public void testSelect() {//insert update delete
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql语句
        String sql = "Select * from actor";

        //3.创建PreparedStatement对象
        PreparedStatement preparedStatement = null;
        ResultSet set = null;
        try {
            connection = JDBCUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);

            //执行sql,得到结果集
            set = preparedStatement.executeQuery();
            //遍历该结果集
            while (set.next()) {
                int id = set.getInt("id");
                String name = set.getString("name");
                String sex = set.getString("sex");
                Date borndate = set.getDate("borndate");
                String phone = set.getString("phone");
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + borndate + "\t" + phone);
            }

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(set, preparedStatement, connection);
        }
    }

    @Test
    public void testDML() {//insert update delete
        //1.得到连接
        Connection connection = null;

        //2.组织一个sql语句
        String sql = "update actor set name=? where id=?";

        //3.创建PreparedStatement对象
        PreparedStatement preparedStatement = null;
        try {
            connection = JDBCUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            //给占位符赋值
            preparedStatement.setString(1, "周星星");//第1个占位符的值为周星星
            preparedStatement.setInt(2, 1);//第2个占位符的值为1
            //执行sql
            preparedStatement.executeUpdate();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //关闭资源
            JDBCUtils.close(null, preparedStatement, connection);
        }
    }
}

运行结果:

image-20221014222311448 image-20221014223453320 image-20221014222329046

标签:02,JDBC,java,String,import,PreparedStatement,sql,day46,properties
From: https://www.cnblogs.com/liyuelian/p/16793246.html

相关文章

  • Linux系统编程02-静态库
    库简单的看作可以直接拿来使用的代码仓库静态库在程序的链接阶段被复制到了程序中动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程......
  • vp训练 | 2022 江苏省赛 A C I J K L
    A.PENTAKILL!题意:给定一个击杀序列,死亡不影响连杀,问是否有人完成五杀分析:模拟,将每个选手的名字进行哈希,将属于每一个人的击杀序列处理出来,对每个人进行枚举判断即可ac......
  • 《Unix/Linux系统编程》第四章学习笔记 20201209戴骏
    第四章并发编程知识点归纳1、并行计算导论在早期,大多数计算机只有一个处理组件,称为处理器或中央处理器(CPU)。受这种硬件条件的限制,计算机程序通常是为串行计算编写的。......
  • 【闲话】2022.10.14
    今天的考试可算是寄大方了以及:已知T1时限6s,T2T3T4时限均为2s,且每道题都有100个数据点。现在有3页提交。请问Accoders什么时候会炸?真的有一说一,性能不如......
  • 2022.10.14
    今天是我写博客的第一天,首先最重要的就是团队,已经有380人啦,我们的公开赛依然在审核中,已经过去一周了还没有审核好,其次今天在学校里得知我下个星期就要跑1000米了,呜呜呜,而且......
  • 2022.10 杂题
    P8569[JRKSJR6]第七学区首先,有若干种\(O(n\logV)\)的暴力。我们选择其中操作比较简单的一种:对于每一位,先求出所有\(0\)段的长度之和,然后用所有区间的长度之和减掉......
  • PostgreSQL----运行02_insert_data
    ALTERTABLEdepartmentsALTERCONSTRAINTdept_mgr_fkDEFERRABLEINITIALLYDEFERRED;BEGIN;INSERTINTOdepartmentsVALUES(10,'Adminis......
  • 2022-10-14
    30F:三笔,中枢构筑中  5F:已经2中枢,有背驰迹象,预计30F一笔将结束  计划:1.如果再次冲高,可空30F一笔2.等30F回调一笔,小级别入场做多......
  • 2022-10-08 20:50:49 星期六
    感觉现在啥也不会了,洛谷的普及都要写甚久,有的还要需要看题解从csp-j出分并且知道自己这一次没有希望进普及到现在已经快半个月了感觉自己要是进了复赛也可能只是拿个二等奖......
  • 2022-2023-1 20201324《信息安全系统设计与实现(上)》第4章
    目录1并发计算导论(1)顺序算法与并行算法(2)并行性与并发性2线程(1)线程的原理(2)线程的优点(3)线程的缺点3线程操作4线程管理函数(1)创建线程(2)线程ID(3)线程终止(4)线程连接(5)用线程快......