JDBC p2 JDBC API

发布时间 2023-07-26 17:25:55作者: 凉白茶

JDBC API

获取数据库连接5种方式

  1. 通过new创建Driver对象;
  2. 使用反射加载Driver类,动态加载,减少依赖性,更加灵活;
  3. 使用DriverManager 替代 Driver 进行统一管理,有了更好的扩展性;
  4. 使用 Class.forName 自动完成注册驱动,简化代码;
  5. 在方式4的基础上改进,增加配置文件,让mysql连接更灵活,最推荐使用;

代码演示:

package com.hspedu.jdbc;

import com.mysql.jdbc.Driver;
import org.junit.jupiter.api.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 分析java连接mysql的5种方式
 */
public class JdbcConn {
    //方式1
    @Test
    public void connect01() throws SQLException {
        Driver driver = new Driver();
        String url = "jdbc:mysql://localhost:3306/jdbc_learning";
        Properties properties = new Properties();
        properties.setProperty("user", "root");//用户名
        properties.setProperty("password", "root");//密码
        Connection connection = driver.connect(url, properties);
        System.out.println("第一种方式" + connection);
        connection.close();
    }
    //方式2
    @Test
    public void connect02() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        //使用反射加载Driver类,动态加载,减少依赖性,更加灵活
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();

        String url = "jdbc:mysql://localhost:3306/jdbc_learning";
        Properties properties = new Properties();
        properties.setProperty("user", "root");//用户名
        properties.setProperty("password", "root");//密码
        Connection connection = driver.connect(url, properties);
        System.out.println("第二种方式" + connection);
        connection.close();
    }

    //方式3 使用DriverManager 替代 Driver 进行统一管理,有了更好的扩展性
    @Test
    public void connect03() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        //使用反射加载Driver类
        Class<?> aClass = Class.forName("com.mysql.jdbc.Driver");
        Driver driver = (Driver) aClass.newInstance();

        String url = "jdbc:mysql://localhost:3306/jdbc_learning";
        String user = "root";
        String password = "root";

        DriverManager.registerDriver(driver);//注册Driver驱动,DriverManager是Java自带的类

        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println("第三种方式" + connection);
    }

    //方式4 使用 Class.forName 自动完成注册驱动,简化代码
    //这种方式推荐使用,使用最多
    @Test
    public void connect04() throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException {
        //使用反射加载Driver类
        //在加载 Driver类时,完成注册
        /*
            源码:1. 静态代码块,在类加载时,会执行一次
                 2. 因此注册driver的工作在底层已经完成了
            static {
                        try {
                            DriverManager.registerDriver(new Driver());
                        } catch (SQLException var1) {
                            throw new RuntimeException("Can't register driver!");
                        }
                    }
         */
        //1.mysqL驱动5.1.6可以无需CLass.forName("com.mysql.jdbc.Driver");
        //2.从jdk1.5以后使用了jdbc4,不再需要显示调用class.forName()注册驱动而是自动调用驱动
        //jar包下META-INF\services\java.sql.Driver文本中的类名称去注册
        //3.建议还是写上CLass.forName("com.mysql.jdbc.Driver"),更加明确
        Class.forName("com.mysql.jdbc.Driver");//内部有一段静态代码会默认自动注册

        String url = "jdbc:mysql://localhost:3306/jdbc_learning";
        String user = "root";
        String password = "root";

        Connection connection = DriverManager.getConnection(url, user, password);
        System.out.println("第四种方式" + connection);
    }

    //方式5 在方式4的基础上改进,增加配置文件,让mysql连接更灵活,最推荐使用
    @Test
    public void connect05() throws IOException, ClassNotFoundException, SQLException {
        //通过Properties对象获取配置文件的信息
        Properties properties = new Properties();
        properties.load(new FileInputStream("src\\mysql.properties"));
        //获取相关的值
        String user = properties.getProperty("user");
        String password = properties.getProperty("password");
        String driver = properties.getProperty("driver");
        String url = properties.getProperty("url");

        Class.forName(driver);//建议写上

        Connection connection = DriverManager.getConnection(url, user, password);

        System.out.println("第五种方式" + connection);
    }
}

配置文件mysql.properties:

user=root
password=zyl
url=jdbc:mysql://localhost:3306/jdbc_learning
driver=com.mysql.jdbc.Driver

