JDBC回顾

1.JDBC

1.JDBC入门

概念

Java Data Base Connectivity(JDBC):Java数据库连接

作用:通过JDBC可以让Java程序操作数据库

本质:官方定义一套用来操作关系型数据库的规则(接口),而各数据库的厂商为了实现这个接口,就会提供各自的驱动jar包,我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

(简单的理解就是添加对应得jar才能连接对应得数据库)

JDBC得由来

1.直接写代码操作数据库

在这里插入图片描述

直接写代码操作数据库存在的问题:

  1. 不知道MySQL数据库的操作⽅式,解析⽅式

  2. 代码繁琐,写起来麻烦

  3. MySQL和Oracle等其他数据库的操作⽅式和解析⽅式不同,每个数据库都要写⼀套代码

  4. MySQL和Oracle等其他数据库相互切换麻烦

  5. JDBC规范定义接⼝,具体的实现由各⼤数据库⼚商来实现 JDBC是Java访问数据库的标准规范。真 正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库⼚商根据⾃家数据库的通 信格式编写好⾃⼰数据库的驱动。所以我们只需要会调⽤JDBC接⼝中的⽅法即可。数据库驱动由 数据库⼚商提供。

在这里插入图片描述

JDBC得好处

  1. 我们只需要会调用JDBC接口方法即可,使用简单
  2. 使用同一套java代码,进行少量得修改就可以访问其他得JDBC支持得数据库

JDBC得四个核心对象

DriverManager用于注册驱动 PS:需要注册驱动才能让JDBC跑起来,因为会自动注册
Connection表示数据库的连接 PS:我的理解就是类似于socket 开启管道使得Java程序连接数据库
Statement执行SQL语句的对象 PS:理解成一个小敞篷小货车,把要执行的sql语句运送到数据库
ResultSet结果集或一张虚拟表 PS:接受和保存数据库传回来的数据

JDBC使用步骤

  1. 注册驱动
  2. 获取连接
  3. 获取SQL语句对象
  4. 执行SQL语句并返回结果
  5. 处理结果
  6. 释放资源

代码如下

package com.xjggb.demo;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class Demo01 {
    public static void main(String[] args) throws SQLException {

        //注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());

        //获取连接
        Connection connection = DriverManager.getConnection(
                "jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8",
                "root",
                "root");

        //获取敞篷小火车
        Statement statement = connection.createStatement();


        //Sql语句
        String sql ="SELECT * FROM `user`";

        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            int user_id = resultSet.getInt("user_id");
            String age = resultSet.getString("age");
            String name = resultSet.getString("name");
            String pwd = resultSet.getString("pwd");
            System.out.println("age = " + age);
             System.out.println("user_id = " + user_id);
            System.out.println("name = " + name);
             System.out.println("pwd = " + pwd);
            


        }
        //释放资源
        resultSet.close();
        statement.close();
        connection.close();



    }
}

注意事项

如果数据出现乱码需要加上参数: ?characterEncoding=utf8,表示让数据库以UTF-8编码来处理数

据。 如: jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8

注册驱动

我们Java程序需要通过数据库驱动才能连接到数据库,因此需要注册驱动。 MySQL的驱动的⼊⼝类

是: com.mysql.jdbc.Driver

在这里插入图片描述

java.sql.DriverManager 类⽤于注册驱动。提供如下⽅法注册驱动

public class Demo01 {
    public static void main(String[] args) throws SQLException {

        //注册驱动
     DriverManager.registerDriver(new com.mysql.jdbc.Driver());


    }
}

通过查询com.mysql.jdbc.Driver源码,我们发现Driver类“主动”将⾃⼰进⾏注册

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            //自己注册
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

在这里插入图片描述

在这里插入图片描述

注意:

使⽤ DriverManager.registerDriver(new com.mysql.jdbc.Driver()); ,存在两⽅⾯不⾜

  1. 硬编码,后期不易维护扩展程序和维护
  2. 驱动被注册两次

使⽤ Class.forName(“com.mysql.jdbc.Driver”); 加载驱动,这样驱动只会注册⼀次

package com.xjggb.demo;

import java.sql.*;

public class Demo02 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {


        //注册驱动
            Class.forName("com.mysql.jdbc.Driver");


        //获取连接
        Connection connection = DriverManager.getConnection(
                "jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8",
                "root",
                "root");


        //获取连接敞篷小火车
        Statement statement = connection.createStatement();


        //Sql语句
        String sql ="SELECT * FROM `user`";

        ResultSet resultSet = statement.executeQuery(sql);

        while (resultSet.next()){
            int user_id = resultSet.getInt("user_id");
            String age = resultSet.getString("age");
            String name = resultSet.getString("name");
            String pwd = resultSet.getString("pwd");
            System.out.println("age = " + age);


        }
        //释放资源
        resultSet.close();
        statement.close();
        connection.close();



    }
}

2.JDBC实现对单表数据得CRUD

准备数据

-- 创建分类表
CREATE TABLE category (
 cid INT PRIMARY KEY AUTO_INCREMENT,
 cname VARCHAR(100)
);
-- 初始化数据
INSERT INTO category (cname) VALUES('家电');
INSERT INTO category (cname) VALUES('服饰');
INSERT INTO category (cname) VALUES('化妆品');

获取Statement对象API介绍

boolean execute(String sql)
此⽅法可以执⾏任意sql语句。返回boolean值,表示是否返回ResultSet结果集。仅当执⾏
select语句,且有返回结果时返回true, 其它语句都返回false;
int executeUpdate(String sql)
根据执⾏的DML(INSERT、UPDATE、DELETE)语句,返回受影响的⾏数
ResultSet executeQuery(String sql)
根据查询语句返回结果集,只能执⾏SELECT语句

小结:

  1. executeUpdate :用于删除 ,更新,插入
  2. executeQuery :用于查询

代码如下

package com.xjggb.demo;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class Demo01 {
    public static void main(String[] args) throws SQLException {

        //注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());

        //获取连接
        Connection connection = DriverManager.getConnection(
                "jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8",
                "root",
                "root");

        //获取敞篷小火车
        Statement statement = connection.createStatement();


        //定义sql
        String sql="";

        //插入记录
        sql="INSERT INTO category (cname) VALUES ('⼿机');";
        int i = statement.executeUpdate(sql);
        System.out.println("插入影响得行数" + i);



        //修改记录
        sql="UPDATE category SET cname='汽⻋' WHERE cid=4;";

        int i1 = statement.executeUpdate(sql);
        System.out.println("返回更新得行数 " + i1);


        sql="delete from category where  cid=1";
        int i2 = statement.executeUpdate(sql);
        System.out.println("返回删除得行数 " + i1);


        //释放资源
        statement.close();
        connection.close();
    }
}


使⽤JDBC查询数据库中的数据的步骤

  1. 注册驱动
  2. 获取连接
  3. 获取到Statement
  4. 使⽤Statement执⾏SQL
  5. ResultSet处理结果
  6. 关闭资源
package com.xjggb.demo;

import com.mysql.jdbc.Driver;

import java.sql.*;

public class Demo01 {
    public static void main(String[] args) throws SQLException {

        //注册驱动
        DriverManager.registerDriver(new com.mysql.jdbc.Driver());

        //获取连接
        Connection connection = DriverManager.getConnection(
                "jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8",
                "root",
                "root");

        //获取敞篷小火车
        Statement statement = connection.createStatement();


        ResultSet resultSet = statement.executeQuery("SELECT * FROM category;");

        while (resultSet.next()){
            int cid = resultSet.getInt("cid");
            String cname = resultSet.getString("cname");

            System.out.println("cname+\"===\"+cid = " + cname+"==="+cid);

        }


        //释放资源
        resultSet.close();
        statement.close();
        connection.close();
    }
}


数据类型得转换

在这里插入图片描述

小结,

使用jdbc操作数据库得步骤:

  1. 注册驱动
  2. 获取连接
  3. 获取小火车
  4. 执行增删改查
  5. 释放资源

3.jdbc工具类

工具类是为了解放双手,封装繁琐得代码

定义一个JDBCUtils类。把注册驱动,获取连接,得到Statement,以及释放资源的代码放到这个类的方法中。以后直接调用方法即可

package com.xjggb.utils;

import java.sql.*;

public class JDBCUtils {
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final   String URL="jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8";
    private static final  String USERNAME="root";
    private static final  String PASSWORD="root";

    // 2.在静态代码块中注册驱动(只注册一次)
    // 当这个类加载到内存的时候就走这个静态代码块,再去触发Driver类中的静态代码块,主动注册
    //尝试过了可以不写自动注册
    static {
        try {
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {}
    }

    // 2.提供一个获取连接的方法`static Connection getConneciton();`
    // 谁使用谁处理异常, 这个方法把连接返回给别人使用,有问题也抛给他处理
    public static Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);

        return connection;

    }

    // 3.定义关闭资源的方法`close(Connection conn, Statement stmt, ResultSet rs)`
    // 谁使用谁处理异常, 其他地方调用close会传入 conn, stmt, rs给我们使用.就处理异常

    public static void close(Connection conn, 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 (conn!=null) {
             try {
                 conn.close();
             } catch (SQLException throwables) {
                 throwables.printStackTrace();
             }
         }


         }

    // 4.重载关闭方法`close(Connection conn, Statement stmt)`
    public static void close(Connection conn, Statement statement)  {
      close(conn,statement);

    }





}


