【JDBC】BloB类型的数据的插入与数据的批量插入操作

本文详细介绍了PreparedStatement相对于Statement的优势,包括解决SQL注入、提高性能,并着重讲解了如何使用PreparedStatement处理BLOB类型的大数据,如图片、视频的存储和读取。此外,还演示了批量插入数据的多种方式,比较了效率。最后,提到了防止SQL注入的重要性。
摘要由CSDN通过智能技术生成

一、PreparedStatement的优势

PreparedStatement除了解决Statement的拼串、sql注入问题之外,还有哪些好处呢?
① PreparedStatement操作Blob的数据,而Statement做不到。
② Preparedstatement可以实现更高效的批量操作。

1.对于常见的数据我们可以存储在数据库中,那么对于图片、视频等文件是否也可以存储在数据库中呢?
答案是肯定的,先来认识一下BLOB类型的数据:

MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的(因此对于BLOB类型的文件,也不能使用Statement)。

2.MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)
在这里插入图片描述

二、对数据库表中数BLOB类型数据的操作

MySQL数据库中customers表的结构:
在这里插入图片描述
1.向数据库表中插入BLOB类型的数据:

//向数据库表中插入图片文件
@Test
public void insertTest() {
    Connection connect = null;
    PreparedStatement ps = null;
    try {
        //1.与数据库建立连接
        connect = JdbcUtils.getConnection();
        //2.预编译sql
        String sql = "insert into customers(name,email,birth,photo) values(?,?,?,?)";
        ps = connect.prepareStatement(sql);
        ps.setObject(1,"交大");
        ps.setObject(2,"jd@126.com");
        ps.setObject(3,"2000-2-26");
        FileInputStream fis = new FileInputStream(new File("E:\\java\\JDBC\\day01_jdbc\\src\\和谐园.png"));
        ps.setBlob(4,fis);
        ps.execute();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        //关闭资源
        JdbcUtils.closeConnection(ps,connect);
    }
}

插入结果
注意:此处在插入时,可能会因为插入图片太大而导致插入不成功,此时需要在my.ini文件中对最大允许的上传参数进行设置:max_allowed_packet=16M。设置结束后,先关闭mysql服务,再对mysql服务进行重启,再启动程序进行上传即可成功。
在这里插入图片描述
2.从数据库中读取BLOB类型的数据,并下载到本地

//从数据库表中读取BLOB数据,下载到本地
@Test
public void queryTest(){
    Connection connect = null;
    PreparedStatement ps = null;
    InputStream is = null;
    FileOutputStream fos = null;
    try {
        connect = JdbcUtils.getConnection();
        String sql = "select id,name,email,birth,photo from customers where id = ?";
        ps = connect.prepareStatement(sql);
        ps.setInt(1,28);
        ResultSet resultSet = ps.executeQuery();
        if (resultSet.next()){
//            //方式一:使用索引
//            int id = resultSet.getInt(1);
//            String name = resultSet.getString(2);
//            String email = resultSet.getString(3);
//            Date date = resultSet.getDate(4);
            //方式二:使用别名(若没有起别名,这就是列名)
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            String email = resultSet.getString("email");
            Date birth = resultSet.getDate("birth");
            Customer customer = new Customer(id, name, email, birth);
            System.out.println(customer);
            Blob photo = resultSet.getBlob("photo");
            is = photo.getBinaryStream();
            fos = new FileOutputStream(new File("E:\\java\\JDBC\\day01_jdbc\\src\\交大.jpg"));
            byte[] bytes = new byte[1024];
            int len ;
            while ((len= is.read(bytes))!=-1){
                fos.write(bytes,0,len);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        try {
            if(is!=null){
                is.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if(fos!=null){
                fos.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //关闭资源
        JdbcUtils.closeConnection(ps,connect);
    }
}

执行结果:
在这里插入图片描述
下载完成:
在这里插入图片描述

三、批量插入数据的操作

/**
 * CREATE TABLE goods(id INT PRIMARY KEY AUTO_INCREMENT,NAME VARCHAR(20));
 * 数据库中的数据的批量插入,从上到下,依次效率提高
 * @author wds
 * @date 2021-12-13 20:07
 */
public class InsertTest {
    //方式1:批量插入数据的操作,使用Statement
    @Test
    public void insertTest01(){
        Connection connect = null;
        Statement statement = null;
        try {
            connect = JdbcUtils.getConnection();
            statement = connect.createStatement();
            for(int i = 1;i<=20000;i++){
                String sql = "insert into goods(name) values('name_'"+i+"')'";
                boolean execute = statement.execute(sql);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.closeConnection(statement,connect);
        }
    }
    //方式2:批量插入数据的操作,使用PreparedStatement
    @Test
    public void insertTest02() {
        Connection connect = null;
        PreparedStatement ps = null;
        try {
            long start = System.currentTimeMillis();
            connect = JdbcUtils.getConnection();
            String sql = "insert into goods(name) values (?)";
            ps = connect.prepareStatement(sql);
            for (int i = 1;i<=20000;i++){
                ps.setObject(1,"name_"+i);
                ps.execute();
            }
            long end = System.currentTimeMillis();
            System.out.println("花费的时间是:"+(end-start)+"毫秒");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.closeConnection(ps,connect);
        }
    }
    //方式3:批量插入数据的操作,使用PreparedStatement和Batch
    /*
    1.addBatch()、executeBatch()、clearBatch()
    2.mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。
    ?rewriteBatchedStatements=true写在配置文件的url后面
    3.使用更新的mysql 驱动:mysql-connector-java-5.1.37-bin.jar
     */
    @Test
    public void insertTest03(){
        Connection connect = null;
        PreparedStatement ps = null;
        try {
            long start = System.currentTimeMillis();
            connect = JdbcUtils.getConnection();
            String sql = "insert into goods(name) values (?)";
            ps = connect.prepareStatement(sql);
            for (int i = 1;i<=20000;i++){
                ps.setObject(1,"name_"+i);
                //1.“攒”sql
                if(i%500==0){
                    //2.执行batch
                    ps.executeBatch();
                    //3.清空batch
                    ps.clearBatch();
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("花费的时间是:"+(end-start)+"毫秒");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.closeConnection(ps,connect);
        }
    }
    //方式4:批量插入数据的操作,使用PreparedStatement和Batch,以及数据库不自动提交
    @Test
    public void insertTest04(){
        Connection connect = null;
        PreparedStatement ps = null;
        try {
            long start = System.currentTimeMillis();
            connect = JdbcUtils.getConnection();
            //设置数据库不自动提交
            connect.setAutoCommit(false);
            String sql = "insert into goods(name) values (?)";
            ps = connect.prepareStatement(sql);
            for (int i = 1;i<=20000;i++){
                ps.setObject(1,"name_"+i);
                //1.“攒”sql
                if(i%500==0){
                    //2.执行batch
                    ps.executeBatch();
                    //3.清空batch
                    ps.clearBatch();
                }
            }
            connect.commit();
            long end = System.currentTimeMillis();
            System.out.println("花费的时间是:"+(end-start)+"毫秒");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.closeConnection(ps,connect);
        }
    }
}

jdbc.properties

user=root
password=12345678
driverClass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true

面试题:

PreparedStatement 和 Statement在执行数据库操作时有什么异同?
① PreparedStatement接口是Statement的子接口,它表示一条预编译过的SQL语句
② PreparedStatement通过预编译能最大可能提高操作性能

  • DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
  • 在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义,事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。

③ PreparedStatement可以防止SQL注入

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

智商三岁半i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值