Bootstrap

MySQL(三) JDBC数据库连接

十、JDBC

1、问题描述
将来我们写sql语句,不能在数据库中写,我们应该将sql语句放到java代码中参与运行,但是sql语句和Java语言是两个不同的语言,所有想要将sql语句放到Java中运行需要用到特定的API

2、JDBC:是一堆接口,是Java操作数据库的标准
步骤
1、导入jdbc的jar包
mysql-connection-java-8.0.25

2、jdbc的核心类
    a、DriverManager:驱动类,注册驱动使用
    b、Connection接口:连接数据库
    c、Statement接口:执行平台,执行sql语句
    d、ResultSet接口:处理结果集-->只针对查询操作

1、开发步骤

1、注册驱动:DriverManager类
    指明我们操作的是哪款数据库

2、获取连接:Connection接口 ->获取连接对象,连接数据库
    a:DriverManager中的方法
        static Connection getConnection(String Url,String User,String password)   获取连接
    b、参数:
        url:指明我门要操作的哪个数据库(地址)
        user:用户
        password:数据库密码

3、准备sql---->sql语句(insert、update、delete)

4、获取执行平台  --->  Statement接口---->执行sql语句
    a、获取:用到的是Connection中的方法  --->  Statement CreateStatement();
    b、
5、执行sql-->Statement接口中的方法
    a、int executeUpdate(String sql) --->增删改操作
    b、ResultSet executeQuery(String sql)---->查询操作,返回的是结果集

6、处理结果 --->ResultSet接口
    boolean next();---->判断结果集中有没有下一个数据

7、关闭资源
    a、关闭结果集:ResultSet
    b、关闭执行平台:Statement
    c、关闭连接对象:Connection

2、JDBC具体流程

创建数据库
CREATE TABLE `user`(
  uid INT PRIMARY KEY AUTO_INCREMENT,
  username VARCHAR(20),
  `password` VARCHAR(20)
);


1、注册驱动:Drivermanafer类
    static void registerDriver(Driver driver)
    a、参数:Driver接口
        需要传递Driver接口实现类的对象,但是在API文档上没有体现Driver的实现类
        所以需要传递mysql核心jar包中的Driver类,此类在com.mysql.cj.jdbc包小,
        此类实现了java.sql.Driver接口
    注意:
    当new com.mysql.cj.jdbc.Driver是底层有一个静态代码块
    在静态代码块中写一个DriverManager.registerDriver(new Driver());
    也就意味着,如果我们使用DriverManager.registerDriver(new Driver());注册驱动
    到最后我们就直接注册了两次,没必要

    解决办法:统一用反射技术,获取Driver的class对象
    Class.forName("com.mysql.cj.jdbc.Driver");
2.获取连接:DriverManager类中的方法
           static Connection getConnection(String url, String user, String password):获取
            连接
                 url:指明我们操作的是哪个库,写的是库的url(地址)
                     jdbc:mysql://localhost:3306/数据库名字?参数1&参数2
                 user:指明数据库的用户名
                 password:指明数据库的密码

        String url = "jdbc:mysql://localhost:3306/230417_java3";
        String user = "root";
        String password = "root";
        Connection connection = DriverManager.getConnection(url,user,password);
        System.out.println(connection);

常见问题:

3、JDBC实现增删改

@Test
    public void insert() throws Exception{
        /**
         * 1、注册驱动:DriverManager类
         */
        Class.forName("com.mysql.cj.jdbc.Driver");

        /**
         * 2、获取连接:DriverManager类中的方法
         */
        String url="jdbc:mysql://localhost:3306/java_JDBC";
        String user="root";
        String passwod="123456";
        Connection connection = DriverManager.getConnection(url,user,passwod);

        /**
         * 3、准备sql
         */
        String sql="insert into user (username,password) values ('zhangsan','123456')";

        /**
         * 4、获取执行平台:Statement接口 -> 执行sql语句
         *      用到的是Connection中的方法
         *      Statement createStatement()
         */
        Statement statement = connection.createStatement();

        /**
         * 5、执行sql:Statement接口中的方法
         *      int executeUpdate(String sql) -> 针对于增删改操作
         */
        int i=statement.executeUpdate(sql);

        /**
         * 6、处理结果集合,但是增删改查不需要处理结果集
         */

        /**
         * 7、关闭资源
         */
        statement.close();
        connection.close();

    }

4、JDBC实现查询操作

1.Statement中的方法:
  ResultSet executeQuery(String sql)->专门针对于查询
2.处理结果集
  a.方法:boolean next()  -> 判断结果集中有没有下一个数据
  b.获取:
    int getInt(int columnIndex)-> 获取第几列的数据  -> 获取int型列的数据 
    int getInt(String columnLabel) -> 获取指定列名的数据,写列名 -> 获取int型列的数据 
        
    String getString(int columnIndex)-> 获取第几列的数据
    String getString(String columnLabel)-> 获取指定列名的数据,写列名  
        
    Object getObject(int columnIndex)-> 获取第几列的数据   
    Object getObject(String columnLabel)-> 获取指定列名的数据,写列名 
@Test
    public void query() throws Exception{

        //1、注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2、获取连接
        String url="jdbc:mysql://localhost:3306/java_JDBC";
        String user="root";
        String passwod="123456";
        Connection connection = DriverManager.getConnection(url, user, passwod);
        //3、准备sql
        String sql="select * from user";
        //4、获取执行平台
        Statement statement = connection.createStatement();
        //5、执行sql
        ResultSet rs = statement.executeQuery(sql);
        //6、处理结果集
        while (rs.next()){    //获取下一行
            int uid=rs.getInt(1);
            String username = rs.getString("username");
            String password = rs.getString(3);  //获取第3列的数据
            System.out.println(uid);
            System.out.println(username);
            System.out.println(password);
        }
        //7、关闭资源
        rs.close();
        statement.close();
        connection.close();

    }

5、封装工具类

package com.java.utils;

import java.sql.*;

public class JDBCUtils {

    //将静态变量定义在类种,声明周期是与类相同的,如果定义在静态代码块中,只能在静态代码块中使用,属于局部变量
    private static String url=null;
    private static String user=null;
    private static String passwod=null;

    //定义在静态代码块中,优先main数据加载,且只加载一次
    static {

        //1、注册驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2、获取连接
            //初始化静态变量
            url="jdbc:mysql://localhost:3306/java_JDBC";
            user="root";
            passwod="123456";
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }


    //获取连接
    public static Connection getConnection(){

        //try-catch中的对象作用域只能在内部使用,所以需要在外部进行创建对象
        Connection connection=null;
        //由于url, user, passwod是定义在静态代码块中,在静态方法中无法调用,因此先定义在静态变量,通过静态代码块进行赋值,才能被静态方法进行调用
        try {
            connection = DriverManager.getConnection(url, user, passwod);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return connection;

    }

    //关闭资源
    public static void Close(Connection connection, Statement statement, ResultSet resultSet){

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


}
@Test
    public void insert1() throws Exception{
        /**
         * 1、注册驱动:DriverManager类
         */

        /**
         * 2、获取连接:DriverManager类中的方法
         */
        Connection connection = JDBCUtils.getConnection();
        /**
         * 3、准备sql
         */
        String sql="insert into user (username,password) values ('lisi','123123')";

        /**
         * 4、获取执行平台:Statement接口 -> 执行sql语句
         *      用到的是Connection中的方法
         *      Statement createStatement()
         */
        Statement statement = connection.createStatement();

        /**
         * 5、执行sql:Statement接口中的方法
         *      int executeUpdate(String sql) -> 针对于增删改操作
         */
        int i=statement.executeUpdate(sql);

        /**
         * 6、处理结果集合,但是增删改查不需要处理结果集
         */

        /**
         * 7、关闭资源
         */
        JDBCUtils.Close(connection,statement,null);

    }

6、获取最新添加的数据的id

1、格式
    select last_insert_id()

2、注意:
    a、获取最新加载数据id时,id需要主键增长
    b、获取最新添加数据id时,添加的最新数据的id列不要自己指定添加,需要依靠自增去自动维护

7、PreparedStatement预处理对象

登录案例

package com.java;

import com.java.utils.JDBCUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

public class Demo02_JDBC {

    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        //采用nextLine是用于存放一行String类型数据时能够点击空格输入,
        // 如果是next()则无法进行输入空格,点击空格自行结束输入
        String username = scanner.nextLine();
        System.out.println("请输入密码:");
        String password=scanner.nextLine();

        Connection connection = JDBCUtils.getConnection();
        String sql="select * from user where username= '"+username+"'and password= '"+password+"'";
        System.out.println(sql);

        Statement statement = connection.createStatement();

        ResultSet resultSet = statement.executeQuery(sql);

        //只能查看一个数据,如果是有数据则进行判空操作判断是否登录成功
        if(resultSet.next()){
            System.out.println("登录成功!");
        }else {
            System.out.println("登录失败!");
        }

        JDBCUtils.Close(connection,statement,resultSet);

    }
}
(1)sql注入
密码输入:111' or '1' = '1  以上程序不行了->sql注入
因为:' or '1' = '1恒为真
(2)使用预处理对象(PreparedStatement)实现操作
1.概述:
  PreparedStatement接口 继承  Statement接口
2.获取:Connection中的方法
       PreparedStatement prepareStatement(String sql) 
3.特点:
  写sql语句的时候支持在sql中写占位符   ?
      
4.为?赋值:
  void setObject(int parameterIndex, Object x)
                 parameterIndex:代表的是第几个?
                 x:为指定?赋的值
                     
5.执行sql方法:
  int executeUpdate() -> 针对增删改
  ResultSet executeQuery() -> 针对查询    
package com.java;

import com.java.utils.JDBCUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;

public class Demo03_JDBC {

    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        //采用nextLine是用于存放一行String类型数据时能够点击空格输入,
        // 如果是next()则无法进行输入空格,点击空格自行结束输入
        String username = scanner.nextLine();
        System.out.println("请输入密码:");
        String password=scanner.nextLine();