小结

编写jdbc得目的是什么?

简化JDBC得代码

4.JDBC登录案例

案例分析

  1. 使用数据库保存用户得账号和密码
  2. 让用户输入账号和密码
  3. 使用SQL根据用户的账号和密码去数据库查询数据
  4. 如果查询到数据,说明登录成功
  5. 如果查询不到数据,说明登录失败

添加数据

CREATE TABLE USER (
  id INT AUTO_INCREMENT PRIMARY KEY,
  NAME VARCHAR(50),
  PASSWORD VARCHAR(50)
);
INSERT INTO USER (NAME, PASSWORD) VALUES('admin', '123'), ('test', '123'), ('gm', '123');

代码如下

package com.xjggb.demo;

import com.xjggb.utils.JDBCUtils;

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

public class Demo04 {
    public static void main(String[] args) throws SQLException {

        //让用户输入账号和密码

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入账号");
        String name = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();


        //获取连接
        Connection connection = JDBCUtils.getConnection();

        //获取敞篷小火车
        Statement statement = connection.createStatement();

        //定义sql
        String sql = "SELECT * FROM USER1 WHERE name='" + name + "' AND password='" + password + "';";

        ResultSet resultSet = statement.executeQuery(sql);

        if (resultSet.next()) {
            //能进来查询到了数据.
            String name2 = resultSet.getString("name");
            System.out.println("欢迎您," + name2);
        } else {
            //查询不到数据,说明登录失败
            System.out.println("账号或密码错误...");
        }

        //关闭资源
        JDBCUtils.close(connection,statement,resultSet);


    }
}


5.sql注入介绍

SQL注入问题

在我们前面JDBC实现登录案例中,当我们输入以下密码,我们发现我们账号和密码都不对竟然登录成功了

请输入用户名:
hehe
请输入密码:
a'or'1'='1

问题分析:

// 代码中的SQL语句
"SELECT * FROM USER1 WHERE name='" + name + "' AND password='" + password + "';";
// 将用户输入的账号密码拼接后
"SELECT * FROM USER1 WHERE name='hehe' AND password='a'or'1'='1';"

我们让用户输入的密码和SQL语句进行字符串拼接。用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义,以上问题称为SQL注入。

要解决SQL注入就不能让用户输入的密码和我们的SQL语句进行简单的字符串拼接。需要使用PreparedSatement类解决SQL注入。

小结:

什么是sql注入?

用户输入得内容和SQL语句拼接改变了SQL语句原本得含义

任何人都可以直接登录,主要是a’or’1’=’1的原因 ,or导致了数据库对传输进来的sql语句判断为true(or语句只要有一边为ture就都是true),则会判断账户以及密码比对正确,就会成功登录

6.PreparedStatement预编译对象

解决SQL注入

为了避免这种情况的发生,Statement就被我们淘汰了,我们使用子接口PreparedStatement

PreparedStatement预编译执行者对象

预编译:SQL语句在执行前就已经编译好了,执行速度更快。
​ 安全性更高:没有字符串拼接的SQL语句,所以避免SQL注入的问题
​ 代码的可读性更好,因为没有字符串拼接

PreparedStatement使用

SQL语句中的参数使用?作为占位符
​ 给?占位符赋值

设置参数

setXxx(参数1,参数2); Xxx代表:数据类型
​ 参数1:第几个? (编号从1开始)
​ 参数2:?的实际参数

执行SQL语句

int executeUpdate(); 执行insert、update、delete语句
​ ResultSet executeQuery(); 执行select语句

1.入门案例解决SQL注入问题
package com.xjggb.demo;

import com.xjggb.utils.JDBCUtils;

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

public class Demo04 {
    public static void main(String[] args) throws SQLException {

        //让用户输入账号和密码

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入账号");
        String na = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();


        //获取连接
        Connection connection = JDBCUtils.getConnection();

        //定义sql
        String sql = "SELECT * FROM USER1 WHERE name= ? AND password= ?;";
        // prepareStatement()会先将SQL语句发送给数据库预编译。
        PreparedStatement ps = connection.prepareStatement(sql);

        ps.setString(1,na);
        ps.setString(2,password);

        ResultSet resultSet = ps.executeQuery();

        if (resultSet.next()) {
            String name = resultSet.getString("name");
            System.out.println("name:" + name);
        } else {
            System.out.println("没有找到数据...");
        }

        //关闭资源
        JDBCUtils.close(connection,ps,resultSet);


    }
}


2.PreparedStatement的API介绍

继承结构

Statement
↑ 继承
PreparedStatement

获取PreparedStatement

java.sql.Connection有获取PreparedSatement对象的方法