ResultSet[结果集]

  • 基本介绍

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

  • 代码演示:

    package com.hspedu.jdbc.resultset_;
    
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.sql.*;
    import java.util.Properties;
    
    /**
     * @author: 86199
     * @date: 2023/6/14 21:52
     * Description: 演示select 语句 返回 ResultSet,并取出结果
     */
    @SuppressWarnings({"all"})
    public class ResultSet_ {
        public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {
            //通过Properties对象获取配置文件的信息
            Properties properties = new Properties();
            properties.load(new FileInputStream("src\\mysql.properties"));
            //获取相关的值
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String driver = properties.getProperty("driver");
            String url = properties.getProperty("url");
    
            //1. 注册驱动
            Class.forName(driver);//建议写上
    
            //2. 得到连接
            Connection connection = DriverManager.getConnection(url, user, password);
    
            //3. 得到Statement
            Statement statement = connection.createStatement();
    
            //组织sql语句
            String sql = "select id, name, sex, borndate from actor;";
            /*
            1	周星驰	男	1970-11-11 00:00:00	110
            2	刘德华	男	1970-11-11 00:00:00	110
            3	刘德华	男	1970-11-11 00:00:00	110
             */
            //执行给定的SQL语句,该语句返回单个ResultSet对象
            /*
                源码:
             */
            ResultSet resultSet = statement.executeQuery(sql);
    
            while (resultSet.next()) {//让光标后移,如果没有更多行,则返回false
                int id = resultSet.getInt(1);//获取该行的第1列
                String name = resultSet.getString(2);//获取该行的第2列
                String sex = resultSet.getString(3);
                String date = resultSet.getString(4);
                System.out.println(id + "\t" + name + "\t" + sex + "\t" + date);
            }
    
    
            //关闭资源
            resultSet.close();
            statement.close();
            connection.close();
        }
    }
    
    
  
  



## Statement对象

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

**MySQL代码:**

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

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

-- 查找某个管理员是否存在
SELECT * 
FROM admin
WHERE `name` = 'tom' AND pwd = '123';

-- SQL注入
-- 输入用户名 1' or
-- 输入密码 为 or '1' = '1
-- SELECT * 
-- FROM admin
-- WHERE `name` = '' AND pwd = '';

SELECT * 
FROM admin
WHERE `name` = '1' or' AND pwd = 'or '1' = '1';

Java代码:

package com.hspedu.jdbc.statement_;

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

/**
 * @author: 86199
 * @date: 2023/6/15 22:24
 * Description: 演示 SQL注入的问题
 */
public class Statement_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {

        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 driver = properties.getProperty("driver");
        String url = properties.getProperty("url");

        //1. 注册驱动
        Class.forName(driver);//建议写上

        //2. 得到连接
        Connection connection = DriverManager.getConnection(url, user, password);

        //3. 得到Statement
        Statement statement = connection.createStatement();

        //组织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("对不起,登录失败");
        }

        resultSet.close();
        statement.close();
        connection.close();
    }
}

//运行
/*
请输入管理员名字:1' or
请输入管理员密码:or '1' = '1
恭喜,登录成功
*/

预处理(查询和修改)

  1. PreparedStatement 执行的SQL语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数。setXxx() 方法有两个参数,第一个参数都是int,要设置SQL语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值。
  2. 调用 executeQuery(),返回 ResultSet 对象。
  3. 调用 executeUpdate():执行更新,包括增,删,修改
package com.hspedu.jdbc.preparedstatement_;

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

/**
 * @author: 86199
 * @date: 2023/7/17 20:43
 * Description: 演示PreparedStatement使用
 */
public class PreparedStatement_ {
    public static void main(String[] args) throws IOException, ClassNotFoundException, SQLException {

        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 driver = properties.getProperty("driver");
        String url = properties.getProperty("url");

        //1. 注册驱动
        Class.forName(driver);//建议写上

        //2. 得到连接
        Connection connection = DriverManager.getConnection(url, user, password);


        //sql中的?就相当于占位符
        String sql = "SELECT name, pwd FROM admin where name =  ? and pwd = ? ;";

        //3. 得到PreparedStatement,这里的statement是实现了PreparedStatement接口的实现类的对象
        PreparedStatement statement = connection.prepareStatement(sql);

        //给 ? 赋值
        statement.setString(1, admin_name);
        statement.setString(2, admin_pwd);

        //执行sql语句,如果执行的是dml语句要用executeUpdate()
        ResultSet resultSet = statement.executeQuery();//()中不能再写sql语句,不然执行的就是带?的,填了sql语句就是调用了父类Statement的方法了

        if (resultSet.next()) {//如果查询到一条记录,说明该管理员存在
            System.out.println("恭喜,登录成功");
        }else{
            System.out.println("对不起,登录失败");
        }

        //关闭链接
        resultSet.close();
        statement.close();
        connection.close();
    }
}
//运行
/*
请输入管理员名字:1' or
请输入管理员密码:or '1' = '1
对不起,登录失败

*/