Logo

郎哥编程

批处理、大文本和二进制数据

2021-07-24 309

学习目标:解决MySQL存储大文本数据和二进制数据的问题,解决数据库批量执行SQL语句的问题。

处理大文本

当文本数据内容超过64K字节时,可以称为大文本数据,大文本数据也称为CLOB数据。在MySQL中,提供了LONGTEXT类型的字段用来存储大文本数据。

课程案例shop数据库的goods(产品表)的brief字段就是大文本数据字段,可以存储4G以内的文本数据。写入大文本数据时,需要通过I/O流的方式从文本文件中读取文本内容。

针对大文本数据,PreparedStatement接口提供了如下几个方法用于写入大文本数据:

●   void     setAsciiStream(int parameterIndex, InputStream x, int length)

该方法将指定的输入流写入数据库文本字段中。参数parameterIndex表示字段所在记录的列号。参数InputStream为输入流。参数length表示输入流的长度。

●   void     setBinaryStream(int parameterIndex, InputStream x, int length)

该方法将指定的输入流写入数据库的二进制字段中。参数parameterIndex表示字段所在记录的列号。参数InputStream为输入流。参数length表示输入流的长度。

大文本数据写入数据库后,在查询时需要使用ResultSet接口将数据读出来。ResultSet接口提供了如下几个方法用于读取大文本数据:

●   InputStream      getAsciiStream(int columnIndex)

该方法根据记录的列编号返回文本输入流。参数columnIndex表示结果集当前光标所在行的列号。

●   InputStream      getAsciiStream(String columnLabel)

该方法根据记录的列名称返回文本输入流。参数columnLabel表示结果集当前光标所在行的列名称。

●   Clob     getClob(int columnIndex)

该方法根据记录的列编号返回Clob对象。参数columnIndex表示结果集当前光标所在行的列号。

●   Clob     getClob(String columnLabel)

该方法根据记录的列名称返回Clob对象。参数columnIndex表示结果集当前光标所在行的列名称。

●   InputStream      getBinaryStream (int columnIndex)

该方法根据记录的列编号返回二进制数据输入流。参数columnIndex表示结果集当前光标所在行的列号。

●   InputStream      getBinaryStream(String columnLabel)

该方法根据记录的列名称返回二进制数据输入流。参数columnLabel表示结果集当前光标所在行的列名称。

●   Blob     getBlob(int columnIndex)

该方法根据记录的列编号返回Blob对象(二进制大数据对象)。参数columnIndex表示结果集当前光标所在行的列号。

●   Blob     getBlob(String columnLabel)

该方法根据记录的列名称返回Blob对象(二进制大数据对象)。参数columnIndex表示结果集当前光标所在行的列名称。

案例8:在goods表中插入一条记录,goods表的brief是LONGTEXT类型字段,该字段的值需要从文本文件读入。

在demo包下新建SqlDemoTest7类。代码如下:

package demo;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
public class SqlDemoTest7 {
 
    // 定义JDBC加载路径
    static String jdbc = "com.mysql.cj.jdbc.Driver";
    // 定义MySQL数据库的连接地址
    static String mysqlurl = "jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2B8";
    // 定义MySQL数据库的用户名
    static String username = "root";
    // 定义MySQL数据库的用户名登录密码
    static String password = "~123456q";
 
