Gravando/lendo campo Blob em banco Oracle 10g

Pessoal, estou colocando aqui a solução para gravar e ler um campo Blob num banco Oracle 10g Release 10.1.0.4.0.
É necessário utilizar o driver ojdbc14.jar (manifest 10.1.0.4.0) e os pacotes commons-fileupload-1.1.1.jar e commons-io-1.2.jar. (http://jakarta.apache.org/commons/fileupload/)
Notem que o exemplo do servlet é extremamente simples onde eu sequer fiz validação do tipo de arquivo para upload, está fixo um .jpg.

Exemplo .jsp:

[code]

MinhaTelaDeTeste

[/code]

Exemplo servlet:

[code]public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException {

Connection conn = null;
PreparedStatement pstmt = null;
Statement stmt = null;

try {
PoolConnection conexao = new PoolConnection();
DataSource jdbcURL = conexao.getJdbcURL(); // Conexão do tomcat
conn = jdbcURL.getConnection();
conn.setAutoCommit(false);

response.setContentType("text/html");

if (request.getContentType() != null) { // Se foi submetido o formulário com dados

	DiskFileItemFactory factory = new DiskFileItemFactory();
	ServletFileUpload upload = new ServletFileUpload(factory);
	
	upload.setSizeMax(-1); // Tamanho máximo do arquivo em bytes, quando -1 não tem limites
	factory.setSizeThreshold(500000); 
	
	List items = upload.parseRequest(request);
	Iterator iter = items.iterator();
	FileItem arquivo = null;
	
	while (iter.hasNext()) { // Processa todos os campos submetidos
	    FileItem item = (FileItem) iter.next();
	
	    if (item.isFormField()) { // Aqui retorna campos tipe text, radio, checkbox, etc
		System.out.println("Nome do campo: " + item.getFieldName()); 
	    } else { // senão retorna campo tipo file
		arquivo = item;
		//String fieldName = item.getFieldName();
		//String fileName = item.getName();
		//String contentType = item.getContentType();
		//boolean isInMemory = item.isInMemory();
		//long sizeInBytes = item.getSize();
	    }
	}			

	//Name                            Null?    Type
	//------------------------------- -------- ----
	//CD_ARQUIVO                               NUMBER(5)
	//DS_NOME_ARQUIVO                          VARCHAR2(50)
	//BL_ARQUIVO                               BLOB

	// Insere valores na tabela, porém sem conteúdo para o campo blob
	pstmt = conn.prepareStatement("insert into testeBlob values (?, ?, EMPTY_BLOB())");
	pstmt.setLong(1,100);
	pstmt.setString(2,arquivo.getName());
	pstmt.execute();

	stmt = conn.createStatement();
	// Consulta para ler o registro que acabou de ser incluído (modo exclusivo)
	ResultSet res = stmt.executeQuery("select bl_arquivo from testeblob where cd_arquivo = 100 for update");				
	
	if (res.next()) {
		Blob mapBlob = res.getBlob(1); // Guarda ponteiro do campo blob
		OutputStream blobOutputStream = mapBlob.setBinaryStream(0);
		blobOutputStream.write(arquivo.get()); // Atualiza campo blob
		blobOutputStream.close();
	}
	conn.commit(); // Grava as alterações no banco
	
	// Ler da base o registro gravado
	res = stmt.executeQuery("select bl_arquivo from testeblob where cd_arquivo = 100");				

	Blob mapBlob = null;
	if (res.next()) {
		mapBlob = res.getBlob(1);
	}			
	res.getStatement().close();
	
	// Gera o arquivo em disco com o conteúdo do campo blob
	InputStream blobStream = mapBlob.getBinaryStream();
	FileOutputStream fos = new FileOutputStream("D:\\Foto.jpg");
	byte[] buffer = new byte[10];      
	int nbytes = 0;       
	while( (nbytes = blobStream.read(buffer)) != -1 )        
		fos.write(buffer, 0, nbytes);
	fos.flush();
	fos.close();
	blobStream.close();
}

RequestDispatcher rd = request.getRequestDispatcher(“MinhaTelaDeTeste.jsp”);
rd.forward(request,response);

} catch (Exception ex) {
ex.printStackTrace();
}
finally {
try {
if (conn != null)
conn.close();
}
catch (Exception e) {
}
}
}[/code]

Olá Juliano, trago este tópico de volta, pois, estou com um problema ao tentar executar o código que vc descreveu. Peço, por favor, que me diga onde está o erro, pois acho que não está muito diferente do código q vc postou. Agradeço a ajuda de todos.
No meu servlet RenderPhoto.java está assim:

44 byte[] imageBytes = new byte[4096];
45 int nBytes;
46 InputStream imageStream = dbFoto.getBinaryStream(numero, cargo);
47 while((nBytes = imageStream.read(imageBytes)) != -1) {
48     imageStream.read(imageBytes, 0, nBytes);
49     out.write(imageBytes);
50 }

e o método de DBFoto que recupera a stream é (acho está ok):

public InputStream getBinaryStream(int numero, int cargo) throws SQLException {

  	Connection con = ConexaoDB.getInstance().getConnection();
  	PreparedStatement stm = null;
  	ResultSet rs = null;
  	InputStream in = null;
  	try {
  		String sqlCand = "SELECT sq_cand FROM admel06.candidato WHERE nr_cand = ? AND cd_cargo = ?";  		
  		String foto = "SELECT fl_foto FROM admel06.foto WHERE sq_cand = ?";
  		stm = con.prepareStatement(sqlCand);
  		stm.setInt(1, numero);
  		stm.setInt(2, cargo);
  		rs = stm.executeQuery();
  		rs.next();
  		int sq_cand = rs.getInt("sq_cand");
  		stm = con.prepareStatement(foto);
  		stm.setInt(1, sq_cand);
  		rs = stm.executeQuery();
  		rs.next();
  	  	Blob blob = rs.getBlob("fl_foto");
  	  	in = blob.getBinaryStream();
  	}
  	catch(SQLException e) {
  		throw e;
  	}
  	finally {
  		if(rs != null)
  			rs.close();
  		if(stm != null)
  			stm.close();
		con.close();
  	}
  	return in;
  }

Estou usando um tal de oracle_thin_driver.jar, mas já testei com o ojdbc14.jar e dá no mesmo.
Eu já debuguei com o Eclipse e o método realmente retorna a stream (linha 46), mas na hora de ler a stream para o array de bytes (linha 47) dá o seguinte erro:

WARNING: Servlet.service() for servlet RenderPhoto threw exception
java.io.IOException: Deve ter estabelecido logon no servidor
	at oracle.jdbc.dbaccess.DBError.SQLToIOException(DBError.java:717)
	at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:249)
	at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:158)
	at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:131)
	at br.gov.tream.fotoCandidato.Foto.RenderPhoto.doGet(RenderPhoto.java:47)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
	at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:667)
	at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
	at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
	at java.lang.Thread.run(Thread.java:595)

