在实际的开发过程中,我们可能需要把大文本或者二进制数据存储到数据库中,下面我们一起来学习一个如何使用JDBC向mysql中插入大文本数据。
在数据库中,大数据称为LOB(Large Objects),而LOB可以分为,clob和blob:
- clob用于存储大文本Text
-
blob用于存储二进制数据,例如图像、声音、二进制文等
在mysql中,提供了以下的数据类型来存储clob和blob:
- TINYTEXT(255)、TEXT(64k)、MEDIUMTEXT(16M)、LONGTEXT(4G)
- TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB
下面我们开始jdbc操作大数据文本text的例子。
1 . 新建一个数据库表:
test/bigtext
create table bigtext(
id int primary key auto_increment,
name varchar(20),
content MEDIUMTEXT
);
2. 新建一个项目
导入mysql连接驱动包,这里我们要导入最新mysql-connector-java-5.1.40-bin.jar版本,然后准备好数据库配置文件和数据库连接工具类
详见我写的另一篇文章: 自己写一个数据库连接工具类
3. 实现插入大文本代码
public static boolean insertBigtext(String name,String path){
Connection conn = null;
PreparedStatement pre = null;
try{
//获取连接
conn = mysqlConnUtil.getConn();
//获取传输器
pre = conn.prepareStatement("insert into bigtext values(null,?,?)");
pre.setString(1, name);
File file = new File(path);
pre.setCharacterStream(2, new FileReader(file), file.length());
return pre.executeUpdate() > 1 ? true : false;
}catch(Exception e){
e.printStackTrace();
}finally{
mysqlConnUtil.release(conn, pre, null);
return false;
}
}
这里要注意一个版本的问题,file.length()返回的数据是一个long类型的数据。
而我们查看JDK关于 PreparedStatement接口的方法描述时,可以发现
//将给定参数设置为给定 Reader 对象,该对象具有给定字符数长度。
//JDK1.2以上支持
void setCharacterStream(int parameterIndex, Reader reader, int length)
// 将指定参数设置为给定 Reader 对象,该对象具有给定字符数长度。
//JDK1.6以上支持
void setCharacterStream(int parameterIndex, Reader reader, long length)
当我们使用较低版本的mysql-connector时,如果不支持jdk1.6,那么就需要对file.length()进行类型转换为int类型,否则会报错。
4. 准备一个10M大文件,1.txt
5. 在main函数中调用方法
public static void main(String[] args) throws Exception {
insertBigtext("java jdbc","1.txt");
}
当我们运行的时候,发现报错了
com.mysql.jdbc.PacketTooBigException: Packet for query is too large (10886452 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3675)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2506)
at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2677)
at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2549)
at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1861)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2073)
at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2009)
at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5098)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1994)
at com.chen.Main.Main.insertBigtext(Main.java:34)
at com.chen.Main.Main.main(Main.java:78)
Packet for query is too large (10886452 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
上面这段错误信息表明,我们程序的Packet 太大了,超出了数据库设置的max_allowed_packet,需要修改一个这个参数。
为什么会出现这个错误呢,当我们的程序向数据库提交sql的时候,是通过一个数据包发送过去的,数据库为了保证安全和稳点,需要设置一个max_allowed_packet来保证用户不能一次性插入过大的数据。
我们在数据库的安装目录找到my.ini,修改max_allowed_packet这个属性的值为64m,重新启动数据库。运行项目:
这个时候又出现了一个新的问题:
The size of BLOB/TEXT data inserted in one transaction is greater than 10% of redo log size. Increase the redo log size using innodb_log_file_size.
这是由于mysql默认的数据库innodb数据库引擎。
我们可以使用命令查看数据库使用的引擎
默认情况下,MySQL 采用 autocommit 模式运行。这意味着,当执行一个用于更新(修改)表的语句之后,MySQL立刻把更新存储到磁盘中,同时记录锁也会被释放。那么事务提交后,在底层做了什么呢?
1. 把事务写入日志缓冲(log buffer),日志缓冲把事务刷新到事务日志.
2. 把事务写入缓冲池(Buffer pool).
数据库默认的innodb_log_file_size过小,导致我们在插入大文本的时候,数据库把事务写入日记缓冲的时候发生了错误。我们修改my.ini 中的innodb_log_file_size = 64M
(innodb_log_buffer_size 日志缓冲区大小 ,默认8M,一般不需要设置太大,除非有BLOB字段)
再重启一下数据库,并运行项目,插入数据库成功。
另外,还有一个问题需要注意一下
以前在进行大文本的插入时,还会发生java内存溢出的问题。这个时候需要配置两个参数,来设置java虚拟机的运行分配内存:
-Xms64M
-Xmx64M
-Xmsn
Specify the initial size, in bytes, of the memory allocation pool. This value must be a multiple of 1024 greater than 1MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
Examples:
-Xms6291456
-Xms6144k
-Xms6m
-Xmxn
Specify the maximum size, in bytes, of the memory allocation pool. This value must a multiple of 1024 greater than 2MB. Append the letter k or K to indicate kilobytes, or m or M to indicate megabytes. The default value is chosen at runtime based on system configuration. For more information, see HotSpot Ergonomics
Examples:
-Xmx83886080
-Xmx81920k
-Xmx80m
-Xmsn用来设置虚拟机的初始分配内存,也就是最小内存,-Xmxn用来分配虚拟机分配的最大内存
那么在eclipse中要如何配置这两个参数呢:
我们需要打开Run Configurations中进行arguments设置: