java向mySQL中添加Blob的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java向mySQL中添加Blob的问题相关的知识,希望对你有一定的参考价值。

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import com.sue.dbutil.DBSource;
import com.sue.dbutil.SimpleDBSource;

public class addImg
public static void main(String[] args)

try
DBSource source = new SimpleDBSource() ;
Connection conn = source.getConnection();
if(conn!=null)
System.out.println("成功");

File file = new File("E:\\javaSue\\project\\QQ\\Img\\1.jpg");
int length = (int)file.length();
InputStream is = new FileInputStream(file);
String sql = "insert into img(name,blob) values(?,?)";
PreparedStatement pst = conn.prepareStatement(sql);
pst.setString(1, "1.jpg");
pst.setBinaryStream(2,is,length);
pst.executeUpdate();
catch (Exception e)
e.printStackTrace();



参考技术A 你的程序没有问题的,但很不标准优化。
1、创建类时,类型名首字母大写;
2、数据库连接Connection以及PreparedStatement等对象,用完后要关闭。

另外还要提醒你的是,在mysql里面不要用blob存大文件,用longblob类型。blob实际上存的信息比较少的:
TinyBlob 最大 255
Blob 最大 65K
MediumBlob 最大 16M
LongBlob 最大 4G追问

首先谢谢你的回答,这个类名是我为了测试先写的。

但是就是出现异常:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'blob) values('1.jpg',_binary'???à\0JFIF\0\0H\0H\0\0??\0C\0 ' at line 1

追答

你表的字段名用了关键字~~~blob,创建表的时候,你的字段不能用关键字的啊啊啊啊。。。

追问

!!!!你不早说~~~~~~~~~~~~~~
很谢谢你了~~!!!!
跪拜~~~~~

本回答被提问者采纳

试图从 mysql 检索文本和 blob 到 jtable

【中文标题】试图从 mysql 检索文本和 blob 到 jtable【英文标题】:trying to retrieve both text and blob from mysql to jtable 【发布时间】:2016-05-06 07:02:19 【问题描述】:

所以我试图以一种很好的方式从 jtable 内的数据库中检索文本和 blob(图像)。出于某种原因,每当我尝试检索 blob 时,我都会得到以下信息:

java.io.ByteArrayInputStream@1cb63183

在所有其他列中,尽管我已指定 blob 位于 8 号!

这是截图:

http://s24.postimg.org/t71o3izlh/Screen_Shot_2016_01_28_at_1_26_55_PM.png

这是我的代码

sql = "SELECT * FROM Products";  

ResultSet rs = stmt.executeQuery(sql);

  ResultSetMetaData rsmd = rs.getMetaData();
 // getting the columns number
  int columnsNumber = rsmd.getColumnCount();

// setting a vector with columns number
Vector columns = new Vector(columnsNumber);


 // adding column names
for(int i=1; i<=columnsNumber; i++)
columns.add(rsmd.getColumnName(i));

// setting a vector with row data
Vector rowdata = new Vector();
Vector row;
JTable table = new JTable(rowdata, columns);

while(rs.next())


 row = new Vector(columnsNumber);

    for(int i=1; i<=columnsNumber; i++)
   
    // adding the rows in "row vector"
    InputStream binaryStream = rs.getBinaryStream(i);
    row.add(rs.getString(i));
    row.add(rs.getBinaryStream(8));


// adding the rows in the database
rowdata.add(row);

有人可以向我解释为什么这种方法不起作用吗?

顺便说一句,如果我删除了这一行:

 row.add(rs.getBinaryStream(8));

获取 java.io.ByteArrayInputSteam 的问题将消失,但是,我只会获取图像的文本表示。

它实际上不是重复的,因为我试图将它添加到特定列中,具体取决于我拥有的行数,即文本和图像。所以它是动态完成的,sql同时具有图像和文本,这与“可能重复”不同

提前致谢!

【问题讨论】:

字节数组是图像的二进制表示,然后您需要将其转换回某种“图像” @MadProgrammer 它实际上不是重复的,因为我试图根据我拥有的行数将它添加到特定列中。所以它是动态完成的,sql同时具有图像和文本,这与“可能重复”不同 所以您不知道该列中实际包含哪些数据并且您不知道如何对其进行解码?作为对您的要求的一般评论,这听起来很疯狂。您需要两列,一列用于文本,一列用于图像,或者您需要另一列来指定数据类型。作为一般概念,该列应该代表它所持有的数据类型,例如imagetext,而不是data,这样就不可能知道它实际上是什么类型的数据 @MadProgrammer 好吧,只有第 8 列应该有图像。其余的将有文字。但是,SQL 查询只是我上面的一个。出于某种原因,虽然我已经为图像指定了第 8 列,但我仍然无法做到这一点。我什至尝试添加另一个“数据”,以便一个用于图像,另一个用于文本,但这也不起作用。 在我看来,一个错误会产生某种Exception,你所拥有的是一个错误 【参考方案1】:

所以,您似乎遇到了一系列复杂的问题。让我们从这里开始,从数据库中加载数据...

while(rs.next())
    
        row = new Vector(columnsNumber);

        for(int i=1; i<=columnsNumber; i++)
        
            // adding the rows in "row vector"
            InputStream binaryStream = rs.getBinaryStream(i);
            row.add(rs.getString(i));
            row.add(rs.getBinaryStream(8));
        
        // adding the rows in the database
        rowdata.add(row);
    

因此,对于ResultSet 中的每一行,您可以查看列,但是对于每一列,您添加 String 值和最后一列中的 blob,因此 blob 将被添加 6 次(基于在您的屏幕截图上)。显然,这不是您想要的,也是您在其他每一列中获得java.io.ByteArrayInputStream@1cb63183 的原因。

相反,您想遍历列1-columnsNumbers - 1,因为我们不想要最后一列,并将图像添加到最后一列,可能类似于...

while(rs.next())

    row = new Vector(columnsNumber);

    for(int i=1; i < columnsNumber; i++)
    
        // adding the rows in "row vector"
        InputStream binaryStream = rs.getBinaryStream(i);
        row.add(rs.getString(i));
    
    row.add(rs.getBinaryStream(8));
    // adding the rows in the database
    rowdata.add(row);

下一个问题...

它仍然在最后一列打印java.io.ByteArrayInputStream@1cb63183!?

这仅仅是因为您添加到row Vector 的只是表示数据库中二进制数据的二进制流,JTable 无法渲染它。您应该首先查看Concepts: Editors and Renderers 和Using Custom Renderers,了解有关如何自定义这些组件的渲染的更多详细信息

首先,我们需要将二进制数据转换为我们可以使用的图像格式

row.add(ImageIO.read(rs.getBinaryStream(8)));

并使用类似于Rendering BufferedImage in JTable cell 中概述的内容

row.add(new ImageIcon(ImageIO.read(rs.getBinaryStream(8))));

这应该允许“默认”TableCellRenderer 呈现它

可运行示例...

警告: 这个例子有点长,因为我必须构建数据库并填充它。为简单起见,它使用独立的H2 Database engine,但应该可以转换为大多数其他数据库。该示例还使用了blob 的列类型,这是故意的,因为它提高了数据库引擎的性能。

使用DefaultTableModel 时在JTable 中显示图像的问题是,DefaultTableModelTableModel#getColumnClass 方法返回Object.class

即使DefaultTableModel 文档也注意到了这一点...

警告: DefaultTableModel 返回一个 Object 的列类。什么时候 DefaultTableModelTableRowSorter 这将导致广泛使用 toString,用于非String 数据类型 太贵了。如果您使用 DefaultTableModelTableRowSorter 强烈建议您覆盖 getColumnClass 返回适当的类型。

我通过自定义从TestPane#makeTableModel 返回的DefaultTableModel 克服了这个问题...

DefaultTableModel model = new DefaultTableModel(new String[]"Name", "Image", 0) 
    @Override
    public Class<?> getColumnClass(int columnIndex) 
        return columnIndex == 1 ? Icon.class : super.getColumnClass(columnIndex);
    
;

这允许JTable 使用正确的TableCellRenderer

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;

public class Main 

    public static void main(String[] args) 
        try 
            Class.forName("org.h2.Driver");
            makeDatabase();
            populateDatabase();
            new Main();
         catch (ClassNotFoundException | SQLException | IOException exp) 
            exp.printStackTrace();
        
    

    protected static Connection makeConnection() throws SQLException 
        String path = "jdbc:h2:./TestDatabase";
        return DriverManager.getConnection(path, "sa", "");
    

    protected static void makeDatabase() throws SQLException 
        String cmd = "create table if not exists fruits ("
                + "key BIGINT IDENTITY, "
                + "name varchar(128), "
                + "image longblob)";
        try (Connection con = makeConnection()) 
            try (PreparedStatement stmt = con.prepareStatement(cmd)) 
                System.out.println("> Make fruits table");
                stmt.executeUpdate();
            
        
    

    protected static void populateDatabase() throws SQLException, IOException 
        removeAlFruits();
        insert("Apple", ImageIO.read(new File("Apple.png")));
        insert("Banana", ImageIO.read(new File("Banana.png")));
        insert("Cherries", ImageIO.read(new File("Cherries.png")));
        insert("Grapes", ImageIO.read(new File("Grapes.png")));
        insert("Orange", ImageIO.read(new File("Orange.png")));
        insert("Pear", ImageIO.read(new File("Pear.png")));
        insert("Pine Apple", ImageIO.read(new File("PineApple.png")));
        insert("Strewberry", ImageIO.read(new File("Strewberry.png")));
        insert("Water Melon", ImageIO.read(new File("WaterMelon.png")));
    

    protected static void insert(String name, BufferedImage image) throws SQLException, IOException 
        String cmd = "insert into fruits (name, image) values (?, ?)";
        try (Connection con = makeConnection()) 
            try (PreparedStatement stmt = con.prepareStatement(cmd)) 
                try (InputStream is = convertImageToInputStream(image)) 
                    System.out.println("> Insert " + name);
                    stmt.setString(1, name);
                    stmt.setBinaryStream(2, is);
                    int rows = stmt.executeUpdate();
                    System.out.println("> " + rows + " rows updated");
                
            
        
    

    protected static InputStream convertImageToInputStream(BufferedImage image) throws IOException 
        ByteArrayOutputStream baos = null;
        ByteArrayInputStream bais = null;
        try 
            baos = new ByteArrayOutputStream();
            ImageIO.write(image, "png", baos);
            baos.close();
            bais = new ByteArrayInputStream(baos.toByteArray());
         finally 
            if (baos != null) 
                try 
                    baos.close();
                 catch (IOException ex) 
                
            
        
        return bais;
    

    protected static void removeAlFruits() throws SQLException 
        String cmd = "delete from fruits";
        try (Connection con = makeConnection()) 
            try (PreparedStatement stmt = con.prepareStatement(cmd)) 
                System.out.println("> Remove all fruits");
                int rows = stmt.executeUpdate();
                System.out.println("> " + rows + " rows updated");
            
        
    

    public Main() 
        EventQueue.invokeLater(new Runnable() 
            @Override
            public void run() 
                try 
                    try 
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                     catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) 
                        ex.printStackTrace();
                    

                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                 catch (SQLException | IOException ex) 
                    ex.printStackTrace();
                
            
        );
    

    public class TestPane extends JPanel 

        public TestPane() throws SQLException, IOException 
            setLayout(new BorderLayout());
            DefaultTableModel model = makeTableModel();
            JTable table = new JTable(model);
            table.setRowHeight(100);
            add(new JScrollPane(table));
        

        protected DefaultTableModel makeTableModel() throws SQLException, IOException 
            DefaultTableModel model = new DefaultTableModel(new String[]"Name", "Image", 0) 
                @Override
                public Class<?> getColumnClass(int columnIndex) 
                    return columnIndex == 1 ? Icon.class : super.getColumnClass(columnIndex);
                

            ;
            String cmd = "select name, image from fruits";
            try (Connection con = makeConnection()) 
                try (PreparedStatement stmt = con.prepareStatement(cmd)) 
                    try (ResultSet rs = stmt.executeQuery()) 
                        while (rs.next()) 
                            String name = rs.getString(1);
                            Blob blob = rs.getBlob(2);
                            ImageIcon icon = null;
                            try (InputStream is = blob.getBinaryStream()) 
                                BufferedImage img = ImageIO.read(is);
                                icon = new ImageIcon(img);
                            
                            model.addRow(new Object[]name, icon);
                        
                    
                
            
            return model;
        

    

替代方法是使用自定义TableCellRender,如Rendering BufferedImage in JTable cell 中所示

【讨论】:

它实际上甚至没有在最后一列打印java.io.ByteArrayInputStream@1cb63183。就像读取图像的字符串一样,就像用记事本打开图像一样 最后一列打印的是什么?图片是如何插入数据库的? 原来 ImageIcon 方法确实有效,我可以通过 showMessageDialog 查看图像。所以我需要找到一种方法将其放入 Jtable 中。这是打印内容的屏幕截图:s21.postimg.org/6ku22ajjr/…。使用 JFileChooser 和 FileInputStream 插入图像 Rendering BufferedImage in JTable cell。理论上,如果TableModel#getColumnClass 方法返回ImageIcon.classIcon.class,则ImageIcon 应该由JTable 开箱即用地呈现。 这种情况不是只显示图片吗?我怎样才能指定哪个是哪个?另外,我没有使用 DefaultTableModel 我正在使用向量

以上是关于java向mySQL中添加Blob的问题的主要内容,如果未能解决你的问题,请参考以下文章

如何向 Azure 存储 Blob 上传添加身份验证

从Java向MySQL添加数据抛出异常

使用 java SDK 将标签添加到 blob

怎么用java向数据库中添加和删除数据?

添加 Azure 存储 Blob 容器输入绑定 Azure Functions Java

MySQL - 添加约束一次添加两次不同的情况