Mysql数据库——JDBC

发布于:2022-11-29 ⋅ 阅读:(340) ⋅ 点赞:(0)

在本章节主要会讲到JDBC的概念,使用细节,以及连接池和JDBC的进阶使用,主要知识点包括

  • JDBC的使用步骤
  • 数据库的查询方法
  • 数据库写入方法
  • SQL注入攻击的应对
  • 连接池的使用
  • Apache Commons DBUtils

JDBC快速入门

什么是JDBC?

JDBC 全称为Java Database Connectivity,他可以使java通过程序操作关系型数据库,JDBC基于驱动程序实现与数据库的连接与操作

什么是驱动程序?

在这里插入图片描述

类似电脑的USB接口,可以链接鼠标,键盘,打印机,摄像头等不同的设备,只需要通过驱动来识别判断使用属于哪一种设备,JDBC驱动程序也可以通过驱动来使得Java程序使用数据库。
在这里插入图片描述

JDBC的优点

  • 统一的API,提供一致的开发过程
  • 易于学习,容易上手,代码结构稳定
  • 功能强大,执行效率高,可处理海量数据

快速上手JDBC

JDBC开发分为5个步骤:
在这里插入图片描述
给出一个示例,来展示如何通过JDBC连接数据库查询数据的。

package com.jdbc.sample;

import java.sql.*;
import java.util.List;

/**
 * 标准JDBC操作五步骤
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-08
 */
public class StandardJDBCSample {
    public static void main(String[] args) {
        Connection conn =null;
        try {
            // 1.加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.创建数据库连接
           conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode" +
                    "=true" +
                    "&characterEncoding" +
                    "=UTF8&serverTimezone=Asia/Shanghai", "root", "123456");

            // 3.创建Statement对象
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM employee WHERE dname ='研发部'");
            // 4.遍历查询结果
            while (rs.next()) {
                Integer eno = rs.getInt(1);//eno
                String ename = rs.getString("ename");
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (conn !=null&&conn.isClosed() ==false) {
                    conn.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        // 5.关闭连接,释放资源

    }
}

接下来,我们就详细的介绍一下JDBC的使用流程。

JDBC驱动的秘密

如何获取JDBC驱动Jar

我们可以在各大数据库的官网获取JDBC驱动jar包,例如:
MYSQL的JDBC驱动jar包地址为:https://dev.mysql.com/downloads/connector/j/

创建数据库连接代码:

String dbDriver = "com.mysql.cj.jdbc.Driver"; //JDBC驱动类
String dbURL = "jdbc:mysql://localhost:3306/imooc" ; //连接字符串
String dbUsername = "root"; //数据库用户名
String dbPassword = "123456"; //数据库密码
//1.加载并初始化JDBC驱动
Class.forName(dbDriver);
//2.创建数据库连接
Connection connection = DriverManager.getConnection(dbURL, dbUsername, dbPassword);

Class.forName作用

  • Class.forName()是用于加载指定的JDBC驱动类
  • Class.forName本质是通知JDBC注册这个驱动类
  • JDBC因为是由不同的数据库厂商提供jar,所以对应的连接串也不同。
    在这里插入图片描述

DriverManager 设备管理器

  • DriverManager 用于注册/管理JDBC驱动程序
  • DriverManager.getConnection(连接字符串,用户名,密码);
  • 返回值Connection对象,对应数据库的物理网络连接

Connection对象

  • Connection对象用于JDBC与数据库的网络通信对象
  • java.sql.Connection是一个接口,具体由驱动厂商实现
  • 所有数据库的操作都是建立在Connection上的

Mysql连接数据串

  • 格式:jdbc:mysql://主机IP:端口号/数据库名?参数列表
  • 主机IP与端口是可选设置,默认值是127.0.0.1与3306
  • 参数列表采用URL编码,格式:参数1=值1&参数2=值2&…
  • 常用的数据库参数如下:
    在这里插入图片描述

下面示例演示如何创建连接串:

package com.jdbc.sample;

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

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-09
 */
public class ConnectionSample {
    public static void main(String[] args) {
        // 1.获取驱动
        Connection conn = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode=true&haracterEncoding=UTF-8" +
                    "&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
            String username="root";
            String password ="123456";
            // 2.获取数据库连接
            conn = DriverManager.getConnection(url,username,password);
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        System.out.println(conn);
    }
}

有几个常见错误需要注意一下:

  1. 未添加驱动包或者驱动包不对时,提示 java.lang.ClassNotFoundException: com.mysql.cj.jdbc.Driver
    在这里插入图片描述

  2. 写错用户名/密码,提示 java.sql.SQLException: Access denied for user ‘root’@‘localhost’ (using password: YES)
    在这里插入图片描述

  3. IP或者端口号写错了,提示 com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
    在这里插入图片描述

Statement对象

在这里插入图片描述

ResultSet对象

在这里插入图片描述

从部门表中筛选数据

package com.jdbc.hrapp.command;

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

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-09
 */
public class QueryCommand implements Command{
    @Override
    public void excute() {
        Connection connection = null ;
        Statement stmt = null;
        ResultSet rs =null;
        System.out.println("请输入部门名称");
        Scanner in =new Scanner(System.in);
        String pdname = in.next();
        try {
            // 1.加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.创建数据库连接
             connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode" +
                     "=true" +
                     "&characterEncoding" +
                     "=UTF8&serverTimezone=Asia/Shanghai", "root", "123456");
            // 3.创建Statement对象
             stmt = connection.createStatement();
            // 结果集
             rs = stmt.executeQuery("SELECT * FROM employee WHERE dname ='"+pdname+"'");
            // 4.遍历结果
            while (rs.next()){
                Integer eno = rs.getInt(1);//eno
                String ename = rs.getString("ename");
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }

        } catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (rs != null){
                    rs.close();
                }
                if (stmt != null){
                    stmt.close();
                }
                if (connection != null &&!connection.isClosed()){
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }


        }
    }
}

