Connection Closed error on querying BLOBs from JdbcTemplate - java

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

Prevent downloaded files from replacing or overwriting each other

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);}
}

Error: Not in GZIP format - attempt to decompress GZIP stream previously stored in a database field

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?

How to save a byte[] as java.sql.Clob?

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

how to convert a java.sql.blob to a base64 encoded string in java

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.

Inserting/Retrieving a file from Sybase

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.]

Categories

Resources