java.sql.PreparedStatement中有设置SQL语句参数,和执行参数化的SQL语句的方法

  1. void setDouble(int parameterIndex, double x) 将指定参数设置为给定 Java double 值。
    
    
  2. void setFloat(int parameterIndex, float x) 将指定参数设置为给定 Java REAL 值。 
    
    
  3. void setInt(int parameterIndex, int x) 将指定参数设置为给定 Java int 值。
    
    
  4. void setLong(int parameterIndex, long x) 将指定参数设置为给定 Java long 值。 
    
    
  5. void setObject(int parameterIndex, Object x) 使用给定对象设置指定参数的值。  
    
    
  6. void setString(int parameterIndex, String x) 将指定参数设置为给定 Java String 值。 
    
    
  7. ResultSet executeQuery() 
    在此 PreparedStatement 对象中执行 SQL 查询,并返回该查询生成的ResultSet对象。 
    
    
  8. int executeUpdate() 
    在此 PreparedStatement 对象中执行 SQL 语句,该语句必须是一个 SQL 数据操作语言DML语句,比如 INSERT、UPDATE 或 DELETE 语句;或者是无返回内容的 SQL 语句,比如 DDL 语句。 
    
    

小结:

PreparedSatement如何设置?的参数

setXxx(第几个问号, 问号的值);

3.PreparedStatement实现增删改

1.创建表

CREATE TABLE employee (
  id INT PRIMARY KEY AUTO_INCREMENT,
  NAME VARCHAR(20),
  age INT,
  address VARCHAR(50)
);

2.添加数据

package com.xjggb.demo01;

import com.xjggb.utils.JDBCUtils;

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

public class Demo01 {
    public static void main(String[] args) throws SQLException {


        //获取连接
        Connection connection = JDBCUtils.getConnection();

        //设置SQL
        String sql=" insert into employee values (null ,?,?,?) ";
        PreparedStatement pstmt = connection.prepareStatement(sql);


        // 设置参数
        pstmt.setString(1, "刘德华");
        pstmt.setInt(2, 57);
        pstmt.setString(3, "香港");
        int i = pstmt.executeUpdate();
        System.out.println("影响的行数:" + i);




        // 再次设置参数
        pstmt.setString(1, "张学友");
        pstmt.setInt(2, 55);
        pstmt.setString(3, "澳门");
        i = pstmt.executeUpdate();
        System.out.println("影响的行数:" + i);

        // 再次设置参数
        pstmt.setString(1, "黎明");
        pstmt.setInt(2, 52);
        pstmt.setString(3, "香港");
        i = pstmt.executeUpdate();
        System.out.println("影响的行数:" + i);


        //关闭资源

        JDBCUtils.close(connection,pstmt);





    }
}


3.修改数据

package com.xjggb.demo01;

import com.xjggb.utils.JDBCUtils;

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

public class Demo02 {
    public static void main(String[] args) throws SQLException {

        //获取连接
        Connection connection = JDBCUtils.getConnection();
        //设置sql
        String sql = "UPDATE employee SET address=? WHERE id=?;";

        //获取连接小火车
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        preparedStatement.setString(1,"台湾");
        preparedStatement.setInt(2, 4);

        int i = preparedStatement.executeUpdate();
        System.out.println("更新影响得行数 " + i);

        JDBCUtils.close(connection,preparedStatement);


    }
}


4.删除数据

package com.xjggb.demo01;

import com.xjggb.utils.JDBCUtils;

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

public class Demo03 {

    //删除数据
    public static void main(String[] args) throws SQLException {
        //获取连接
        Connection connection = JDBCUtils.getConnection();

        //添加SQL
        String sql= "delete from employee where id=?";

        PreparedStatement statement = connection.prepareStatement(sql);

        statement.setInt(1,3);

        int i = statement.executeUpdate();
        System.out.println("删除影响得行数" + i);


        //关闭资源
        JDBCUtils.close(connection,statement);


    }
}


5.查询

package com.xjggb.demo;

import com.xjggb.utils.JDBCUtils;

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

public class Demo04 {
    public static void main(String[] args) throws SQLException {

        //让用户输入账号和密码

        Scanner sc = new Scanner(System.in);
        System.out.println("请输入账号");
        String na = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();


        //获取连接
        Connection connection = JDBCUtils.getConnection();

        //定义sql
        String sql = "SELECT * FROM USER1 WHERE name= ? AND password= ?;";
        // prepareStatement()会先将SQL语句发送给数据库预编译。
        PreparedStatement ps = connection.prepareStatement(sql);

        ps.setString(1,na);
        ps.setString(2,password);

        ResultSet resultSet = ps.executeQuery();

        if (resultSet.next()) {
            String name = resultSet.getString("name");
            System.out.println("name:" + name);
        } else {
            System.out.println("没有找到数据...");
        }

        //关闭资源
        JDBCUtils.close(connection,ps,resultSet);


    }
}


小结:

PreparedSatement使用步骤

  1. 编写SQL语句,未知内容使用?占位
  2. 获得PreparedStatement对象
  3. 设置实际参数
  4. 执行参数化SQL语句
  5. 关闭资源

将SQL语句不确定的值使用?先占位,然后使用PreparedStatement处理,没有SQL注入

7.JDBC事务

1.准备数据

CREATE TABLE account (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('张三', 1000), ('李四', 1000);

2.API介绍

Connection接口中与事务有关的方法

  1. void setAutoCommit(boolean autoCommit) throws SQLException;
    false:开启事务, ture:关闭事务
    
    
  2. void commit() throws SQLException;
    提交事务
    
    
  3. void rollback() throws SQLException;
    回滚事务使用步骤
    
    

3.使用步骤

  1. 注册驱动
  2. 获取连接
  3. 开启事务
  4. 获取 到Statement
  5. Statement 执行sql
  6. 提交或者回滚事务
  7. 关闭资源
package com.xjggb.demo01;

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

public class Demo04 {
    private static final   String URL="jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8";
    private static final  String USERNAME="root";
    private static final  String PASSWORD="root";
    public static void main(String[] args) {



        Connection conn = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");

            //拿到连接
            conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);

            //开启事务  false:开启事务, ture:关闭事务
            conn.setAutoCommit(false);


            Statement statement = conn.createStatement();
            // 张三减500
            String sql = "UPDATE account SET balance = balance - 500 WHERE id=1;";
            statement.executeUpdate(sql);




            // 李四加500
            sql = "UPDATE account SET balance = balance + 500 WHERE id=2;";
            statement.executeUpdate(sql);

            // 模拟异常
             int i = 10 / 0;

            //关闭资源
            statement.close();

            //提交事务
            conn.commit();



        } catch (Exception e) {
            e.printStackTrace();

            try {
                //出现异常 回滚事务
                conn.rollback();
                System.out.println(" 出现异常事务回滚 ");

            } catch (SQLException e1) {
                e1.printStackTrace();

                
            }
        }finally {
            try {

                //关闭资源
                if (conn!=null){
                    conn.close();
                }

            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }


    }
}


小结:

JDBC与事务相关得API

在Connection接口中.

setAutoCommit(false); 表示开启事务

commit(); 提交事务

rollback(); 回滚事务

8.ParameterMetaData元数据

元数据的基本概述

什么是元数据:数据库、表、列的定义信息。
在这里插入图片描述

ParameterMetaData作用

ParameterMetaData可用于获取有关PreparedStatement对象中每个参数标记的类型和属性。

ParameterMetaDataAPI介绍

  1. int getParameterCount() 获取PreparedStatement的SQL语句参数?的个数
    
    
  2. int getParameterType(int param) 获取指定参数的SQL类型。  
    
    

使用步骤

  1. 获取ParameterMetaData对象
  2. 使用对象调用方法

注意事项

不是所有的数据库驱动都能获取到参数类型(MySQL会出异常)

package com.xjggb.demo01;

import com.xjggb.utils.JDBCUtils;

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

public class Demo {
    public static void main(String[] args) throws SQLException {

        Connection connection = JDBCUtils.getConnection();

        String sql="INSERT INTO account (NAME, balance) VALUES (?, ?)";

        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData();
        int parameterCount = parameterMetaData.getParameterCount();

        System.out.println("参数个数" + parameterCount);
         // Parameter metadata not available for the given statement
        // MySQL不支持获取参数类型
        // System.out.println("参数类型: " + md.getParameterType(1));

    }
}


小结

ParameterMetaData的作用

得到元数据得参数个数

9.ResultSetMetaData元数据

1.ResultSetMetaData作用

在这里插入图片描述

2.ResultSetMetaDataAPI介绍

  1. int getColumnCount() 返回此 ResultSet对象中的列数
    
    
  2. String getColumnName(int column) 获取指定列的名称
    
    
  3. String getColumnTypeName(int column) 获取指定列的数据库特定类型名称
    
    

代码如下

package com.xjggb.demo01;

import com.xjggb.utils.JDBCUtils;

import java.sql.*;

public class DEmo05 {
    public static void main(String[] args) throws SQLException {


        String sql="SELECT * FROM account WHERE id=1";

        Connection connection = JDBCUtils.getConnection();

        PreparedStatement stmt = connection.prepareStatement(sql);

        ResultSet resultSet = stmt.executeQuery();


        //获取结果元数据
        ResultSetMetaData md = resultSet.getMetaData();


        int columnCount = md.getColumnCount();
        System.out.println("列数:" + columnCount);


        for (int i = 0; i < columnCount; i++) {
            System.out.println("列名:" + md.getColumnName(i + 1)); // 获取列名
            System.out.println("列类型:" + md.getColumnTypeName(i + 1)); // 获取类的类型
            System.out.println("-----------");
        }

    }
}


10.把增删改都写成一个方法

package com.xjggb.utils;

import java.sql.*;

public class JDBCUtils {
    private static final String DRIVER_CLASS = "com.mysql.jdbc.Driver";
    private static final   String URL="jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8";
    private static final  String USERNAME="root";
    private static final  String PASSWORD="root";

    // 2.在静态代码块中注册驱动(只注册一次)
    // 当这个类加载到内存的时候就走这个静态代码块,再去触发Driver类中的静态代码块,主动注册
    //尝试过了可以不写自动注册
    static {
        try {
            Class.forName(DRIVER_CLASS);
        } catch (ClassNotFoundException e) {}
    }

    // 2.提供一个获取连接的方法`static Connection getConneciton();`
    // 谁使用谁处理异常, 这个方法把连接返回给别人使用,有问题也抛给他处理
    public static Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);

        return connection;

    }

    // 3.定义关闭资源的方法`close(Connection conn, Statement stmt, ResultSet rs)`
    // 谁使用谁处理异常, 其他地方调用close会传入 conn, stmt, rs给我们使用.就处理异常

    public static void close(Connection conn, 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 (conn!=null) {
             try {
                 conn.close();
             } catch (SQLException throwables) {
                 throwables.printStackTrace();
             }
         }


         }

    // 4.重载关闭方法`close(Connection conn, Statement stmt)`
    public static void close(Connection conn, Statement statement)  {
      close(conn,statement,null);

    }
    
    
    public static int executeCUD(String sql, Object...args) throws SQLException {




        //获取连接
        Connection connection = getConnection();

        PreparedStatement pstmt  = connection.prepareStatement(sql);

        // 通过PreparedStatement得到参数的元数据
        ParameterMetaData parameterMetaData = pstmt.getParameterMetaData();
        // 获取?号的个数
        int parameterCount = parameterMetaData.getParameterCount();
        System.out.println("parameterCount = " + parameterCount);

        for (int i = 1; i <= parameterCount; i++) {

            pstmt.setObject(i, args[i - 1]);
        }




        //执行sql
        int i = pstmt.executeUpdate();

        //关闭资源
        close(connection,pstmt);

        return i;


    }





}


测试

package com.xjggb.demo01;

import com.xjggb.utils.JDBCUtils;

import java.sql.SQLException;

public class Demo06 {

    public static void main(String[] args) throws SQLException {
        //show2();
       show1();


    }




    public static void show2() throws SQLException {
        String sql = "UPDATE employee SET address=? WHERE id=?;";

        int i = JDBCUtils.executeCUD(sql, "来了老弟",8);

        System.out.println("i = " + i);
    }

    public static void show1() throws SQLException {
        String sql = "INSERT INTO employee VALUES (null, ?, ?, ?);";
        int i = JDBCUtils.executeCUD(sql, "迪丽热巴", 39, "新疆");
        System.out.println("i = " + i);
    }
}


2.连接池介绍

没有连接池得现状

之前JDBC访问数据库的步骤:
创建数据库连接→运行SQL语句→关闭连接 每次数据库访问执行这样重复的动作

获取数据库连接需要消耗比较多的资源,而每次操作都要重新获取新的连接对象,执行一次操作就把连接关闭,而数据库创建连接通常需要消耗相对较多的资源。这样数据库连接对象的使用率低。

在这里插入图片描述

我们现实生活中每日三餐。我们并不会吃一餐饭就将碗丢掉,而是吃完饭后将碗放到碗柜中,下一餐接着使用。目的是重复利用碗,我们的数据库连接也可以重复使用,可以减少数据库连接的创建次数。提高数据库连接对象的使用率。

连接池得概念

连接池就是一个容器,连接池中保存了一些数据库连接,这些连接是可以重复使用的。

连接池得原理

  1. 启动连接池,连接池就会初始化一些连接
  2. 当用户需要使用数据库连接,直接从连接池中取出
  3. 当用户使用完连接,会将连接重新放回连接池中

在这里插入图片描述

连接池得好处

连接池中会保存一些连接,这些连接可以重复使用,降低数据资源的消耗

常用的连接池实现组件有以下这些

  1. 阿里巴巴-德鲁伊Druid连接池:Druid是阿里巴巴开源平台上的一个项目
  2. C3P0是一个开源的连接池,目前使用它的开源项目有Hibernate,Spring等。
  3. DBCP(DataBase Connection Pool)数据库连接池,是Tomcat使用的连接池组件。

小结:

连接池原理

1.启动连接池时,这个连接池会保存一些链接
2.用户使用连接时,去连接池中取连接使用
3.使用完连接,将连接放回连接池