显然上面一段代码具有sql注入的风险,为了解决这个问题,我们引入PreparedStatement ,它会将sql语句进行预处理。

package com.jdbc.hrapp.command;

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

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-09
 */
public class QueryCommand implements Command{
    @Override
    public void excute() {
        Connection connection = null ;
        PreparedStatement stmt = null;
        ResultSet rs =null;
        System.out.println("请输入部门名称");
        Scanner in =new Scanner(System.in);
        String pdname = in.next();
        try {
            // 1.加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 2.创建数据库连接
             connection =  DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode" +
                     "=true" +
                     "&characterEncoding" +
                     "=UTF8&serverTimezone=Asia/Shanghai", "root", "123456");
            // 3.创建Statement对象
             stmt = connection.prepareStatement("SELECT * FROM employee WHERE dname =?");
             stmt.setString(1,pdname);
            // 结果集
             rs = stmt.executeQuery();
            // 4.遍历结果
            while (rs.next()){
                Integer eno = rs.getInt(1);//eno
                String ename = rs.getString("ename");
                Float salary = rs.getFloat("salary");
                String dname = rs.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }

        } catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                if (rs != null){
                    rs.close();
                }
                if (stmt != null){
                    stmt.close();
                }
                if (connection != null &&!connection.isClosed()){
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }


        }
    }
}

PreparedStatemen

  • PreparedStatement 预编译Statement是Statement的子接口
  • PreparedStatement对SQL进行参数化,预防SQL注入攻击
  • PreparedStatement比Statement执行效率更高

错误的使用方式

在这里插入图片描述

封装DbUtils

因为每次使用JDBC都需要创建连接,使用完毕后都需要释放资源等,很麻烦,所以应运而生产生DbUtils类,帮助我们创建/关闭连接。
工具类如下:

package com.jdbc.common;

import java.sql.*;

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-11
 */
