I am querying a BLOB object from database and trying to write it in file system but I keep running into connection closed error. Here's the code
FileOutputStream out;
out = new FileOutputStream(filePathtoCreate+File.separator+filename);
Blob inBlob= jdbcTemplate.queryForObject("select BLOB_CONTENT from Table_A where name = ?" , Blob.class,new Object[] { filename});
InputStream in = inBlob.getBinaryStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
out.write(buf, 0, len);
}
in.close();
out.close();
} catch (SQLException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
When I run this code I get
java.sql.SQLRecoverableException: Closed Connection
at oracle.sql.BLOB.getDBAccess(BLOB.java:1122)
at oracle.sql.BLOB.getBinaryStream(BLOB.java:265)
I do not get this issue if I go by regular JDBC Connection, so why is this happening and how do I resolve it. Thanks in advance.
You can read Blob inside jdbcTemplate's query with RowMapper, example:
jdbcTemplate.query("select * from Report where id =?",
new Object[]{id}, (resultSet, i) -> {
return toReport(resultSet);
});
private Report toReport(ResultSet resultSet) throws SQLException {
InputStream contentStream = resultSet.getClob("CONTENT")
.getAsciiStream();
String content =
new Scanner(contentStream, "UTF-8").useDelimiter("\\A").next();
report.setContent(content);
Blob blob = resultSet.getBlob("IMAGE");
Query given SQL to create a prepared statement from SQL and a list of arguments to bind to the query, mapping each row to a result object via a RowMapper.
Related
How to download all file types in MySQL database using Java app and prevent one file from replacing the other?
How can I include all file types in my filepath=("D:\\sch work\\skirt\\filename.pdf"); so that I am able to download pdf, docx, jpeg etc, from a MySQL database using Java mouse click event on a JTable?
I have two problems.
I can only open a PDF files although I want to open docs, JPEG and img files.
Every time I download another file from a different row it replaces the existing one. I would like to keep all of them
Below please find my code for mouse click event and please suggest what I should add for it to work as I need it.
private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {
String filePath =("D:\\sch work\\skirt\\filename.pdf");
int BUFFER_SIZE = 4096;
try {
int cert_code= jTable1.getSelectedRow();
String tableClick=(jTable1.getModel().getValueAt(cert_code,3).toString());
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/employee_certificate","root","");
String sql= "SELECT cert FROM certificate WHERE cert_code =?" ;
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, tableClick);
ResultSet rs=pstmt.executeQuery();
if(rs.next()){
Blob blob = rs.getBlob("cert");
InputStream inputStream = blob.getBinaryStream();
OutputStream outputStream = new FileOutputStream(filePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
//JOptionPane.showMessageDialog(null,"file saved")
} }
catch (Exception e)
{JOptionPane.showMessageDialog(null,e);}
}
If you want something other than PDF, you should store what's in that cert blob, so you can send out the appropriate filename/type:
You get PDF because that's the exact+only file type you write out to:
String filePath =("D:\\sch work\\skirt\\filename.pdf");
^^^
Perhaps something more like (in pseudo-code):
select cert,filename,filetype from ...
filepath = 'd:\sch work\skirt' + filename
header('Content-type: ' + filetype);
here is my answer.God bless Marc B abundantly.
private void jTable1MouseClicked(java.awt.event.MouseEvent evt) {
int BUFFER_SIZE = 4096;
try {
int cert_code= jTable1.getSelectedRow();
String tableClick=(jTable1.getModel().getValueAt(cert_code,3).toString());
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/employee_certificate","root","");
String sql= "SELECT cert, cert_name FROM certificate WHERE cert_code =?" ;
PreparedStatement pstmt = con.prepareStatement(sql);
pstmt.setString(1, tableClick);
ResultSet rs=pstmt.executeQuery();
if(rs.next()){
String filename = rs.getString("cert_name");
Blob blob = rs.getBlob("cert");
InputStream inputStream = blob.getBinaryStream();
String filePath ="D:\\sch work\\skirt\\"+filename;
OutputStream outputStream = new FileOutputStream(filePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
outputStream.close();
//JOptionPane.showMessageDialog(null,"file saved")
} }
catch (Exception e)
{JOptionPane.showMessageDialog(null,e);}
}
Streaming confuses me - just when I think I'm grasping the idea, my code goes belly up.
I'm attempting to take in a string, gzip compress it, and store it in a PostGreSQL database. THEN I want to get it back out and re-transform it into an output stream. The error happens in my 'get' function when I attempt to read the stream into the GZIPstream. The error is:
java.util.zip.ZipException: Not in GZIP format
Here's the functions used to compress the string then put it into the database:
public Jstruct_FileImportRun setSnapshotXml(String inValue) throws IOException
{
return setSnapshotXml(new BufferedInputStream(new ByteArrayInputStream(inValue.getBytes())));
}
public Jstruct_FileImportRun setSnapshotXml(BufferedInputStream inValue)
{
try
{
ByteArrayOutputStream compressedBytes = new ByteArrayOutputStream(30000 * 1024);
GZIPOutputStream gzipStream = new GZIPOutputStream(compressedBytes);
byte[] transferBuffer = new byte[32 * 1024];
int readSize;
while ((readSize = inValue.read(transferBuffer)) != -1)
{
gzipStream.write(transferBuffer, 0, readSize);
}
inValue.close();
gzipStream.close();
getField(SNAPSHOT_XML).setValue(compressedBytes.toByteArray());
}
catch (IOException e)
{
throw new JstructException(e);
}
return this;
}
and here's the code (that throws an error) when I attempt to retrieve it:
public static void getSnapshotXml(Connection inConn, Long inRunId, OutputStream inOutputStream) throws Exception
{
SQLQuery query = new SQLQuery()
.addSelect(SNAPSHOT_XML)
.addFrom(getTable())
.addWhereClause(FILE_IMPORT_RUN_ID + " = " + inRunId);
ResultSet rs = null;
try
{
rs = query.execute(inConn);
if (rs.next())
{
InputStream stream = rs.getBinaryStream(SNAPSHOT_XML.name());
GZIPInputStream gzipStream = new GZIPInputStream(stream);
byte[] transferBuffer = new byte[32 * 1024];
int readSize;
while ((readSize = gzipStream.read(transferBuffer)) != -1)
{
inOutputStream.write(transferBuffer, 0, readSize);
}
gzipStream.close();
inOutputStream.close();
}
}
finally
{
SQLUtil.closeResultSetAndStatement(rs);
}
}
again, the error "java.util.zip.ZipException: Not in GZIP format" happens in the line "GZIPInputStream gzipStream = new GZIPInputStream(stream);"
Halp!! what am I doing wrong?
I have a file that I get as a byte[] and I have to persist it in my entity as Clob.
How to save a byte[] as java.sql.Clob?
To get a Clob from byte[] on Oracle, you can do
private Clob createClob(byte[] data, Connection conn) {
CLOB clob = null;
try {
clob = CLOB.createTemporary(conn, false, oracle.sql.CLOB.DURATION_SESSION);
clob.open(CLOB.MODE_READWRITE);
OutputStream out = (OutputStream) clob.setAsciiStream(0L);
out.write(data);
out.flush();
out.close();
}
catch (Exception e) {
logger.error("", e);
}
finally {
try {
if (clob != null && clob.isOpen()) clob.close();
}
catch (SQLException e) {
logger.error("Unable to close CLOB", e);
}
}
return clob;
}
To create a Blob (binary) is almost the same, just replacing clob by blob and OutputStream out = (OutputStream) blob.setBinaryStream(0L);
With Apache commons-io
byte[] data = IOUtils.toByteArray(clob.getAsciiStream());
if you need special encoding or you have some issue try:
byte[] data = IOUtils.toByteArray(clob.getCharacterStream(), "UTF-8");
javax.sql.rowset.serial.SerialClob can accept array of char and create a serializable Clob object.
You can refer here
http://docs.oracle.com/javase/7/docs/api/javax/sql/rowset/serial/SerialClob.html
javax.sql.rowset.serial.SerialBlob can accept array of bytes
You can refer here
http://docs.oracle.com/javase/7/docs/api/javax/sql/rowset/serial/SerialBlob.html
i am trying to get an image out of a mysql database where it is stored as a blob. so far i have tried three more or less different ways, non of which seem to take me anywhere. i must be making some stupid mistake here.
try {
// create a java mysql database connection
String myDriver = "org.gjt.mm.mysql.Driver";
Class.forName(myDriver);
Connection conn = DriverManager.getConnection(mySettings.dbConnect, mySettings.dbUser, mySettings.dbPass);
PreparedStatement stmt = conn.prepareStatement("select up.userid, up.name, la.languages, up.photo, up.dob, up.edited from userprofile up join languages la on up.languages_id = la.languages_id where up.userid = ?");
stmt.setString(1, userid);
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
// version 1
InputStream photois = rs.getBinaryStream("photo");
int ch;
String str = new String();
while ((ch = photois.read()) != -1) {
// here the exception occures when i InputStream.read().
// both Exception.getMessage() and Exception.getCause()
// of the caught exception yield null
str += (char)ch;
}
byte[] bdata=str.getBytes();
byte[] img64 = Base64.encode(bdata);
String photo64 = new String(img64);
// version 2
Blob b = rs.getBlob("photo");
byte[] ba = b.getBytes(1, b.length());
// b.length() throws exception, no message, no cause
byte[] img64 = Base64.encode(ba);
String photo64 = new String(img64);
// version 3
InputStream photois = rs.getBinaryStream("photo");
byte[] buf = IOUtils.toByteArray(photois);
// this throws an exception, message and cause both null as above
String photo64 = DatatypeConverter.printBase64Binary(buf);
}
conn.close();
}
catch (Exception e) {
System.err.println("Got an exception! (reading userprofile from db)");
System.err.println(e.getMessage());
System.err.println(e.getCause());
}
in all cases the console gives me this:
The Exception with null in getMessage() and getCause() is the NullPointerException.
The JavaDoc for ResultSet#getBinaryStream() states that it returns null for the column containing SQL NULL. Even though the JavaDoc for the ResultSet#getBlob() omits to mention the same, it looks to me that the test rows do not contain any data in the blob column, i.e. the blob is NULL in database.
I am trying to insert a file containing into a Sybase database. I am using JConnect-7.0.7
Here is my table:
CREATE TABLE blob_test (
blobVar IMAGE
)
I am inserting the image using:
String sql = "INSERT INTO blob_test VALUES (convert(binary,?))";
PreparedStatement stmt = conn.prepareStatement(sql);
File image = new File(filePath);
InputStream fis = new FileInputStream(image);
int ilen=(int) image.length();
stmt.setBinaryStream(1, fis, ilen);
stmt.execute();
And trying to retrieve the image using:
JdbcTemplate jdbcTemplate= new JdbcTemplate(dataSource);
List<Blob> result = jdbcTemplate.query(
"SELECT blobVar FROM blob_test", new Object[] {}, new RowMapper() {
#Override
public Blob mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getBlob(1);
}
});
for(int i=0;i<result.size();i++){
Blob b = result.get(i);
BufferedOutputStream os;
os = new BufferedOutputStream(new FileOutputStream(new File("output"+i+".zip")));
os.write(b.getBytes(1, (int) b.length()));
os.flush();
os.close();
}
However, when I execute my code it outputs 1kb zip files that are corrupted. My code works exactly as it should for an oracle database.
Alternatively, I have also tried this code to retrieve the file:
JdbcTemplate jdbcTemplate= new JdbcTemplate(dataSource);
List<InputStream> result = jdbcTemplate.query(
"SELECT * FROM blob_test", new Object[] {}, new RowMapper() {
#Override
public InputStream mapRow(ResultSet rs, int rowNum) throws SQLException {
return lobHandler.getBlobAsBinaryStream(rs, 1);
}
});
for(int i=0;i<result.size();i++){
InputStream in = result.get(i);
OutputStream out = new FileOutputStream(new File("outputTest"+i+".zip"));
byte[] buff = new byte[4096];
int len = 0;
while ((len = in.read(buff)) != -1) {
out.write(buff, 0, len);
}
out.flush();
out.close();
}
However, when I run this code I get an exception:
java.io.IOException: JZ0I9: This InputStream was closed.
at com.sybase.jdbc4.jdbc.ErrorMessage.raiseIOException(Unknown Source) at com.sybase.jdbc4.jdbc.ErrorMessage.raiseIOException(Unknown Source)
at com.sybase.jdbc4.jdbc.RawInputStream.checkMe(Unknown Source)
at com.sybase.jdbc4.jdbc.RawInputStream.read(Unknown Source)
at com.sybase.jdbc4.jdbc.RawInputStream.read(Unknown Source)
at blobtester.BlobTester.getOracleBlob(BlobTester.java:86)
at blobtester.BlobTester.main(BlobTester.java:34)
Again, this works for oracle. Is there anything I'm missing that is different about Sybase? Is the file being saved/retrieved correctly?
edit:
It turns out the problem was inserting the file into Sybase. I changed the code to:
File image = new File(filePath);
InputStream fis = new FileInputStream(image);
LobHandler lobHandler = new DefaultLobHandler();
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("INSERT INTO blob_test VALUES (?)", new Object[] {new SqlLobValue(fis, (int)image.length(), lobHandler)}, new int[] {Types.BLOB});
And it worked for both Sybase and oracle. Thanks.
Code from this link worked: http://forum.spring.io/forum/spring-projects/data/9931-sybase-and-blob-storing
[Just adding an answer, to close the question.]