连接池得好处?

连接池中的连接可以重复使用,提交数据库资源的使用

1.C3P0连接池

C3P0地址:https://sourceforge.net/projects/c3p0/?source=navbar

在这里插入图片描述

注意 :配置文件名字不能改,放在src目录下

在这里插入图片描述

C3P0常用的配置参数解释

参数说明
initialPoolSize连接池刚启动时,连接池内包含的连接数量
maxPoolSize连接池中最多可以放多少个连接
checkoutTimeout连接池中没有连接时最长等待时间
maxIdleTime连接池中的空闲连接多久没有使用就会回收。默认是0,0表示不回收

C3P0配置文件

配置文件的要求

  1. 文件名:c3p0-config.xml
  2. 放在源代码即src目录下

配置文件c3p0-config.xml

<c3p0-config>
  <!-- 使用默认的配置读取连接池对象 -->
  <default-config>
  	<!--  数据库连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
     <!-- 连接池参数 -->
     <property name="initialPoolSize">5</property>
     <property name="maxPoolSize">10</property>
     <property name="checkoutTimeout">2000</property>
     <property name="maxIdleTime">1000</property>
  </default-config>

  <named-config name="xiaoguo"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
     <!-- 连接池参数 -->
     <property name="initialPoolSize">5</property>
     <property name="maxPoolSize">10</property>
     <property name="checkoutTimeout">2000</property>
     <property name="maxIdleTime">1000</property>
  </named-config>
  
  <named-config name="abc"> 
    <!--  连接参数 -->
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8</property>
    <property name="user">root</property>
    <property name="password">root</property>
    
    <!-- 连接池参数 -->
     <property name="initialPoolSize">5</property>
     <property name="maxPoolSize">10</property>
     <property name="checkoutTimeout">2000</property>
     <property name="maxIdleTime">1000</property>
  </named-config>
  
</c3p0-config>

API介绍:

ComboPooledDataSource类API

  1. public ComboPooledDataSource()
    无参构造使用默认配置(使用xml中default-config标签中对应的参数)
    
    
  2. public ComboPooledDataSource(String configName)
    有参构造使用命名配置(configName:xml中配置的名称,使用xml中named-config标签中对应的参数)
    
    
  3. public Connection getConnection() throws SQLException
    从连接池中取出一个连接
    
    

使用步骤

  1. 导入jar包c3p0-0.9.5.2.jarmchange-commons-java-0.2.12.jar
  2. 复制配置文件c3p0-config.xml放在src目录下,配置对应参数
  3. 创建连接池对象ComboPooledDataSource
  4. 从连接池中获取连接对象
  5. 使用连接对象操作数据库
  6. 关闭资源,将连接还回连接池中

代码如下

package com.xjggb.demo02;

import com.mchange.v2.c3p0.ComboPooledDataSource;

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

public class Demo01 {
    public static void main(String[] args) throws SQLException {
//
//        // 方式一: 使用默认配置(default-config)
//        ComboPooledDataSource dataSource = new ComboPooledDataSource();

        // 方式二: 使用命名配置(named-config:配置名)
        // new ComboPooledDataSource("配置名");
        ComboPooledDataSource dataSource = new ComboPooledDataSource("xiaoguo");

        //获取连接
        Connection connection = dataSource.getConnection();
//        System.out.println("connection = " + connection);
//        connection.close();
//
//        for (int i = 0; i <9 ; i++) {
//            System.out.println("dataSource.getConnection() = " + dataSource.getConnection());
//
//        }
//
//        Connection connection1 = dataSource.getConnection();
//        System.out.println("connection1 = " + connection1);
 
        
        //添加SQL
        String sql= "delete from employee where id=?";

        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setInt(1,5);

        int i = statement.executeUpdate();
        System.out.println("返回影响得行数" + i);

        statement.close();
        //放回线程
        dataSource.close();



    }
}


小结:

配置文件 得好处

  1. 可以连接不同得数据库 xiaoguo , abc
  2. 可是使用不同得连接池参数:maxPoolSize
  3. 可以连接不同厂商的数据库:Oracle或MySQL

2.Druid连接池

介绍

Druid是阿里巴巴开发的号称为监控而生的数据库连接池,Druid是目前最好的数据库连接池。在功能、性能、扩展性方面,都超过其他数据库连接池,同时加入了日志监控,可以很好的监控数据库连接池和SQL的执行情况。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

Druid地址:https://github.com/alibaba/druid

在这里插入图片描述

Druid常用的配置参数

参数说明
initialSize刚启动连接池时,连接池中包含连接的数量
maxActive连接池中最多可以放多少个连接
maxWait获取连接时最大等待时间,单位毫秒

Druid连接池基本使用

API介绍

com.alibaba.druid.pool.DruidDataSourceFactory类有创建连接池的方法

public static DataSource createDataSource(Properties properties)
创建一个连接池,连接池的参数使用properties中的数据

我们可以看到Druid连接池在创建的时候需要一个Properties对象来设置参数,所以我们使用properties文件来保存对应的参数。
Druid连接池的配置文件名称随便,放到src目录下面方便加载
druid.properties文件内容:

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.93.222:3306/day19?characterEncoding=utf8
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000

使用步骤

  1. 导入druid的jar包
  2. 赋值druid.properties文件到src下,并设置对应参数
  3. 加载properties文件的内容到Properties对象中
  4. 创建Druid连接池,使用配置文件中的参数
  5. 从Druid连接池中取出连接
  6. 执行SQL语句
  7. 关闭资源
package com.xjggb.demo03;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

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



        //加载配置文件
        InputStream resourceAsStream = Demo01.class.getResourceAsStream("/druid.properties");

        Properties properties = new Properties();
        properties.load(resourceAsStream);



        //创建连接池
        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

//		for (int i = 0; i < 9; i++) {
//			Connection conn = dataSource.getConnection();
//			System.out.println(conn);
//		}
//
//        Connection connection = dataSource.getConnection();
//
//        System.out.println("connection = " + connection);
//        connection.close();
//
//        //放回去拿出来是一致得
//        Connection connection1 = dataSource.getConnection();
//        System.out.println("connection = " + connection1);
        //获取连接
        Connection connection = dataSource.getConnection();

        String sql="SELECT * FROM `category`";

        PreparedStatement statement = connection.prepareStatement(sql);

        //查询到数据
        ResultSet resultSet = statement.executeQuery();

        while (resultSet.next()){
            System.out.println("resultSet.getInt(\"cid\") = " + resultSet.getInt("cid"));
            System.out.println("resultSet.getString(\"cname\") = " + resultSet.getString("cname"));


        }


    }
}


小结:

Druid常用的配置参数

参数说明
initialSize启动连接池时,默认的连接数量
maxActive连接池中最大的连接数量
maxWait没有连接时最大的等待时间

Druid连接池基本使用不管是C3P0连接池,配置大致都可以分为2种:1.连接数据库的参数2.连接池的参数,这2种配置大致参数作用都相同,只是参数名称可能不一样。

3.工具类

package com.xjggb.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

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

public class DataSourceUtils {
    // 1.声明静态数据源成员变量
    private static DataSource dataSource;


    static {
        InputStream resourceAsStream = DataSourceUtils.class.getResourceAsStream("/druid.properties");

        Properties properties = new Properties();
        try {
            properties.load(resourceAsStream);
            //创建连接池
             dataSource = DruidDataSourceFactory.createDataSource(properties);

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取数据源 方法
    public static DataSource getDataSource(){

        return dataSource;
    }

    //获取连接对象
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 5.定义关闭资源的方法
    public static void close(Connection conn, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {}
        }

        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException e) {}
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {}
        }
    }

    // 6.重载关闭方法
    public static void close(Connection conn, Statement stmt) {
        close(conn, stmt, null);
    }






}


测试

package com.xjggb.demo03;

import com.xjggb.utils.DataSourceUtils;

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

public class Demo02 {
    public static void main(String[] args) throws SQLException {

        Connection connection = DataSourceUtils.getConnection();

        String sql="SELECT * FROM `category`";

        PreparedStatement statement = connection.prepareStatement(sql);

        //查询到数据
        ResultSet resultSet = statement.executeQuery();

        while (resultSet.next()){
            System.out.println("resultSet.getInt(\"cid\") = " + resultSet.getInt("cid"));
            System.out.println("resultSet.getString(\"cname\") = " + resultSet.getString("cname"));


        }


        //关闭资源
       DataSourceUtils.close(connection,statement,resultSet);

    }
}


小结:

使用工具类使得代码更加简单,关注sql就行

3.总结

1.理解JDBC得概念

jdbc是操作数据库规范

通过jdbc,可以让java操作数据库

  1. 能够使用Connection接⼝

    Connection conn = DriverManager.getConnection("jdbc:mysql:///day16", "root", "root");
    Statement stmt = conn.createStatement();
    
    
  2. 能够使用Statement接⼝

    执行SQL语句的对象,相当于小货车
    
    Statement stmt = conn.createStatement();
    int i = stmt.executeUpdate(sql);
    ResultSet rs = stmt.executeQuery(sql);
    
    
  3. 能够使用ResultSet接⼝

​ 对结果集得处理

5.能够使用JDBC操作CRUD

6.能够使用JDBC操作事务

操作事务的方法在Connectionvoid setAutoCommit(false): 开启事务
void commit(); 提交事务
void rollback(); 回滚事务

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值