        Connection connection = JDBCUtils.getConnection();
        String sql="select * from user where username=? and password =?";
        System.out.println(sql);

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        //为?赋值
        preparedStatement.setObject(1,username);
        preparedStatement.setObject(2,password);

        ResultSet resultSet = preparedStatement.executeQuery();

        //只能查看一个数据,如果是有数据则进行判空操作判断是否登录成功
        if(resultSet.next()){
            System.out.println("登录成功!");
        }else {
            System.out.println("登录失败!");
        }

        JDBCUtils.Close(connection,preparedStatement,resultSet);

    }
}
(3)JDBC工具类结合Properties文件
创建资源路径

编写配置文件

driverclass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/java_JDBC
username=root
password=123456
编写工具类
package com.java.utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBCUtils1 {

    //将静态变量定义在类种,声明周期是与类相同的,如果定义在静态代码块中,只能在静态代码块中使用,属于局部变量
    private static String url=null;
    private static String user=null;
    private static String passwod=null;

    //定义在静态代码块中,优先main数据加载,且只加载一次
    static {

        //1、注册驱动
        try {
            Properties properties=new Properties();
            //文件加载
            InputStream in = JDBCUtils1.class.getClassLoader().getResourceAsStream("jdbc.properties");
            properties.load(in);

            Class.forName(properties.getProperty("driverclass"));
            url=properties.getProperty("url");
            user=properties.getProperty("username");
            passwod=properties.getProperty("password");
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    //获取连接
    public static Connection getConnection(){

        //try-catch中的对象作用域只能在内部使用,所以需要在外部进行创建对象
        Connection connection=null;
        //由于url, user, passwod是定义在静态代码块中,在静态方法中无法调用,因此先定义在静态变量,通过静态代码块进行赋值,才能被静态方法进行调用
        try {
            connection = DriverManager.getConnection(url, user, passwod);
        } catch (SQLException e) {
            e.printStackTrace();
        }

        return connection;

    }

    //关闭资源
    public static void Close(Connection connection, Statement statement, ResultSet resultSet){

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


}
测试
@Test
    public void insert2() throws Exception{
        /**
         * 1、注册驱动:DriverManager类
         */

        /**
         * 2、获取连接:DriverManager类中的方法
         */
        Connection connection = JDBCUtils1.getConnection();
        /**
         * 3、准备sql
         */
        String sql="insert into user (username,password) values (?,?)";

        /**
         * 4、获取执行平台:Statement接口 -> 执行sql语句
         *      用到的是Connection中的方法
         *      Statement createStatement()
         *
         *      PreparedStatement接口 继承  Statement接口
         *      Connection中的方法
         *        PreparedStatement prepareStatement(String sql)
         */
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        /**
         * 5、执行sql:Statement接口中的方法
         *      int executeUpdate(String sql) -> 针对于增删改操作
         *
         *      设置?占位符中的字段值
         */

        preparedStatement.setObject(1,"王五");
        preparedStatement.setObject(2,"111222");

        int i=preparedStatement.executeUpdate();

        /**
         * 6、处理结果集合,但是增删改查不需要处理结果集
         */

        /**
         * 7、关闭资源
         */
        JDBCUtils1.Close(connection,preparedStatement,null);

    }

;