public class DbUtils {
    /**
     * 创建新的数据库连接
     * 
     * @return
     * @throws SQLException
     * @throws ClassNotFoundException
     */
    public static Connection getConnection() throws SQLException, ClassNotFoundException {
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode" +
                "=true" +
                "&characterEncoding" +
                "=UTF8&serverTimezone=Asia/Shanghai", "root", "123456");
        return conn;
    }

    /**
     * 关闭连接,释放资源
     * 
     * @param rs
     * @param statement
     * @param connection
     */
    public static void closeConnection(ResultSet rs, Statement statement,Connection connection){
        try {
            if (rs != null){
                rs.close();
            }
            if (statement != null){
                statement.close();
            }
            if (connection != null &&!connection.isClosed()){
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

JDBC实现写数据

下面给出代码示例:
增加:

package com.jdbc.hrapp.command;

import com.jdbc.common.DbUtils;

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

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-11
 */
public class InsertCommand implements Command{
    @Override
    public void excute() {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入员工编号");
        int eno = sc.nextInt();
        System.out.println("请输入员工姓名");
        String ename =sc.next();
        System.out.println("请输入员工薪资");
        Float salary =sc.nextFloat();
        System.out.println("请输入员工隶属部门");
        String dname =sc.next();
        try {
            connection  = DbUtils.getConnection();
            String sql = "INSERT INTO employee(eno,ename,salary,dname) VALUES(?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1,eno);
            preparedStatement.setString(2,ename);
            preparedStatement.setFloat(3,salary);
            preparedStatement.setString(4,dname);
            int cnt =preparedStatement.executeUpdate();
            System.out.println("cnt:"+cnt);
            System.out.println("员工入职手续已经办理完成!");
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            DbUtils.closeConnection(null,preparedStatement,connection);
        }

    }
}

删除

package com.jdbc.hrapp.command;

import com.jdbc.common.DbUtils;

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

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-11
 */
public class DeleteCommand implements Command{
    @Override
    public void excute() {

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入员工编号");
        int eno = sc.nextInt();

        try {
            connection  = DbUtils.getConnection();
            String sql = "DELETE FROM  employee WHERE eno =?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setFloat(1,eno);
            int cnt =preparedStatement.executeUpdate();
            if (cnt==1) {
                System.out.println("员工离职完成");
            }else {
                System.out.println("未找到"+eno+"员工数据");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            DbUtils.closeConnection(null,preparedStatement,connection);
        }

    }
}


修改:

package com.jdbc.hrapp.command;

import com.jdbc.common.DbUtils;

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

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-11
 */
public class UpdateCommand implements Command{
    @Override
    public void excute() {

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入员工编号");
        int eno = sc.nextInt();

        System.out.println("请输入员工新的薪资");
        Float salary =sc.nextFloat();

        try {
            connection  = DbUtils.getConnection();
            String sql = "UPDATE employee SET salary = ? WHERE eno =?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(2,eno);
            preparedStatement.setFloat(1,salary);
            int cnt =preparedStatement.executeUpdate();
            if (cnt==1) {
                System.out.println("员工调薪完成");
            }else {
                System.out.println("未找到"+eno+"员工数据");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            DbUtils.closeConnection(null,preparedStatement,connection);
        }

    }
}


JDBC中的事务管理

我们身边的例子:
在这里插入图片描述

小张想交话费,100元,但是发现自己没钱了,怎么办呢,她就找小王借了100元,在现实生活中很正常,就是小王的钱减少100,小张的钱增加100,那么在数据库中是怎么管理的呢?就是小张的账户增加100,小王的账户减少100,这两个动作要么同时发生,要么都不发生,不允许说是存在一个中间态。这个时候就需要把两个动作放在一个事务中管理。

什么是事务

  • 事务是以一种可靠的、一致的方式,访问和操作数据库的程序单元
  • 说人话:要么把事情做完,要么什么都不做,不要做一半
  • 事务依赖于数据库实现,MySQL通过事务区作为数据缓冲地带

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

JDBC的事务模式

JDBC有两种事务模式:自动提交的事务模式 和手动提交的事务模式

自动提交事务模式

  • 自动提交模式是指每执行一次写操作SQL,自动提交事务
  • 自动提交开启方法: conn.setAutoCommit(true)
  • 自动事务是JDBC默认行为,此模式无法保证多数据一致性

手动提交事务模式

  • 手动提交模式是指显式调用commit()与rollback()方法管理事务
  • 手动提交开启方法: conn.setAutoCommit(false)
  • 手动提交事务可保证多数据一致性,但必须手动调用提交/回滚方法

下面我们通过实例来来看一下这两种模式怎么使用。

自动提交时

package com.jdbc.sample;

import com.jdbc.common.DbUtils;

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

/**
 * 事务控制
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-12
 */
public class TransactionSample {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = DbUtils.getConnection();
            //connection.setAutoCommit(false);
            String sql = "INSERT INTO employee(eno,ename,salary,dname) VALUES(?,?,?,?)";
            for (int i = 1000; i < 2000; i++) {
                if (i == 1005) {
                    throw new RuntimeException("插入失败了");
                }
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "员工" + i);
                preparedStatement.setFloat(3, 4000f);
                preparedStatement.setString(4, "市场部");
                preparedStatement.executeUpdate();
            }
            //connection.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if (connection != null && !connection.isClosed()) {
                   // connection.rollback();
                }
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }

        } finally {
            DbUtils.closeConnection(null, preparedStatement, connection);
        }
    }
}

结果在i=1005时提示报错,数据库中有1000——1004的数据,是因为每次执行INSERT都自动提交了事务。
在这里插入图片描述
而当我使用connection.setAutoCommit(false); 设置为手动提交事务后,结果就不同了。

手动提交事务

package com.jdbc.sample;

import com.jdbc.common.DbUtils;

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

/**
 * 事务控制
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-12
 */
public class TransactionSample {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            connection = DbUtils.getConnection();
            connection.setAutoCommit(false);
            String sql = "INSERT INTO employee(eno,ename,salary,dname) VALUES(?,?,?,?)";
            for (int i = 1000; i < 2000; i++) {
                if (i == 1005) {
                    throw new RuntimeException("插入失败了");
                }
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "员工" + i);
                preparedStatement.setFloat(3, 4000f);
                preparedStatement.setString(4, "市场部");
                preparedStatement.executeUpdate();
            }
            connection.commit();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if (connection != null && !connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }

        } finally {
            DbUtils.closeConnection(null, preparedStatement, connection);
        }
    }
}

结果在i=1005时抛出异常提示插入失败,数据回滚,所以没有任何数据插入。
在这里插入图片描述
在这里插入图片描述

基于实体类实现分页数据封装

给出示例代码:

package com.jdbc.hrapp.command;

import com.jdbc.common.DbUtils;
import com.jdbc.hrapp.entity.Employee;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-12
 */
public class PaginationCommand implements Command {
    @Override
    public void excute() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入页号");
        int page = scanner.nextInt();
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet rs = null;
        List<Employee> list = new ArrayList();
        try {
            connection = DbUtils.getConnection();
            String sql = "SELECT * FROM employee LIMIT ?,10";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, (page - 1) * 10);
            rs = preparedStatement.executeQuery();
            while (rs.next()) {
                Employee employee = new Employee();
                employee.setEno(rs.getInt("eno"));
                employee.setEname(rs.getString("ename"));
                employee.setSalary(rs.getFloat("salary"));
                employee.setDname(rs.getString("dname"));
                list.add(employee);
            }
            System.out.println(list.size());
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } finally {
            DbUtils.closeConnection(rs,preparedStatement,connection);
        }
    }
}

JDBC中Date日期对象的处理

在JDBC中我们一般使用java.util.date存储查询的date数据,但是在数据库中是用java.sql.date,所以需要针对这个做处理。
在查询时候,因为sql.date 继承自 util.date 所以查询出的数据可以直接赋值使用,但是在录入时,我们输入的String类型最终需要处理成sql.date才能使用。处理过程如下:

 Date udHiredate =null;
 // 声明字符串类型日期
String strhiredate = "1970-01-01";
// 声明时间格式
SimpleDateFormat simpleDateFormat =new SimpleDateFormat("yyyy-MM-dd");

// 字符串转换为util.date
udHiredate =  simpleDateFormat.parse(strhiredate);

// 2.java.util.date 转java.sql.date
// util.date转为数值毫秒数
 Long time = udHiredate.getTime(); //获取从1970年到现在的毫秒数
 // 毫秒数转sql.date
java.sql.Date sqlDate = new java.sql.Date(time);

*这里注意声明格式时候,“YYYY-MM-DD"和"yyyy-MM-dd” 不同,我们采用后面的方式。

JDBC批处理

JDBC的批处理也很简单,使用addBatch()和excuteBatch()方法即可,下面我们看一下和之前标准方法插入数据的区别,代码如下

package com.jdbc.sample;

import com.jdbc.common.DbUtils;

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

/**
 * 事务控制
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-12
 */
public class BatchSample {

    //标准方法插入若干数据
    public static void tc1(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            long startTime = new Date().getTime();
            connection = DbUtils.getConnection();
            connection.setAutoCommit(false);
            String sql = "INSERT INTO employee(eno,ename,salary,dname) VALUES(?,?,?,?)";
            for (int i = 100000; i < 200000; i++) {
                preparedStatement = connection.prepareStatement(sql);
                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "员工" + i);
                preparedStatement.setFloat(3, 4000f);
                preparedStatement.setString(4, "市场部");
                preparedStatement.executeUpdate();
            }
            connection.commit();
            long endTime =new Date().getTime();
            System.out.println("tc1执行总时长" + (startTime-endTime));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if (connection != null && !connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }

        } finally {
            DbUtils.closeConnection(null, preparedStatement, connection);
        }
    }

    // 使用批处理插入数据
    public static void tc2(){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            long startTime = new Date().getTime();
            connection = DbUtils.getConnection();
            connection.setAutoCommit(false);
            String sql = "INSERT INTO employee(eno,ename,salary,dname) VALUES(?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 200000; i < 300000; i++) {

                preparedStatement.setInt(1, i);
                preparedStatement.setString(2, "员工" + i);
                preparedStatement.setFloat(3, 4000f);
                preparedStatement.setString(4, "市场部");
                preparedStatement.addBatch();
            }
            preparedStatement.executeBatch();
            connection.commit();
            long endTime =new Date().getTime();
            System.out.println("tc2执行总时长" + (startTime-endTime));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            e.printStackTrace();
            try {
                if (connection != null && !connection.isClosed()) {
                    connection.rollback();
                }
            } catch (SQLException ex) {
                throw new RuntimeException(ex);
            }

        } finally {
            DbUtils.closeConnection(null, preparedStatement, connection);
        }
    }
    public static void main(String[] args) {
        tc1();
        tc2();
    }
}

执行后效果如下,可以看出批处理比之前快了10s左右,那么为什么会这样呢?是因为批处理省去了重复的sql解析工作。
在这里插入图片描述

连接池和JDBC进阶使用

阿里巴巴Druid连接池

在这里插入图片描述
给出示例代码及配置:
配置项-druid-config.properties

# Druid??????
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/imooc?useSSL=false&useUnicode=true&characterEncoding=UTF8&serverTimezone=Asia/Shanghai
username=root
password=123456
initialSize=10
maxActive=20

代码:

package com.jdbc.sample;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.jdbc.common.DbUtils;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Properties;

/**
 * Druid连接池
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-14
 */
public class DruidSample {
    public static void main(String[] args) {
        // 1.加载属性文件
        Properties properties = new Properties();
        String propertyFile  = DruidSample.class.getResource("/druid-config.properties").getPath();
        Connection connection =null;
        PreparedStatement preparedStatement =null;
        ResultSet rs = null;
        // URLDecoder().decode多次使用了,请记住使用
        try {
            propertyFile = new URLDecoder().decode(propertyFile,"UTF-8");
            properties.load(new FileInputStream(propertyFile));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 2.获取datasource数据源对象
        try {
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            // 3.创建数据库链接
            for (int i = 0; i < 21; i++) {
                connection = dataSource.getConnection();


          preparedStatement =  connection.prepareStatement("SELECT * FROM employee limit 1");
          rs = preparedStatement.executeQuery();
          while(rs.next()){
              Integer eno = rs.getInt(1);//eno
              String ename = rs.getString("ename");
              Float salary = rs.getFloat("salary");
              String dname = rs.getString("dname");
              System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
          }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            DbUtils.closeConnection(rs,preparedStatement,connection);
        }


    }
}

C3P0使用

配置文件:c3p0-config.xml


<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/imooc?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true</property>
        <property name="user">root</property>
        <property name="password">123456</property>
        <!-- 连接池初始连接数量 -->
        <property name="initialPoolSize">10</property>
        <!--最大连接数量-->
        <property name="maxPoolSize">20</property>
    </default-config>
</c3p0-config>

代码;

package com.jdbc.sample;

import com.jdbc.common.DbUtils;
import com.mchange.v2.c3p0.ComboPooledDataSource;

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

/**
 * C3P0连接池
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-17
 */
public class C3P0Sample {
    public static void main(String[] args) {
        Connection connection =null;
        PreparedStatement preparedStatement =null;
        ResultSet resultSet =null;
        DataSource dataSource = new ComboPooledDataSource();
        try {
            connection =dataSource.getConnection();
            String sql ="SELECT * FROM employee limit 10";
            preparedStatement = connection.prepareStatement(sql);
            resultSet =preparedStatement.executeQuery();
            while (resultSet.next()){
                Integer eno = resultSet.getInt(1);//eno
                String ename = resultSet.getString("ename");
                Float salary = resultSet.getFloat("salary");
                String dname = resultSet.getString("dname");
                System.out.println(dname + "-" + eno + "-" + ename + "-" + salary);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            DbUtils.closeConnection(resultSet,preparedStatement,connection);
        }
    }
}

Common DbUtils使用

代码如下:

package com.jdbc.sample;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.jdbc.hrapp.entity.Employee;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLDecoder;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

/**
 * todo {类简要说明}
 *
 * @author wangwei
 * @version 1.0.0
 * @since 2022-10-17
 */
public class CommonDbUtilSample {
    private static void query(){
        Properties properties =new Properties();
        String propertyFile  = DruidSample.class.getResource("/druid-config.properties").getPath();

        try {
            propertyFile = new URLDecoder().decode(propertyFile,"UTF-8");
            properties.load(new FileInputStream(propertyFile));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
            QueryRunner queryRunner =new QueryRunner(dataSource);
            List<Employee> list = queryRunner.query("SELECT * FROM employee LIMIT ?,10",
                    new BeanListHandler<>(Employee.class),
                    new Object[]{1});
            for (Employee employee:list) {
                System.out.println(employee.toString());
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private static void update(){
        Properties properties =new Properties();
        String propertyFile  = DruidSample.class.getResource("/druid-config.properties").getPath();
        Connection connection =null;
        try {
            propertyFile = new URLDecoder().decode(propertyFile,"UTF-8");
            properties.load(new FileInputStream(propertyFile));
            DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
           connection = dataSource.getConnection();
           connection.setAutoCommit(false);
           String sql1 ="update employee set salary =salary+1000 where eno =?";
            String sql2 ="update employee set salary =salary-500 where eno =?";
            QueryRunner queryRunner =new QueryRunner();
            queryRunner.update(connection,sql1,new Object[]{1000});
            queryRunner.update(connection,sql2,new Object[]{1000});
            connection.commit();
        } catch (Exception e) {
            try {
          if (connection!=null&&!connection.isClosed()){

                  connection.rollback();
              } }catch (SQLException ex) {
                  throw new RuntimeException(ex);

          }
        }
    }
    public static void main(String[] args) {
        query();
        update();
    }
}

本文含有隐藏内容,请 开通VIP 后查看