byte[] to be stored in Oracle - java

I have a byte[] which is actually an image.
i want to store it in Oracle 11g. I created a BLOB Column in my Table. and by following i tried to insert it.
String imageStr = "xyz...."
byte[] data = imageStr.getBytes();
String sQuery = "insert into Table (LOCATION , BLOB_DATA) Values ('Lahore', data) ";
It throws exception "java.sql.SQLException: ORA-01465: invalid hex number"
I searched it and found that this type of query should be done via PreparedStaement.
so i did something following
PreparedStatement prepStmt = dbConnection.prepareStatement("insert into Table (LOCATION, BLOB_DATA) values(?,?);
prepStmt.setString(1, 'Lahore');
prepStmt.setBytes(2, bytes);
I start getting error on dbConnection.prepareStatement(String) because the DBConnection class is not Java Native class.
It's a Custom class made by Earlier Developers for Database Connection and it do not has prepareStatement(String) function in it.
So what to do now??
1. Should i create a method prepareStatement(String) in DBConnection class?
2. Should i go for first approach?

You can look at my example to store image in db
Statement s;
Connection c;
FileInputStream fis;
PreparedStatement ps;
File file;
try
{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");//your driver
c=DriverManager.getConnection("Jdbc:Odbc:image","scott","tiger");//password and name changes according to your db
s=c.createStatement();
st.execute("Create table ImageStoring(Image_No number(5),Photo blob)");
}
catch(Exception e1)
{
e1.printStackTrace();
}
try
{
file=new File"D:/ARU/Aruphotos/4.jpg");
fis=new FileInputStream(file);
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
c=DriverManager.getConnection("Jdbc:Odbc:image","scott","tiger");
s=c.createStatement();
ps=c.prepareStatement("insert into ImageStoring values(?,?)");
ps.setInt(1,2);
ps.setBinaryStream(2,fis,(int)file.length());
System.out.println("success");
ps.execute();
ps.close();
c.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}

Related

Can't I save objects into sqlite in my android app

I tried to save an object into sqlite, and the class of the object has implemented Serializable. But there is always an error:
android.database.sqlite.SQLiteException: unrecognized token:
"[Ljava.lang.Object;#277c81d9" (code 1): , while compiling: insert
into mClass(classData) values(?)[Ljava.lang.Object;#277c81d9
Here is my code:
public boolean add(ReturnInfo ri) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
db = dh.getWritableDatabase();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(ri);
oos.flush();
byte[] data = bos.toByteArray();
bos.close();
oos.close();
db.execSQL("insert into mClass(classData) values(?)" + new Object[]{data});
db.close();
Log.e("db", "insert succeeded");
return true;
} catch (Exception e) {
e.printStackTrace();
Log.e("db", "insert failed");
return false;
}
The database has been created successfully, I have no idea where went wrong.
The issue is that you use prepared statements in a wrong way.
db.execSQL("insert into mClass(classData) values(?)" + new Object[]{data});
Here you generate inappropriate SQL statement because you just add an object to the end of the string and end up with something like this:
"insert into mClass(classData) values(?)[Ljava.lang.Object;#277c81d9"
which is not an SQL statement.
To use prepared statements you need write the following:
SQLiteStatement stmt =
db.compileStatement("insert into mClass(classData) values(?)");
stmt.bindString(1, data);
stmt.execute()
Also, look at this question to get a better understanding of prepared statements in android.

Using java to read files having oracle BFILE datatype from database

I have a table which contains location to files on the external filesystem.
The datatype used for column containing file locations is BFILE.
How to read such files from the database using java?
Hi please read following post and this Link will be helpful
This sample demonstrates Oracle JDBC BFILE support. It illustrates filling a table with BFILEs and includes a utility for dumping the contents of a BFILE. For information on BFILEs.
/*
* This sample demonstrate basic File support
*/
import java.sql.*;
import java.io.*;
import java.util.*;
//including this import makes the code easier to read
import oracle.jdbc.driver.*;
// needed for new BFILE class
import oracle.sql.*;
public class FileExample{
public static void main (String args [])throws Exception{
// Register the Oracle JDBC driver
DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
// Connect to the database
// You can put a database name after the # sign in the connection URL.
//
// The sample creates a DIRECTORY and you have to be connected as
// "system" to be able to run the test.
// I you can't connect as "system" have your system manager
// create the directory for you, grant you the rights to it, and
// remove the portion of this program that drops and creates the directory.
Connection conn =
DriverManager.getConnection ("jdbc:oracle:oci8:#", "system", "manager");
// It's faster when auto commit is off
conn.setAutoCommit (false);
// Create a Statement
Statement stmt = conn.createStatement ();
try
{
stmt.execute ("drop directory TEST_DIR");
}
catch (SQLException e)
{
// An error is raised if the directory does not exist. Just ignore it.
}
stmt.execute ("create directory TEST_DIR as '/tmp/filetest'");
try
{
stmt.execute ("drop table test_dir_table");
}
catch (SQLException e)
{
// An error is raised if the table does not exist. Just ignore it.
}
// Create and populate a table with files
// The files file1 and file2 must exist in the directory TEST_DIR created
// above as symbolic name for /private/local/filetest.
stmt.execute ("create table test_dir_table (x varchar2 (30), b bfile)");
stmt.execute ("insert into test_dir_table values
('one', bfilename ('TEST_DIR', 'file1'))");
stmt.execute ("insert into test_dir_table values
('two', bfilename ('TEST_DIR', 'file2'))");
// Select the file from the table
ResultSet rset = stmt.executeQuery ("select * from test_dir_table");
while (rset.next ())
{
String x = rset.getString (1);
BFILE bfile = ((OracleResultSet)rset).getBFILE (2);
System.out.println (x + " " + bfile);
// Dump the file contents
dumpBfile (conn, bfile);
}
// Close all resources
rset.close();
stmt.close();
conn.close();}
// Utility function to dump the contents of a Bfile
static void dumpBfile (Connection conn, BFILE bfile) throws Exception{
System.out.println ("Dumping file " + bfile.getName());
System.out.println ("File exists: " + bfile.fileExists());
System.out.println ("File open: " + bfile.isFileOpen());
System.out.println ("Opening File: ");
bfile.openFile();
System.out.println ("File open: " + bfile.isFileOpen());
long length = bfile.length();
System.out.println ("File length: " + length);
int chunk = 10;
InputStream instream = bfile.getBinaryStream();
// Create temporary buffer for read
byte[] buffer = new byte[chunk];
// Fetch data
while ((length = instream.read(buffer)) != -1)
{
System.out.print("Read " + length + " bytes: ");
for (int i=0; i<length; i++)
System.out.print(buffer[i]+" ");
System.out.println();
}
// Close input stream
instream.close();
// close file handler
bfile.closeFile();}}
Use the following link
https://docs.oracle.com/cd/A97335_02/apps.102/a83724/oralob3.htm#1059336
There you will find many examples like this
OraclePreparedStatement ops = (OraclePreparedStatement)conn.prepareStatement
("INSERT INTO my_bfile_table VALUES (?,?)");
ops.setString(1,"one");
ops.setBFILE(2, bfile);
ops.execute();

Making Oracle DB connection Dynnamically in JSP

Connecting to database dynamically jsp
Hi, I'm trying to make connection to database dynamically.
So when user clicks link from index page, it will send parameter "OS"
so my test page will receive parameter OS, looks for matchs in textfile that has list of database information like
XP-jdbc:oracle:thin#xx.xxx.xx.xx:xxxx:XPXP1-XP_user-XP_pass
W7-jdbc:oracle:thin#YY.YYY.YY.YY:YYYY:W7W71-W7_user-W7_pass
MAC-jdbc:oracle:thin#ZZ.ZZZ.ZZ.ZZ:ZZZZ:MACO1-MAC_user-MAC_pass
LINNUX-jdbc:oracle:thin#AA.AAA.A.AA:AAAA:LINN1-LINNUX_user-LINNUX_ph1
my attempt:
String userName = request.getParameter("OS");
try{
String db = "";
String[] temp1;
String dblist = root + "\\" + "dblist.txt";
BufferedReader dbin = new BufferedReader(new FileReader(dblist));
while ((db = dbin.readLine()) != null){
temp1=db.split("-");
if ((temp1[0].equals(userName))){
connString = temp1[1].toString();
connUser = temp1[2].toString();
connPass = temp1[3].toString();
}
}
dbin.close();
}catch (IOException ex) {
System.out.println(ex);
}
try{
DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Connection conn = DriverManager.getConnection(connString, connUser, connPass);
Statement stmt = conn.createStatement();
}
My problem is, this doesn't work!
I get java.sql.SQLException: Invalid Oracle URL specified when i open my web page....
What did i have wrong?
Apparently my property file was corrutped >.> that was the reason why my property file only read half of it's components...thanks for your help anyways
you could use Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); instead of DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
Also,have you checked if YY.YYY.YY.YY:YYYY is replaced by proper IP and port?

Image not served inside jsp from Servlets

I have a jsp wherein for each row of the table i need to display the image present in the database. I retrieve all the table row data from database including image as Blob and store it in a bean. The image is stored in the bean as byte array like this:
photo = rs.getBlob("PHOTO");
photoByteArray = photo.getBytes(1, (int)photo.length());
While looping over the list of beans in jsp, the src attribute points to a servlet like this:
<img class="img" width="55" height="50" src="displayThumbnail?photoData=${part.photoData}">
which serves the image like shown below but they don't show up however upon debugging the byte array do seem to have data.
protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("image/jpeg");
OutputStream o = response.getOutputStream();
String photoDataStr = request.getParameter("photoData");
byte[] photoData = null;
if(photoDataStr != null) {
photoData = photoDataStr.getBytes();
}
o.write(photoData);
o.close();
}
However the image doesn't show up. Now, if i query the database for each individual image as shown below, the images do show up fine in that case.
protected void processRequest(HttpServletRequest request, HttpServletResponse response) {
PreparedStatement pstmt = null;
ResultSet rs = null;
Connection conn = null;
try {
if(conn == null) {
conn = open();
}
pstmt = conn.prepareStatement("select photo from PART_PHOTOS where id = ?");
String id = request.getParameter("id");
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if (rs.next()) {
Blob b = rs.getBlob("photo");
response.setContentType("image/jpeg");
response.setContentLength((int) b.length());
InputStream is = b.getBinaryStream();
OutputStream os = response.getOutputStream();
byte buf[] = new byte[(int) b.length()];
is.read(buf);
os.write(buf);
os.close();
is.close();
}
} catch (Exception ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
pstmt = null;
}
//check if it's the end of the loop
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
I would highly appreciate if anyone can provide any recommendations around the same.
You're assuming that you can put random binary data into an HTML file, and it will be parsed correctly, and sent back to your server intact. This is a bad assumption! If nothing else, the byte that corresponds to the ASCII for the quote character is going to cause problems, right? Not to mention encoding issues, and the fact that the parameters to a URL must be urlencoded. This is just doomed to fail.
To make this work, you'd have to have some kind of explicit text encoding of the binary data when you serve the page (base64, maybe), and then decode the servlet parameter back to binary image data after the URL is posted back.
Your first processRequest() snippet is only sending back the byte representation of the photoData request parameter and not the photo data identified by the parameter. Looks like a bug in your code.
It seems you are trying to solve your problem in the wrong manner. When you first create the HTML table, storing the image in your "bean" from your first query gives you nothing unless you cache the data, and the subseqent displayThumbnail request retrieves the image from the cache, avoiding the database query.
If you do not want to mess with caching, then there is no need to store the image in your initial bean since it gives you nothing, and just do something like your second processRequest() snippet to fetch the image directly when the browser asks for it.
Your ${part.photoData} expression must return some ID. In the processRequest() method you must get that ID value (by using request.getParameter("photoData")) and by that value retrieve image from database (or better from cache or from file system) and send the binary data to web client.

How to overcome OutOfMemoryError during huge file write

I am writing a full database extract program in java. Database is Oracle, and it is huge. Some tables have ~260 million records. The program should create one file per table in a specific format, so using Oracle datapump etc is not an option. Also, some company security policies do not allow to write a PL/SQL procedure to create files on DB server for this requirement. I have to go with Java and JDBC.
The issue I am facing is that Since files for some of the table is huge (~30GB) I am running out of memory almost every time even with a 20GB Java Heap. During the creation of file when the file size exceeds the heap size, even with one of the most aggressive GC policy, the process seems to hang-up. For example if the file size is > 20GB and heap size is 20GB, once heap utilization hits max heap size, its slows down writing 2MB per minute or so and at this speed, it will take months to get full extract.
I am looking for some way to overcome this issue. Any help would be greatly appreciated.
Here are some details of the system configuration I have:
Java - JDK1.6.0_14
System config - RH Enterprise Linux (2.6.18) running on 4 X Intel Xeon E7450 (6 cores) #2.39GH
RAM - 32GB
Database Oracle 11g
file wirting part of the code goes below:
private void runQuery(Connection conn, String query, String filePath,
String fileName) throws SQLException, Exception {
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = conn.prepareStatement(query,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(maxRecBeforWrite);
rs = stmt.executeQuery();
// Write query result to file
writeDataToFile(rs, filePath + "/" + fileName, getRecordCount(
query, conn));
} catch (SQLException sqle) {
sqle.printStackTrace();
} finally {
try {
rs.close();
stmt.close();
} catch (SQLException ex) {
throw ex;
}
}
}
private void writeDataToFile(ResultSet rs, String tempFile, String cnt)
throws SQLException, Exception {
FileOutputStream fileOut = null;
int maxLength = 0;
try {
fileOut = new FileOutputStream(tempFile, true);
FileChannel fcOut = fileOut.getChannel();
List<TableMetaData> metaList = getMetaData(rs);
maxLength = getMaxRecordLength(metaList);
// Write Header
writeHeaderRec(fileOut, maxLength);
while (rs.next()) {
// Now iterate on metaList and fetch all the column values.
writeData(rs, metaList, fcOut);
}
// Write trailer
writeTrailerRec(fileOut, cnt, maxLength);
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
try {
fileOut.close();
} catch (IOException ioe) {
fileOut = null;
throw new Exception(ioe.getMessage());
}
}
}
private void writeData(ResultSet rs, List<TableMetaData> metaList,
FileChannel fcOut) throws SQLException, IOException {
StringBuilder rec = new StringBuilder();
String lf = "\n";
for (TableMetaData tabMeta : metaList) {
rec.append(getFormattedString(rs, tabMeta));
}
rec.append(lf);
ByteBuffer byteBuf = ByteBuffer.wrap(rec.toString()
.getBytes("US-ASCII"));
fcOut.write(byteBuf);
}
private String getFormattedString(ResultSet rs, TableMetaData tabMeta)
throws SQLException, IOException {
String colValue = null;
// check if it is a CLOB column
if (tabMeta.isCLOB()) {
// Column is a CLOB, so fetch it and retrieve first clobLimit chars.
colValue = String.format("%-" + tabMeta.getColumnSize() + "s",
getCLOBString(rs, tabMeta));
} else {
colValue = String.format("%-" + tabMeta.getColumnSize() + "s", rs
.getString(tabMeta.getColumnName()));
}
return colValue;
}
Its probably due to the way you call prepareStatement, see this question for a similar problem. You don't need scrollability and a ResultSet will be read-only be default so just call
stmt = conn.prepareStatement(query);
Edit:
Map your database tables to Class usig JPA.
Now load collection of Objects from DB using Hibernate in the Batch of some tolerable size and serialize it to FILE .
Is your algorithm like the following? This is assuming a direct mapping between DB rows and lines in the file:
// open file for writing with buffered writer.
// execute JDBC statement
// iterate through result set
// convert rs to file format
// write to file
// close file
// close statement/rs/connection etc
Try using Spring JDBC Template to simplify the JDBC portion.
I believe this must be possible on default 32 MB java heap. Just fetch each row, save the data to file stream, flash and close once done.
What value are you using for maxRecBeforWrite?
Perhaps the query of the max record length is defeating your setFetchSize by forcing JDBC to scan the entire result for record length? Maybe you could delay writing your header and note the max record size on the fly.

Categories