    public static void main(String[] args) throws FileNotFoundException {
        Connection conn = null;
        PreparedStatement prepartStatement = null;
        try {
            // 加载JDBC驱动
            Class.forName(jdbc);
            // 连接数据库
            conn = DriverManager.getConnection(mysqlurl, username, password);
            if (null != conn) {
                System.out.println(conn);
                // 向shoper表中插入一条记录
                String sql = "insert into goods(id,name,categoryId,photo,shoperId,price,status,createDate,brief)"
                        + "values(?,?,?,?,?,?,?,?,?)";
                // 实例化PreparedStatement对象
                prepartStatement = conn.prepareStatement(sql);
                // 设置id字段的值
                prepartStatement.setString(1,"0001");
                // 设置name字段的值
                prepartStatement.setString(2,"电脑");
                // 设置categoryId字段的值
                prepartStatement.setString(3,"010");
                // 设置photo字段的值
                prepartStatement.setString(4,"");
                // 设置photo字段的值
                prepartStatement.setString(5,"01");
                // 设置price字段的值
                prepartStatement.setDouble(6, 0.0);
                // 设置status字段的值
                prepartStatement.setInt(7, 0);
                // 设置createDate字段的值
                java.util.Date date = new java.util.Date();
                java.sql.Date sqldate = new java.sql.Date(date.getTime());
                prepartStatement.setDate(8,sqldate);
                // 定义一个File对象,准备从文件中读取数据
                File file = new File("d:" + File.separator + "temp.txt");
                InputStream input = new FileInputStream(file);
                prepartStatement.setAsciiStream(9, input, file.length());
                // 执行SQL语句
                int row  = prepartStatement.executeUpdate();
                if( row == 1 )
                {
                    System.out.println("goods表添加记录成功");
                }
                else
                {
                    System.out.println("goods表添加记录失败");
                }
                prepartStatement.close();
                conn.close();
            } else {
                System.out.println("数据库连接失败");
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

执行大文本数据的写入必须使用PreparedStatement接口,PreparedStatement接口的setDate()方法和Statement接口的setDate()方法有所不同,它需要传入java.sql.Date类型的对象。

程序使用FileInputStream将文本文件读取进来,然后通过PreparedStatement接口的setAsciiStream()方法将文件内容写入到对应的大文本字段中。

大文本文件写入完成后,在读取数据库记录时,可以使用ResultSet接口的读取大文本数据的方法将文本内容读取出来。

处理二进制数据

二进制数据不能使用文本编辑器查看内容,需要专门读取二进制数据的应用程序查看。例如读取图片文件时,读取图片的程序需要了解该文件的结构,并解释读取的数据,如果不了解该图片文件的结构,读取图片文件就会失败,也就无法把图片显示出来了。

在MySQL中,提供了LONGBLOB类型的字段用来存储二进制数据,可以存储4G以内的二进制数据。除此之外,还提供了BLOB、MediumBlob、TinyBlob字段来存储二进制数据,BLOB用于存储65K以内的二进制数据,MediumBlob用于存储16M以内的二进制数据,TinyBlob用来存储255字节以内的二进制数据。

JDBC提供了Blob接口来封装对MySQL二进制字段类型的存取封装操作,Blob接口包含了getBinaryStream()方法,用于获取InputStream输入流。

课程案例shop数据库的user(用户表)的photo字段就是LONGBLOB字段,可以存储4G以内的图文文件。写入二进制数据时,需要通过I/O流的方式从图片文件中读取数据。

案例8:在user表中插入一条记录,user表的photo是LONGBLOB类型字段,该字段的值需要从图片文件读入。

在demo包下新建SqlDemoTest8类。代码如下:

package demo;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
public class SqlDemoTest8 {
    // 定义JDBC加载路径
    static String jdbc = "com.mysql.cj.jdbc.Driver";
    // 定义MySQL数据库的连接地址
    static String mysqlurl = "jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2B8";
    // 定义MySQL数据库的用户名
    static String username = "root";
    // 定义MySQL数据库的用户名登录密码
    static String password = "~123456q";
 
    public static void main(String[] args)  throws FileNotFoundException {
        Connection conn = null;
        PreparedStatement prepartStatement = null;
        try {
            // 加载JDBC驱动
            Class.forName(jdbc);
            // 连接数据库
            conn = DriverManager.getConnection(mysqlurl, username, password);
            if (null != conn) {
                System.out.println(conn);
                // 向user表中插入一条记录
                String sql = "insert into user(id,name,loginName,psw,email,createDate,userType,photo)"
                        + "values(?,?,?,?,?,?,?,?)";
                // 实例化PreparedStatement对象
                prepartStatement = conn.prepareStatement(sql);
                // 设置id字段的值
                prepartStatement.setString(1,"0002");
                // 设置name字段的值
                prepartStatement.setString(2,"张三");
                // 设置loginName字段的值
                prepartStatement.setString(3,"zhansan");
                // 设置psw字段的值
                prepartStatement.setString(4,"123456");
                // 设置email字段的值
                prepartStatement.setString(5,"zhangsan@163.com");
                // 设置createDate字段的值
                java.util.Date date = new java.util.Date();
                java.sql.Date sqldate = new java.sql.Date(date.getTime());
                prepartStatement.setDate(6,sqldate);
                // 设置userType字段的值
                prepartStatement.setInt(7,0);
                // 定义一个File对象,准备从图片文件中读取数据
                File file = new File("d:" + File.separator + "head.png");
                InputStream input = new FileInputStream(file);
                prepartStatement.setBinaryStream(8, input, file.length());
                // 执行SQL语句
                int row  = prepartStatement.executeUpdate();
                if( row == 1 )
                {
                    System.out.println("user表添加记录成功");
                }
                else
                {
                    System.out.println("user表添加记录失败");
                }
                prepartStatement.close();
                conn.close();
            } else {
                System.out.println("数据库连接失败");
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}
SqlDemoTest9程序代码和SqlDemoTest7程序

代码基本相同,SqlDemoTest9使用FileInputStream将图片文件读取进来,然后通过PreparedStatement接口的setBinaryStream ()方法将图片文件内容写入到对应的二进制字段中。

批处理操作

PreparedStatement接口的addBatch()方法,可以将SQL更新语句的一组参数添加到SQL命令中,对SQL更新语句涉及的表中记录进行批量更新。数据库记录的批处理更新需要addBatch()方法和executeBatch()方法共同完成。

案例9:使用SQL语句批处理操作在shoper表中插入多个店铺。

在demo包下新建SqlDemoTest9类。代码如下:

package demo;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
 
public class SqlDemoTest9 {
    // 定义JDBC加载路径
    static String jdbc = "com.mysql.cj.jdbc.Driver";
    // 定义MySQL数据库的连接地址
    static String mysqlurl = "jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2B8";
    // 定义MySQL数据库的用户名
    static String username = "root";
    // 定义MySQL数据库的用户名登录密码
    static String password = "~123456q";
 
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement prepareStatement = null;
        try {
            // 加载JDBC驱动
            Class.forName(jdbc);
            // 连接数据库
            conn = DriverManager.getConnection(mysqlurl, username, password);
            if (null != conn) {
                System.out.println(conn);
                String name = "打印机专卖店";
                String brief = "打印机专业销售";
                // 向shoper表中插入条记录
                String sql = "insert into shoper(id,userId,name,brief,log,shopMoney,status,createDate)"
                        + "values(?,?,?,?,?,?,?,?)";
                // 实例化Statement对象
                prepareStatement = conn.prepareStatement(sql);
                // 批处理设置SQL语句更新参数
                for( int i = 0; i < 10; i++ )
                {
                    // 设置id字段的值
                    prepareStatement.setString(1,"0000" + i);
                    // 设置userId字段的值
                    prepareStatement.setString(2,"uoo" + i);
                    // 设置name字段的值
                    prepareStatement.setString(3,"店铺-" + i);
                    // 设置brief字段的值
                    prepareStatement.setString(4,"店铺结束-" + i);
                    // 设置log字段的值
                    prepareStatement.setString(5,"log" + i);
                    // 设置shopMoney字段的值
                    prepareStatement.setDouble(6,0.0);
                    // 设置status字段的值
                    prepareStatement.setInt(7, 0);
                    // 设置日期字段
                    java.util.Date date = new java.util.Date();
                    java.sql.Date sqldate = new java.sql.Date(date.getTime());
                    prepareStatement.setDate(8,sqldate);
                    prepareStatement.addBatch();
                }
                // 执行批处理
                int row[]  = prepareStatement.executeBatch();
                System.out.println("更新了" + row.length + "条记录");
                prepareStatement.close();
                conn.close();
            } else {
                System.out.println("数据库连接失败");
            }
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
 
    }
}

SqlDemoTest9程序在shoper表中插入10条记录。程序使用for循环,将10条记录的SQL插入命令,通过addBatch()方法添加到PreparedStatement对象的批处理命令中。最后通过executeBatch()方法执行批处理命令。

批处理执行完成后,数据库shoper表被插入了10条记录。

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论