Tengo un problema al insertar en un campo Blob de Oracle.
Si el archivo es de 4Kb o menos no da ningun problema.
Compañeros, el problema me da cuando tengo un archivo de 5Kb, falla y da este error :
Una cosa mas, estoy ocupando un driver de Oracle y no utilizo ninguna clase especial de Oracle para la insercion.
Utilizo solo el java.io.* y el java.sql.*
java.sql.SQLException: No hay mßs datos para leer del socket
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
at oracle.jdbc.dbaccess.DBError.check_error(DBError.java:1160)
at oracle.jdbc.ttc7.MAREngine.unmarshalUB1(MAREngine.java:963)
at oracle.jdbc.ttc7.MAREngine.unmarshalSB1(MAREngine.java:893)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:375)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1894)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:109
4)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.ja
va:2132)
at oracle.jdbc.driver.OracleStatement.doExecuteOther(OracleStatement.jav
a:2015)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStateme
nt.java:2877)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePrepar
edStatement.java:608)
at EscribirBlob.insertarBlob(EscribirBlob.java:57)
Les transcribo el metodo donde me da el error :
private void insertarBlob(String sql, String archivo)
{
Connection con = null;
PreparedStatement pstmt = null;
FileInputStream fis = null;
byte[] buf = null;
try
{
int size = 0;
File file = new File(archivo);
if (file.exists())
{
fis = new FileInputStream(file);
size = (int) file.length();
System.out.println("size : " + size);
//buf = new byte[size];
//fis.read(buf);
}
else
{
System.out.println("Archivo : " + archivo + " no existe");
}
Conexion cone = new Conexion();
con = cone.getConexionBlob(); // todo esto lo pasa bien.
pstmt = con.prepareStatement(sql);
pstmt.setString(1, "KEY2");
pstmt.setBinaryStream(2, fis, size);
//pstmt.setBytes(2, buf);
pstmt.executeUpdate();
System.out.println("operacion exitosa");
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (fis != null)
{
fis.close();
}
if (pstmt != null)
{
pstmt.close();
}
if (con != null)
{
con.close();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
La linea 57 de mi programa donde marca el error es :
pstmt.executeUpdate();
public int add(BeanVenDocumentoArchivo bean) {
setIntError(-1);
CallableStatement cstm = null;
StringBuffer sql = new StringBuffer();
sql.append("{call PKG_VENTAS.sp_ven_documento_archivo_add(");
sql.append("?,?,?,?,?,");
sql.append("?,?,?,?");
sql.append(")}");
try {
cstm = connection.prepareCall(sql.toString());
cstm.setInt(1, bean.getBDocumento().getId());
cstm.setString(2, bean.getNombre());
cstm.setString(3, bean.getBArchivo().getNombre());
cstm.setString(4, bean.getBArchivo().getExtension());
/////SUBE UN ARCHIVO
byte[] data = new byte[bean.getBArchivo
().getSizeBytes()];
bean.getBArchivo().getInputStream().read(data);
oracle.sql.BLOB blob = oracle.sql.BLOB.createTemporary(
((org.apache.commons.dbcp.PoolableConnection) cstm
.getConnection()).getDelegate(), true,
oracle.sql.BLOB.DURATION_SESSION);
blob.open(oracle.sql.BLOB.MODE_READWRITE);
java.io.OutputStream out = blob.getBinaryOutputStream();
try {
out.write(data);
out.flush();
out.close();
} catch (IOException e) {
throw new SQLException("failed write to blob" + e.getMessage());
}
blob.close();
cstm.setBlob(5, blob);
///FIN SUBE ARCHIVO
cstm.setInt(6, bean.getBUsuario().getId());
cstm.registerOutParameter(7, OracleTypes.INTEGER);
cstm.registerOutParameter(8, OracleTypes.INTEGER);
cstm.registerOutParameter(9, OracleTypes.VARCHAR);
cstm.execute();
bean.setId(cstm.getInt(7));
setIntError(cstm.getInt(8));
setStrError(cstm.getString(9));
} catch (SQLException e) {
setIntError(-1);
setStrError(e.getMessage());
e.printStackTrace();
} catch (Exception e) {
setIntError(-1);
setStrError(e.getMessage());
e.printStackTrace();
} finally {
if (bean.getBArchivo().getInputStream() != null) {
try {
bean.getBArchivo().getInputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
Conexion.closeConnection(cstm, null, null, null);
}
/*
* if(getIntError()==0){ setIntError(add_blob(bean)); }
*/
return getIntError();
}
Tengo un problema al insertar en un campo Blob de Oracle.
Si el archivo es de 4Kb o menos no da ningun problema.
Compañeros, el problema me da cuando tengo un archivo de 5Kb, falla y da este error :Una cosa mas, estoy ocupando un driver de Oracle y no utilizo ninguna clase especial de Oracle para la insercion.
Utilizo solo el java.io.* y el java.sql.*
java.sql.SQLException: No hay mßs datos para leer del socket
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:134)
at oracle.jdbc.dbaccess.DBError.throwSqlException(DBError.java:179)
at oracle.jdbc.dbaccess.DBError.check_error(DBError.java:1160)
at oracle.jdbc.ttc7.MAREngine.unmarshalUB1 (MAREngine.java:963)
at oracle.jdbc.ttc7.MAREngine.unmarshalSB1(MAREngine.java:893)
at oracle.jdbc.ttc7.Oall7.receive(Oall7.java:375)
at oracle.jdbc.ttc7.TTC7Protocol.doOall7(TTC7Protocol.java:1894)
at oracle.jdbc.ttc7.TTC7Protocol.parseExecuteFetch(TTC7Protocol.java:109
4)
at oracle.jdbc.driver.OracleStatement.executeNonQuery(OracleStatement.ja
va:2132)
at oracle.jdbc.driver.OracleStatement.doExecuteOther (OracleStatement.jav
a:2015)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStateme
nt.java:2877)
at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePrepar
edStatement.java:608)
at EscribirBlob.insertarBlob (EscribirBlob.java:57)
Saludos,
Roy Hernandez
Saludos
Manifest-Version: 1.0
Specification-Title: "Oracle JDBC driver classes for use with JDK1.4"
Specification-Version: "Oracle JDBC Driver version - 9.0.2.0.0"
Specification-Vendor: "Oracle Corporation" .
Implementation-Title: "ojdbc14.jar"
Implementation-Version: "Oracle JDBC Driver version - 9.0.2.0.0"
Implementation-Vendor: "Oracle Corporation"
Implementation-Time: "Wed Feb 19 15:32:24 2003"
Smooth, no se si tu tienes algun driver mas reciente que me puedas enviarmelo por correo. Te lo agradeceria mucho y asi hare la prueba con el nuevo driver.
What is the longest value I can bind?
Method | Column Type | Maximum length |
---|---|---|
setBytes | LONG | 4k bytes |
setBytes | LONG RAW | 2G bytes |
setString | LONG | 32k chars (SetBigStringTryClob="false") 4k chars (SetBigStringTryClob="true") |
setString | CLOB | 2G chars |
In 9.2, setString() on a LONG can insert up to 64k characters with the OCI driver, and 4k characters with the Thin driver. In 10.1.0 we changed the limit for both drivers to 32k characters. We understand that reducing the limit for OCI from 64k to 32k may be a problem to some customers. However, considering the substantial performance improvement that this change made possible, and that Oracle is strongly recommending our customers to migrate from LONG to CLOB, we decided that the architectural change is necessary.
We recommend customers who need setString() to work over 32k characters to migrate from LONG to CLOB.
import oracle.jdbc.OracleResultSet;
import oracle.sql.BLOB;
public static void escribeFilesEnBd(Connection con,String
ficheroAleer) throws SQLException {
PreparedStatement stmt = null;
ResultSet rs = null;
try {
String nombreFichero="H:\\"+ficheroAleer;
File m_file= new File(nombreFichero);
FileInputStream fis=null;
PreparedStatement pstm1=null;
fis=new FileInputStream(m_file);
long filelength=m_file.length();
String valor=ficheroAleer.substring(0,ficheroAleer.length()-4);
pstm1=con.prepareStatement("insert into fotoempl values
(?,empty_blob(),(select cdnumnif from empleado where cdemplea=?)) ");
pstm1.setString(1,valor);
pstm1.setString(2,valor);
pstm1.executeUpdate();
pstm1.close();
con.setAutoCommit(false);
BLOB ablob=null;
PreparedStatement stm = con.prepareStatement("select foto from
fotoempl where cdemplea=? for update",ResultSet.TYPE_FORWARD_ONLY
,ResultSet.CONCUR_UPDATABLE);
stm.setString(1,valor);
rs =stm.executeQuery();
System.out.println("cogo el blob");
if (rs.next()){
ablob = ((OracleResultSet)rs).getBLOB("foto");
}
OutputStream os = ablob.getBinaryOutputStream();
int size = ablob.getBufferSize();
byte[] buffer = new byte[size];
int length = -1;
while ((length = fis.read(buffer)) != -1)
try{
os.write(buffer,0,length);
}catch(Exception e){
System.out.println("Error escribiendo el OutputStream"+e.toString()+"\n");
}
os.close();
fis.close();
pstm1.close();
} catch(Exception e) {
System.out.println("ERROR : " + e.toString());
}
finally {
if (stmt != null) {
stmt.close();
}
if (rs != null) {
rs.close();
}
con.commit();
}
El campo lo tengo definido como Blob, si esta definido como long raw
no permite hacerlo
}
> > ------------------------------
> > *De:* jav...@googlegroups.com [mailto:jav...@googlegroups.com] *En
> > nombre de *Juan Montanaro
> > *Enviado el:* jueves, 17 de agosto de 2006 8:16
> >
> > *Para:* jav...@googlegroups.com
> > *Asunto:* [JavaSOS] Re: Pregunta de Blob
> > > va:2132)
> > > at oracle.jdbc.driver.OracleStatement.doExecuteOther(
> > > OracleStatement.jav
> > > a:2015)
> > > at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout
> > > (OracleStateme
> > > nt.java:2877)
> > > at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate
> > > (OraclePrepar
saludos
package com.sae.arquitectura.dao.common.converter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
import oracle.sql.CLOB;
public class BigStringConverter implements UserType {
public BigStringConverter() {
super();
}
public int[] sqlTypes() {
return new int[] {Types.CLOB};
}
public Class returnedClass() {
return String.class;
}
public boolean equals(Object arg0, Object arg1) throws
HibernateException {
boolean ret = false;
if(arg0 == null || arg1 == null) {
ret = false;
}else if(!(arg0 instanceof String) || !(arg1
instanceof String)) {
ret = false;
}else {
ret = ((String)arg0).equals((String)
arg1);
}
return ret;
}
public int hashCode(Object arg0) throws HibernateException {
return arg0.hashCode();
}
// Esta es la ultima version que se publicaba en el foro de hibernate.
me parece que esta fallando
// public Object nullSafeGet(ResultSet arg0, String[] arg1, Object
arg2)throws HibernateException, SQLException {
// String ret = null;
// StringBuffer buffer = new StringBuffer();
// try {
// //First we get the stream
// InputStream is = arg0.getAsciiStream
// (arg1[0]);
// byte[] buf = new byte[1024];
// int read = -1;
//
// while((read = is.read(buf)) > 0) {
// buffer.append(new String
// (buf,0,read));
// }
// is.close();
// }catch(IOException ioe) {
// ioe.printStackTrace();
// throw new HibernateException("Unable to read from
resultset",ioe);
// }
// ret = buffer.toString();
// return ret;
// }
/**
* Esta version es mas vieja que la que esta comentada pero anda de
pelos
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object
owner) throws HibernateException, SQLException {
Reader clobReader = rs.getCharacterStream(names[0]);
if (clobReader == null)
return null;
StringBuffer str = new StringBuffer();
BufferedReader bufferedClobReader = new
BufferedReader(clobReader);
try {
String line = null;
while ((line = bufferedClobReader.readLine()) != null)
str.append(line);
} catch (IOException e) {
throw new SQLException(e.toString());
} finally {
try {
bufferedClobReader.close();
} catch (IOException e) {
}
}
return str.toString();
}
/* (non-Javadoc)
* (at) see org (dot) hibernate.usertype.UserType#nullSafeSet
(java.sql.PreparedStatement, java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement pst, Object value,int
index)throws HibernateException, SQLException {
if (value == null) {
pst.setNull(index, sqlTypes()[0]);
return;
}
try {
Connection conn =
pst.getConnection().getMetaData().getConnection();
Writer tempClobWriter = null;
CLOB tempClob = CLOB.createTemporary(conn, true,
CLOB.DURATION_SESSION);
try {
tempClob.open(CLOB.MODE_READWRITE);
tempClobWriter = tempClob.getCharacterOutputStream();
tempClobWriter.write((String) value);
tempClobWriter.flush();
} finally {
if (tempClobWriter != null)
tempClobWriter.close();
tempClob.close();
}
pst.setClob(index, (Clob) tempClob);
} catch (IOException e) {
throw new HibernateException(e);
}
}
public Object deepCopy(Object arg0) throws HibernateException {
String ret = null;
arg0 = arg0 == null? new String() : arg0;
String in = (String)arg0;
int len = in.length();
char[] buf = new char[len];
for(int i=0;i<len;i++) {
buf[i] = in.charAt(i);
}
ret = new String(buf);
return ret;
}
public boolean isMutable() {
return false;
}
public Serializable disassemble(Object arg0) throws
HibernateException {
return (String)arg0;
}
public Object assemble(Serializable arg0, Object arg1) throws
HibernateException {
return this.deepCopy(arg0);
}
public Object replace(Object arg0, Object arg1, Object arg2) throws
HibernateException {
return this.deepCopy(arg0);
}
}
Agradezco toda la ayuda de cada uno de ustedes. Al fin encontre la solucion.
Mucho me ayudaron los consejos y estar pasando horas a prueba y error.
Resulta que con un driver diferente de Oracle que es el mas reciente, lo
baje y probe.
Felizmente funciono.
Cual es la experiencia que aprendi ?
1- Estaba trabajando con un driver del anio 2003.
2- Este driver funciona para bases de datos anteriores a la 10G.
3- La tabla la creaba con base de datos de la 10G.
4- Uno debe tener el driver adecuado. Baje de un sitio el ultimo driver de
la 10G.
5- Borre la tabla, la volvi a crear pero utilizando este driver en un
software donde tu le configuras el driver de java.
6- Despues de hacer esto, puse en mi classpath el driver recien bajado.
7- Para alegria mia me funciono. Y algo mas, funciona igual para Mysql sin
tener que cambiar el codigo.
9- El archivo a insertar lo leia a puro java.io y formaba un arreglo de
byte.
10- El truco que aprendi es que puedo utilizar el metodo setBytes(int,
arreglo de byte) del PrepareStatement.
11- Antes yo tenia en mi mente que solamente podia ocupar el metodo setBlob
para hacer esto, y no es asi.
Se que Oracle tiene clases especiales para manejar este metodo
perfectamente, pero si te das cuenta solamente lo usaras para Oracle. En
cambio por el otro camino lo utilice ya para Mysql y no tengo que cambiar
codigo.
12- Finalmente hice una clase LeerBlob en la cual forme mi resultSet,
utilice el metodo getBytes e hice la reversa. Con ese array de bytes forme
otro archivo con extension .jpg, .gif, .png y saben que : me funciono.
A ese archivo, le llame copia.extension y para mi sorpresa, le daba doble
clic y era una copia exacta del archivo que habia insertado en el campo
BLOB.
Un dia de estos me voy a meter a Hibernate y se que me ayudara muchisimo tu
codigo smooth.
Un consejo final para los que inician con java : Busquen, busquen y busquen
porque hay cantidad de cosas que ya fueron hechas y que otra gente ya sudo
la camiseta.
Pero aparte de buscar, primero peleen ustedes lo mas que puedan, utilizando
lo que saben y usando la gran ayuda que te brinda la documentacion tecnica
de cada clase.
Gracias a todos.
Nota : La clase Conexion la tienes que hacer tu. Si no en su lugar coloca el
codigo para hacer la coneccion a tu base de datos.
Pero bueno, aqui los pego.
import java.sql.*;
import java.io.*;
public class EscribirBlob
{
public static void main(String[] args)
{
EscribirBlob eb = new EscribirBlob();
String sqlInsert = "INSERT INTO"
+ " pru_clob_blob2"
+ " (llave, descripcion)"
+ " VALUES (?, ?)";
String archivo = "./index_03_04.jpg";
//String archivo = "./Duke box.gif";
//String archivo = "./DukePoint.gif";
eb.insertarBlob(sqlInsert, archivo);
}
private void insertarBlob(String sql, String archivo)
{
Connection con = null;
PreparedStatement pstmt = null;
FileInputStream fis = null;
byte[] buf = null;
try
{
int size = 0;
File file = new File(archivo);
if (file.exists())
{
fis = new FileInputStream(file);
size = (int) file.length();
System.out.println("size : " + size);
buf = new byte[size];
fis.read(buf);
}
else
{
System.out.println("Archivo : " + archivo +
" no existe");
}
Conexion cone = new Conexion();
con = cone.getConexionBlob();
pstmt = con.prepareStatement(sql);
pstmt.setString(1, "KEY3");
pstmt.setBytes(2, buf);
pstmt.executeUpdate();
System.out.println("operacion exitosa");
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (fis != null)
{
fis.close();
}
if (pstmt != null)
{
pstmt.close();
}
if (con != null)
{
con.close();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
}
Para leer un campo BLOB y de lo que leo formo un archivo(copia) de imagen en
este caso:
Despues de correr el programa deberias encontrar un archivo copia.algo al
cual le puedes dar doble clic
y veras una copia exacta del archivo que insertaste en el campo blob.
Debes respetar la extension con la que insertastes en el blob para colocarle
la misma extesion al leer.
import java.sql.*;
import java.io.*;
public class LeerBlob
{
public static void main(String[] args)
{
LeerBlob lc = new LeerBlob();
lc.leerBytes("jpg");
}
private void leerBytes(String extension)
{
ResultSet rs = null;
Statement stmt = null;
Connection con = null;
FileOutputStream fos = null;
byte[] buf = null;
try
{
String sql = "SELECT descripcion"
+ " from pru_clob_blob2"
+ " where llave='KEY3'";
String archivo = "copia." + extension;
fos = new FileOutputStream(archivo);
Conexion cone = new Conexion();
con = cone.getConexionBlob();
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
rs.next();
buf = rs.getBytes(1);
System.out.println("pase el getBytes");
if (!rs.wasNull())
{
System.out.println("no va nulo");
fos.write(buf);
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
try
{
if (fos != null)
{
fos.close();
}
if (rs != null)
{
rs.close();
}
if (stmt != null)
{
stmt.close();
}