JDBC学习总结(二)JDBC操作Blob类型字段/高效的批量插入/JDBC处理数据库事务/将多个SQL看成一个事务执行/数据库连接池C3P0/DBCP/Druid/DBUtils工具类实现CRUD

本文详细介绍了JDBC操作BLOB类型字段的方法,包括插入、修改和查询。接着探讨了批量插入的高效实现,包括使用Statement、PreparedStatement和批处理。接着,深入讲解了JDBC处理数据库事务,包括事务的ACID属性和事务处理方法。最后,讨论了数据库连接池技术,如C3P0、DBCP和Druid,并介绍了Apache-DBUtils工具类在CRUD操作中的应用。

一、JDBC操作BLOB类型字段

(一)MySQL的BLOB类型

  • MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。

  • 插入BLOB类型的数据必须使用PreparedStatement,不能使用Statement,因为BLOB类型的数据无法使用字符串拼接写的。

  • MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)

在这里插入图片描述

  • 实际使用中根据需要存入的数据大小定义不同的BLOB类型。
  • 需要注意的是:如果存储的文件过大,数据库的性能会下降
  • 如果在指定了相关的Blob类型以后,且文件没超过最大范围,还报错:Packet for query is too large,那么我们需要在mysql的安装目录下,找到my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

(二)向数据表中插入Blob类型数据

案例

import com.fox.util.JDBCUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class BlobTest1 {
   
   
    public static void main(String[] args){
   
   
        Connection connection = null;
        PreparedStatement ps = null;
        FileInputStream fis =null;
        try {
   
   
            connection = JDBCUtils.getConnection();
            String sql="insert into customers(name,email,birth,photo) values(?,?,?,?)";
            ps = connection.prepareStatement(sql);
            ps.setString(1,"彭于晏");
            ps.setString(2,"pengyuyan@qq.com");
            ps.setString(3,"1992-02-02");//会隐式转化为Date类型
            fis = new FileInputStream(new File("D:/test/pyy.jpg"));
            ps.setBlob(4,fis);//该方法需要传入一个InputStream对象
            ps.execute();
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            JDBCUtils.closeResource(connection,ps);
            if(fis!=null){
   
   
                try {
   
   
                    fis.close();
                } catch (IOException e) {
   
   
                    e.printStackTrace();
                }
            }
        }
    }
}

(三)修改数据表中Blob类型的字段

案例

import com.fox.util.JDBCUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class BlobTest2 {
   
   
    public static void main(String[] args) {
   
   
        Connection connection = null;
        PreparedStatement ps = null;
        FileInputStream fis = null;
        try {
   
   
            connection = JDBCUtils.getConnection();
            String sql="update customers set photo=? where id=?";
            ps = connection.prepareStatement(sql);
            fis = new FileInputStream(new File("D:/test/pengyuyan.jpg"));
            ps.setBlob(1,fis);
            ps.setInt(2,22);
            ps.execute();
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            JDBCUtils.closeResource(connection,ps);
            if(fis!=null){
   
   
                try {
   
   
                    fis.close();
                } catch (IOException e) {
   
   
                    e.printStackTrace();
                }
            }
        }
    }
}

(四)查询数据表中Blob类型的字段

java.sql.Blob接口中有一个方法:
InputStream getBinaryStream() 将此 Blob实例指定的BLOB值作为流 Blob 。

import com.fox.bean.Customer;
import com.fox.util.JDBCUtils;
import java.io.*;
import java.sql.*;

