最近正好在学习JDBC原理,突发奇想地想将图片通过二进制存储到数据库中,但是在这个过程中出现了一些问题,什么问题呢,就请读者耐心地读下去,相信对JDBC二进制存储的过程不是很熟悉的朋友有一定的帮助!(毕竟花了彩笔博主的好几个小时呢~~~~)
先给大伙上代码:
public class Client {
private Connection connection = JDBCUtil.getConnection();
private Blob coverBlob = null;
private RenderedImage coverImage = null;
private PreparedStatement preparedStatement = null;
private FileInputStream fis = null;
private FileOutputStream fos = null;
public void get(String imageName,String destFilePath) throws SQLException, IOException {
fos = new FileOutputStream(new File(destFilePath));
preparedStatement = connection.prepareStatement("SELECT image FROM images WHERE imagename = ?;");
preparedStatement.setString(1, imageName);
ResultSet results = preparedStatement.executeQuery();
if (results.next()) {
coverBlob = results.getBlob(1);
coverImage = ImageIO.read(coverBlob.getBinaryStream());
}
System.out.println(ImageIO.write(coverImage, "jpg", fos));
}
public void insert(String imageName,String filePath) throws SQLException, IOException {
fis = new FileInputStream(new File(filePath));
coverBlob = connection.createBlob();
OutputStream out = coverBlob.setBinaryStream(1);
coverImage = ImageIO.read(fis);
ImageIO.write(coverImage,"jpg",out);
// System.out.println(coverBlob.length());
PreparedStatement ps = connection.prepareStatement("INSERT INTO images VALUES (null,?,?)");
ps.setString(1,imageName);
ps.setBlob(2,coverBlob);
ps.executeUpdate();
}
public static void main(String[] args) throws IOException, SQLException {
Client client = new Client();
client.insert("12345678999","D:\\桌面文件\\文件夹\\图片\\123.jpg");
client.get("12345678999","D:\\桌面文件\\01.jpg");
}
}
就是一个简单的连接数据库然后以二进制存储图片到数据库中的一段代码,大伙也可以看看,因为毕竟等会出现问题!!
但是为了照顾一些不熟悉这方面知识的朋友,我这边还是对几个关键的类和数据库表结构说一下:
项目 | Value |
---|---|
Blob (Binary large Object) | 位于 java.sql包下的一个用于存储Blob类型的基础数据类 |
ImageIO | 是javax扩展包中的imageio包下对Image类型的文件进行传输的一个类 |
数据库表结构我就直接上图了:
问题出现
直接上图!!好家伙直接给我报了一个非法参数异常,就是参数为空了,当时在第一次看到这个异常的时候,不就是一个image为空嘛,根据多年改bug经验,感觉一会就能整完(然后就。。。就度过了一段难过的时光)。
分析问题
好了,问题已经出现了,我们首先定位到出现问题的代码:
然后看一下这个方法的源代码:
这个方法的目的就是将图片以二进制数据写入到输出流中,然后,我们再看一下异常那句代码打印出来的:
是在ImageTypeSpecifier类中createFromRenderedImage方法中产生的,我们分析这个方法,他这里异常的产生是因为image是空值,也就是在ImageIO.write(coverImage, “jpg”, fos);中coverImage是个空的值,但是,我们这个CoverImage是通过读取数据库所获取的。好了,通过异常我基本就已经确定问题出现在哪了,就是从数据库中读取到了一个空的值,为什么是一个空的值呢,我反复确认了读取图片的方法,基本没有什么问题,所以问题肯定是出现在了存储图片的时候。
然后,我们现在来看看存储图片的代码(这个时候,我基本知道在哪出现问题):
我当时就是猜测在ps.setBlob()的时候传进去的coverBlob是空的,没有任何数据,然后,我开始开启debug模式开始找问题了。
查到这里的时候,我觉得没有什么问题,也就是在这个地方,我卡了很久,因为通过 ImageIO.write(coverImage,“jpg”,out);方法确实是将图片的二进制数据输出到了out流当中。当时的我已经开始怀疑是不是找错问题出现的地方了,然后我就不断找资料和文章(这个期间过了好几个小时),最终我找到了问题所在,在此之前,我们先看一下jdk文档对Blob中的setBinaryStream();方法的解释。
看这个解释,是不是觉得,我们通过这个方法获取的流是会将数据写入到Blob对象当中,当时我也是这么觉得,然后我自己又仔细的思考了一下,又不对,我们先看一下这个方法获取到流对象是什么
看到上面这句话没有,我们这个方法获取到的流对象是一个WatchableOutputStream对象,然后这个对象的继承关系如下
很好,我后面通过对这几个类的源码的查看,最终发现,这个流并不会将读取到的数据写入到Blob对象当中,好了,真相也就大白了,也就是说,我们这个流对象没有把二进制数据放入到Blob对象中,那么我们插入到数据库中的数据也肯定是一个空的值,所以才会报异常。
解决问题
我们已经知道了问题所在,那么剩下的就是改代码了,怎么改呢,我就直接上代码了。
public class Client {
private Connection connection = JDBCUtil.getConnection();
Blob coverBlob = null;
RenderedImage coverImage = null;
public void get(String imageName) throws SQLException, IOException {
FileOutputStream fos = new FileOutputStream(new File("D:\\桌面文件\\01.jpg"));
PreparedStatement preparedStatement = connection.prepareStatement("SELECT image FROM images WHERE imagename = ?;");
preparedStatement.setString(1, imageName);
ResultSet results = preparedStatement.executeQuery();
if (results.next()) {
coverBlob = results.getBlob(1);
coverImage = ImageIO.read(coverBlob.getBinaryStream());
}
System.out.println(ImageIO.write(coverImage, "jpg", fos));
preparedStatement.close();
results.close();
}
public void insert(String imageName, String filePath) throws SQLException, IOException {
FileInputStream fis = new FileInputStream(new File(filePath));
coverBlob = connection.createBlob();
long offset = 1l;
OutputStream out = coverBlob.setBinaryStream(offset);
byte[] buff = new byte[1024 * 1024];
byte[] outBuff = null;
int n = 0;
if ((n = fis.read(buff)) != -1) {
outBuff = new byte[n];
System.arraycopy(buff, 0, outBuff, 0, n);
buff = null;
out.write(outBuff, 0, n);
}
coverBlob.setBytes(1l, outBuff);
System.out.println(coverBlob.length());
PreparedStatement ps = connection.prepareStatement("INSERT INTO images VALUES (null,?,?)");
ps.setString(1, imageName);
ps.setBlob(2, coverBlob);
ps.executeUpdate();
out.flush();
out.close();
fis.close();
}
public static void main(String[] args) throws IOException, SQLException {
Client client = new Client();
client.insert("12345678999", "D:\\桌面文件\\文件夹\\图片\\123.jpg");
client.get("12345678999");
}
}
我们的目的还是要将图片数据存储到Blob对象当中,之前报异常的那种方式不行,我们就改一种方式就对了(具体是什么方式,大家看一下代码就基本了解了)。