Gravando/lendo campo Blob em banco Oracle 10g

5 respostas
J

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:
<html>
   <head>
      <title>MinhaTelaDeTeste</title>
   </head>
   <body>
      <form name="sistema" method="post" action="<sua classe servlet>" enctype="multipart/form-data">
	<input type="file" name="arquivo">
	<br><br>
	<input type="submit" value="Carregar...">
      </form>
   </body>
</html>
Exemplo servlet:
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) {
	}
}
}

5 Respostas

M

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)
M

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)
J

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

M

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


M

[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:

Criado 29 de setembro de 2006
Ultima resposta 27 de nov. de 2006
Respostas 5
Participantes 2