public class BlobTest3 {
   
   
    public static void main(String[] args) {
   
   
        Connection connection = null;
        PreparedStatement ps = null;
        InputStream is =null;
        FileOutputStream fos =null;
        ResultSet rs =null;
        try {
   
   
            connection = JDBCUtils.getConnection();
            String sql="select id,name,email,birth,photo from customers where name=?";
            ps = connection.prepareStatement(sql);
            ps.setString(1,"彭于晏");
            rs = ps.executeQuery();
            if(rs.next()){
   
   
                //方式一:
                //int id = rs.getInt(1);
                //String name = rs.getString(2);
                //String email = rs.getString(3);
                //Date birth = rs.getDate(4);
                //方式二:(推荐)
                int id = rs.getInt("id");
                String name = rs.getString("name");
                String email = rs.getString("email");
                Date birth = rs.getDate("birth");
                Customer customer = new Customer(id, name, email, birth);
                System.out.println(customer);
                //将Blob类型的字段下载下来,以文件的方式保存在本地
                Blob photo = rs.getBlob("photo");
                is = photo.getBinaryStream();
                fos = new FileOutputStream("pengyuyan.jpg");
                byte[] buffer=new byte[1024];
                int len=0;
                while((len=is.read(buffer))!=-1){
   
   
                    fos.write(buffer,0,len);
                }
            }
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            JDBCUtils.closeResource(connection,ps,rs);
            if(fos!=null){
   
   
                try {
   
   
                    fos.close();
                } catch (IOException e) {
   
   
                    e.printStackTrace();
                }
            }
            if(is!=null){
   
   
                try {
   
   
                    fos.close();
                } catch (IOException e) {
   
   
                    e.printStackTrace();
                }
            }
        }
    }
}

二、批量插入

(一)批量执行SQL语句

当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率

JDBC的批量处理语句包括下面三个方法:
(方法在java.sql.Statement及其子接口中)

  • void addBatch(String):添加需要批量处理的SQL语句或是参数;
  • int[] executeBatch():执行批量处理语句;
  • void clearBatch():清空缓存的数据

通常我们会遇到两种批量执行SQL语句的情况:

  • 多条SQL语句的批量处理;
  • 一个SQL语句的批量传参;

update、delete本身就具有批量操作的效果。此时的批量操作,主要指的是批量插入。

(二)高效的批量插入

案例:向数据表中插入100000条数据
首先,数据库中提供一个goods表。创建如下:

CREATE TABLE goods(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);

1.实现层次一:使用Statement

import com.fox.util.JDBCUtils;
import java.sql.Connection;
import java.sql.Statement;

public class InsertTest1 {
   
   
    public static void main(String[] args) {
   
   
        Connection connection = null;
        Statement statement = null;
        try {
   
   
            long start = System.currentTimeMillis();
            connection = JDBCUtils.getConnection();
            statement = connection.createStatement();
            for (int i = 0; i < 20000; i++) {
   
   
                String sql="insert into goods(name) values('name_"+i+"')";
                statement.executeUpdate(sql);
            }
            long end = System.currentTimeMillis();
            System.out.println("批量插入耗时:"+(end-start)/1000+"秒");
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            JDBCUtils.closeResource(connection,statement);
        }
    }
}

在这里插入图片描述
效率太低了,在实际的开发中通常都不会使用Statement

2.实现层次二:使用PreparedStatement

import com.fox.util.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;

public class InsertTest2 {
   
   
    public static void main(String[] args) {
   
   
        Connection connection = null;
        PreparedStatement ps = null;
        try {
   
   
            long start = System.currentTimeMillis();
            connection = JDBCUtils.getConnection();
            String sql="insert into goods(name) values(?)";
            ps = connection.prepareStatement(sql);
            for (int i = 0; i < 20000; i++) {
   
   
                ps.setString(1,"name_"+i);
                ps.executeUpdate();
            }
            long end = System.currentTimeMillis();
            System.out.println("批量插入耗时:"+(end-start)/1000+"秒");
        } catch (Exception e) {
   
   
            e.printStackTrace();
        } finally {
   
   
            JDBCUtils.closeResource(connection,ps);
        }
    }
}

在这里插入图片描述

可以看到,使用PreparedStatement比使用Statement做批量插入耗时少一点。使用PreparedStatement的性能一定是更高的,因为使用Statement,每一次插入都需要编译一次sql语句,而每次编译都需要进行语法检查,语义检查,翻译成二进制命令,缓存等等,性能低;使用PreparedStatement就能够实现sql语句预编译,只编译一次,每一次插入只需要填充占位符就好。

3.实现层次三:使用批处理

使用批处理即使用 addBatch() 、executeBatch() 、clearBatch()

注意

  • MySQL服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。rewriteBatchedStatements=true 写在配置文件的url后面
    在这里插入图片描述

  • 如果写完参数还是不能使用批处理,是因为MySQL驱动太老了,需要下载新一点的驱动。部分老的MySQL驱动不支持批处理比如mysql-connector-java-5.1.7 ,这里我使用的驱动是mysql-connector-java-5.1.37。

import com.fox.util.JDBCUtils;
import java.sql.Connection;
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值