O engraçado é que aparece outro tipo de erro agora:

SEVERE: Servlet.service() for servlet RenderPhoto threw exception
java.lang.NullPointerException
	at oracle.sql.LobPlsqlUtil.plsql_read(LobPlsqlUtil.java:911)
	at oracle.sql.LobPlsqlUtil.plsql_read(LobPlsqlUtil.java:52)
	at oracle.jdbc.dbaccess.DBAccess.lobRead(DBAccess.java:658)
	at oracle.sql.LobDBAccessImpl.getBytes(LobDBAccessImpl.java:95)
	at oracle.sql.BLOB.getBytes(BLOB.java:175)
	at oracle.jdbc.driver.OracleBlobInputStream.needBytes(OracleBlobInputStream.java:126)
	at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:108)
	at oracle.jdbc.driver.OracleBufferedStream.read(OracleBufferedStream.java:91)
	at br.gov.tream.fotoCandidato.Foto.RenderPhoto.doGet(RenderPhoto.java:47)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
	at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:667)
	at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
	at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
	at java.lang.Thread.run(Thread.java:595)

Pelo seu segundo erro não há nada no stream (imageStream). Verifique se realmente está retornando algo da base.

Está sim(veja na imagem anexa a tela do debug).
O que mais poderia ser??


[RESOLVIDO]
Desculpe, Juliano, não atentei para um detalhe do seu código:
A conexão com o banco é fechada DEPOIS das operações de leitura/escrita sobre a InputStream.
Só percebi o erro após ver a explicação nesse post de outro fórum. No meu código, a classe do banco está naquele padrão: abre conexão, recupera dados, fecha conexão e entrega daods pro action, a NullPointerException era por causa da conexão fechada. :lol: