Classe Generica trabalhando com stored procedure
Colega, tenho a classe abaixo que funciona perfeitamente como select. A mesma é do curso do Dyego sobre Desvendando o swing. Com o select tudo bem, como disse, mas eu gostaria de trabalha com procedure. Tem como adaptar? Minha conexao é com Oracle
[COD]package treinamento.dao;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.logging.Level;import java.util.logging.Logger;
public abstract class GenericaDao {
private static final long serialVersionUID = 1L;
public Connection getConnection() { try { Class.forName("oracle.jdbc.OracleDriver"); Connection cx = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","teste","teste"); return cx; } catch (Exception ex) { Logger.getLogger(GenericaDao.class.getName()).log(Level.SEVERE, null, ex); return null; } }
public Statement getStatement() throws SQLException { return getConnection().createStatement(); }
public PreparedStatement getStatement(String st) throws SQLException { return getConnection().prepareStatement(st); }
public ResultSet executeQuery(String query,Object... params) throws SQLException { PreparedStatement ps = getStatement(query); for (int i = 0; i < params.length; i++) { ps.setObject(i+1, params[i]); } return ps.executeQuery(); }
public int executeCommand(String query,Object... params) throws SQLException { PreparedStatement ps = getStatement(query); for (int i = 0; i < params.length; i++) { try { ps.setObject(i+1, params[i]); } catch (Exception e) { System.out.println("Error to try "+i+" with value "+params[i]); } } int result = ps.executeUpdate(); ps.close(); return result; }
}[/CODE]
[COD]package treinamento.dao;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.logging.Level;import java.util.logging.Logger;
public abstract class GenericaDao {
private static final long serialVersionUID = 1L;
public Connection getConnection() { try { Class.forName("oracle.jdbc.OracleDriver"); Connection cx = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","teste","teste"); return cx; } catch (Exception ex) { Logger.getLogger(GenericaDao.class.getName()).log(Level.SEVERE, null, ex); return null; } }
public Statement getStatement() throws SQLException { return getConnection().createStatement(); }
public PreparedStatement getStatement(String st) throws SQLException { return getConnection().prepareStatement(st); }
public ResultSet executeQuery(String query,Object... params) throws SQLException { PreparedStatement ps = getStatement(query); for (int i = 0; i < params.length; i++) { ps.setObject(i+1, params[i]); } return ps.executeQuery(); }
public int executeCommand(String query,Object... params) throws SQLException { PreparedStatement ps = getStatement(query); for (int i = 0; i < params.length; i++) { try { ps.setObject(i+1, params[i]); } catch (Exception e) { System.out.println("Error to try "+i+" with value "+params[i]); } } int result = ps.executeUpdate(); ps.close(); return result; }
}[/CODE]
Nilo Souza
Curtidas 0
Respostas
Anthony Accioly
28/05/2011
Nilo.
Tem sim.
A API JDBC Possui CallableStatements (http://download.oracle.com/javase/6/docs/api/java/sql/CallableStatement.html) para fazer exatamente isso:
A sintaxe funciona assim:
#Código{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
Eis um exemplo de código fonte: http://www.java2s.com/Code/Java/Database-SQL-JDBC/CallStoredProcedureInOracleAndPassInOutParameters.htm
Para recuperar um cursor do Stored Procedure você vai ter que registrá-lo com a sequinte sintaxe antes de recuperar o ResultSet:
#CódigoregisterOutParameter(<nome-do-cursor>, OracleTypes.CURSOR);
Eis um exemplo: http://www.andrels.com/wp-en_US/index.php/2010/01/retieving-an-oracle-cursor-in-java/
Espero ter ajudado.
Abraços,
Tem sim.
A API JDBC Possui CallableStatements (http://download.oracle.com/javase/6/docs/api/java/sql/CallableStatement.html) para fazer exatamente isso:
A sintaxe funciona assim:
#Código{?= call <procedure-name>[(<arg1>,<arg2>, ...)]}
Eis um exemplo de código fonte: http://www.java2s.com/Code/Java/Database-SQL-JDBC/CallStoredProcedureInOracleAndPassInOutParameters.htm
Para recuperar um cursor do Stored Procedure você vai ter que registrá-lo com a sequinte sintaxe antes de recuperar o ResultSet:
#CódigoregisterOutParameter(<nome-do-cursor>, OracleTypes.CURSOR);
Eis um exemplo: http://www.andrels.com/wp-en_US/index.php/2010/01/retieving-an-oracle-cursor-in-java/
Espero ter ajudado.
Abraços,
GOSTEI 0
Nilo Souza
28/05/2011
Achei que fosse mais simples, precisarei estudar mais.
GOSTEI 0
Anthony Accioly
28/05/2011
Nilo,
Ok. Tendo uma dúvida mais específica pode perguntar.
No geral o CallableStatement é muito parecido com o PreparedStatement que você está usando nesse código.
Se você chegou a dar uma olhada no último exemplo, seu uso é bastante direto:
Eu não gosto muito desse padrão de sair percorrendo var-args de Objects e chamando setObject por índice (apesar de muitos frameworks fazerem isso...). Porém, é possível fazer uma adaptação trivial do seu método executeQuery para fazer o que você quer. Apenas troque a versão para obter uma CallableStatement da conexão, sete o parâmetro de saída para o cursor, faça uma chamada para execute e obtenha o ResultSet a partir do cursor. Tudo como no exemplo acima.
Ok. Tendo uma dúvida mais específica pode perguntar.
No geral o CallableStatement é muito parecido com o PreparedStatement que você está usando nesse código.
Se você chegou a dar uma olhada no último exemplo, seu uso é bastante direto:
//Calling Oracle procedure
CallableStatement cs = conn.prepareCall("{call PAC_CURSOR.PRO_RETURN_CARS(?,?)}");
//Defining type of return
cs.registerOutParameter("o_cursor", OracleTypes.CURSOR);
cs.setLong("i_id", id);
cs.execute();//Running the call
//Retrieving the cursor as ResultSet
ResultSet rs = (ResultSet)cs.getObject("o_cursor");
//Iterating the returned rows
while(rs.next()){
//Getting column values
System.out.println("ID: " + rs.getLong("car_id"));
System.out.println("Manufacturer: " + rs.getString("company"));
System.out.println("Model: " + rs.getString("model"));
System.out.println("Color: " + rs.getString("color"));
System.out.println("HP: " + rs.getString("hp"));
System.out.println("Price: " + rs.getFloat("price"));
}
Eu não gosto muito desse padrão de sair percorrendo var-args de Objects e chamando setObject por índice (apesar de muitos frameworks fazerem isso...). Porém, é possível fazer uma adaptação trivial do seu método executeQuery para fazer o que você quer. Apenas troque a versão para obter uma CallableStatement da conexão, sete o parâmetro de saída para o cursor, faça uma chamada para execute e obtenha o ResultSet a partir do cursor. Tudo como no exemplo acima.
GOSTEI 0
Nilo Souza
28/05/2011
Caro,
se comecei a entender comecei a trilhar desse jeito.
MINHA CLASSE DE PROCEDURE GENERICA
MINHA CLASSE DAO PARA INSERIR, ALTERAR E EXCLUIR
se comecei a entender comecei a trilhar desse jeito.
MINHA CLASSE DE PROCEDURE GENERICA
package treinamento.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class GenericaDao_Proc {
private static final long serialVersionUID = 1L;
public Connection getConnection() {
try {
Class.forName("oracle.jdbc.OracleDriver");
Connection cx = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","TESTE","TESTE");
return cx;
} catch (Exception ex) {
Logger.getLogger(GenericaDao_Proc.class.getName()).log(Level.SEVERE, null, ex);
return null;
}
}
public Statement getStatement() throws SQLException {
return getConnection().createStatement();
}
public PreparedStatement getPrepared(String st) throws SQLException {
return getConnection().prepareStatement(st);
}
public CallableStatement getCallableStatement(String st) throws SQLException{
return getConnection().prepareCall(st);
}
public ResultSet executeQuery(String query,Object... params) throws SQLException {
PreparedStatement ps = getPrepared(query);
for (int i = 0; i < params.length; i++) {
ps.setObject(i+1, params[i]);
}
return ps.executeQuery();
}
public int executePrepered(String query,Object... params) throws SQLException {
PreparedStatement ps = getCallableStatement(query);
for (int i = 0; i < params.length; i++) {
try {
ps.setObject(i+1, params[i]);
} catch (Exception e) {
System.out.println("Error to try "+i+" with value "+params[i]);
}
}
int result = ps.executeUpdate();
ps.close();
return result;
}
public int executeCommand(String query,Object... params) throws SQLException {
PreparedStatement ps = getPrepared(query);
for (int i = 0; i < params.length; i++) {
try {
ps.setObject(i+1, params[i]);
} catch (Exception e) {
System.out.println("Error to try "+i+" with value "+params[i]);
}
}
int result = ps.executeUpdate();
ps.close();
return result;
}
}
MINHA CLASSE DAO PARA INSERIR, ALTERAR E EXCLUIR
package treinamento.dao;
import treinamento.entidade.Usuario;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
/**
*
* @author Nilo
*/
public class Usuario_Proc_Dao extends GenericaDao_Proc{
private static final long serialVersionUID = 1L;
public Usuario_Proc_Dao(){
}
public void addUsuarioProc(Usuario usr) throws SQLException {
String query = "{ call sp_restricoes(?,?,?,?,?,?,?) }";
executePrepered(query, usr.getNome(), usr.getLogin(), usr.getSenha(),usr.getId_grupo(),usr.getUsuario_incluir(),usr.getUsuario_altera());
}
public Usuario getUsuario(int idUsuario) throws SQLException {
ResultSet rs = executeQuery("SELECT * FROM USUARIO WHERE IDUSUARIO = ?", idUsuario);
Usuario usr = null;
if (rs.next()) {
usr = populateUsuarioInfo(rs);
}
rs.close();
return usr;
}
public List<Usuario> getAllUsuarios() throws SQLException {
ResultSet rs = executeQuery("SELECT * FROM USUARIO");
List<Usuario> toReturn = new LinkedList<Usuario>();
while (rs.next()) {
toReturn.add(populateUsuarioInfo(rs));
}
rs.close();
return toReturn;
}
public static Usuario populateUsuarioInfo(ResultSet rs) throws SQLException {
Usuario toReturn = new Usuario();
toReturn.setIdUsuario(rs.getInt("IDUSUARIO"));
toReturn.setLogin(rs.getString("LOGIN"));
toReturn.setNome(rs.getString("NOME"));
toReturn.setSenha(rs.getString("SENHA"));
toReturn.setId_grupo(rs.getInt("ID_GRUPO"));
toReturn.setUsuario_incluir(rs.getInt("USUARIO_INCLUI"));
toReturn.setUsuario_altera(rs.getInt("USUARIO_ALTERA"));
return toReturn;
}
}
GOSTEI 0
Nilo Souza
28/05/2011
Fiz um teste e me retorno o problema abaixo, se puderem me ajudar. Desde já grato!
classe de teste
METODO DA CLASSE DAO
MENSAGEM DE ERRO DO TESTE
classe de teste
@Test
public void testAddUsuarioProc() throws Exception {
System.out.println("addUsuarioProc");
Usuario usr = new Usuario();
usr.setNome("Nilo Souza");
usr.setLogin("nsouza9");
usr.setSenha("123");
usr.setId_grupo(1);
usr.setUsuario_incluir(5);
Usuario_Proc_Dao instance = new Usuario_Proc_Dao();
instance.addUsuarioProc(usr);
}
METODO DA CLASSE DAO
public void addUsuarioProc(Usuario usr) throws SQLException {
String query = "{ call sp_restricoes(?,?,?,?,?,?,?) }";
executePrepered(query,0, usr.getNome(), usr.getLogin(), usr.getSenha(),usr.getId_grupo(),usr.getUsuario_incluir(),'I');
}
MENSAGEM DE ERRO DO TESTE
Testsuite: treinamento.dao.Usuario_Proc_DaoTest addUsuarioProc Error to try 6 with value I Tests run: 1, Failures: 0, Errors: 1, Time elapsed: 1,43 sec ------------- Standard Output --------------- addUsuarioProc Error to try 6 with value I ------------- ---------------- --------------- Testcase: testAddUsuarioProc(treinamento.dao.Usuario_Proc_DaoTest): Caused an ERROR Parâmetro IN ou OUT ausente do índice:: 7 java.sql.SQLException: Parâmetro IN ou OUT ausente do índice:: 7 at oracle.jdbc.driver.OraclePreparedStatement.processCompletedBindRow(OraclePreparedStatement.java:1821) at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3571) at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3657) at oracle.jdbc.driver.OracleCallableStatement.executeUpdate(OracleCallableStatement.java:4739) at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350) at treinamento.dao.GenericaDao_Proc.executePrepered(GenericaDao_Proc.java:70) at treinamento.dao.Usuario_Proc_Dao.addUsuarioProc(Usuario_Proc_Dao.java:30) at treinamento.dao.Usuario_Proc_DaoTest.testAddUsuarioProc(Usuario_Proc_DaoTest.java:55) Test treinamento.dao.Usuario_Proc_DaoTest FAILED test: Deleting: /tmp/TEST-treinamento.dao.Usuario_Proc_DaoTest.xml BUILD SUCCESSFUL (total time: 2 seconds)
GOSTEI 0
Davi Costa
28/05/2011
Na sua chamada vc usou:
public void addUsuarioProc(Usuario usr) throws SQLException {
String query = "{ call sp_restricoes(?,?,?,?,?,?,?) }";
executePrepered(query, usr.getNome(), usr.getLogin(), usr.getSenha(),usr.getId_grupo(),usr.getUsuario_incluir(),usr.getUsuario_altera());
}
Mas aparentemente no seu teste vc não instancio todos esse atributos.
@Test
public void testAddUsuarioProc() throws Exception {
System.out.println("addUsuarioProc");
Usuario usr = new Usuario();
usr.setNome("Nilo Souza"); // confere
usr.setLogin("nsouza9"); //confere
usr.setSenha("123");//confere
usr.setId_grupo(1);//confere
usr.setUsuario_incluir(5);//confere
// mas o usr.getUsuario_altera()?
Usuario_Proc_Dao instance = new Usuario_Proc_Dao();
instance.addUsuarioProc(usr);
}
Att Davi
public void addUsuarioProc(Usuario usr) throws SQLException {
String query = "{ call sp_restricoes(?,?,?,?,?,?,?) }";
executePrepered(query, usr.getNome(), usr.getLogin(), usr.getSenha(),usr.getId_grupo(),usr.getUsuario_incluir(),usr.getUsuario_altera());
}
Mas aparentemente no seu teste vc não instancio todos esse atributos.
@Test
public void testAddUsuarioProc() throws Exception {
System.out.println("addUsuarioProc");
Usuario usr = new Usuario();
usr.setNome("Nilo Souza"); // confere
usr.setLogin("nsouza9"); //confere
usr.setSenha("123");//confere
usr.setId_grupo(1);//confere
usr.setUsuario_incluir(5);//confere
// mas o usr.getUsuario_altera()?
Usuario_Proc_Dao instance = new Usuario_Proc_Dao();
instance.addUsuarioProc(usr);
}
Att Davi
GOSTEI 0
Nilo Souza
28/05/2011
Fiz conforme orientou e ficou desde jeito dando o erro abaixo:
Metodo alterado
public void addUsuarioProc(Usuario usr) throws SQLException { String query = "{ call sp_restricoes(?,?,?,?,?,?,?) }"; executePrepered(query,usr.getIdUsuario(), usr.getNome(), usr.getLogin(), usr.getSenha(),usr.getId_grupo(),usr.getUsuario_incluir(),usr.getOpr()); }Classe teste alterada
@Test public void testAddUsuarioProc() throws Exception { System.out.println("addUsuarioProc"); Usuario usr = new Usuario(); usr.setIdUsuario(0); usr.setNome("Nilo Souza"); usr.setLogin("nsouza9"); usr.setSenha("123"); usr.setId_grupo(1); usr.setUsuario_incluir(5); usr.setUsuario_altera(2); Usuario_Proc_Dao instance = new Usuario_Proc_Dao(); instance.addUsuarioProc(usr); }Erro ao testar a classe
Testsuite: treinamento.dao.Usuario_Proc_DaoTestaddUsuarioProcTests run: 1, Failures: 0, Errors: 1, Time elapsed: 1,775 sec ------------- Standard Output ---------------addUsuarioProc------------- ---------------- ---------------Testcase: testAddUsuarioProc(treinamento.dao.Usuario_Proc_DaoTest): Caused an ERRORORA-06550: linha 1, coluna 7:PLS-00306: número incorreto de tipos de argumentos na chamada para 'SP_RESTRICOES'ORA-06550: linha 1, coluna 7:PL/SQL: Statement ignored java.sql.SQLException: ORA-06550: linha 1, coluna 7:PLS-00306: número incorreto de tipos de argumentos na chamada para 'SP_RESTRICOES'ORA-06550: linha 1, coluna 7:PL/SQL: Statement ignored at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396) at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:440) at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:837) at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:445) at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:191) at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:523) at oracle.jdbc.driver.T4CCallableStatement.doOall8(T4CCallableStatement.java:204) at oracle.jdbc.driver.T4CCallableStatement.executeForRows(T4CCallableStatement.java:1007) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1315) at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3576) at oracle.jdbc.driver.OraclePreparedStatement.executeUpdate(OraclePreparedStatement.java:3657) at oracle.jdbc.driver.OracleCallableStatement.executeUpdate(OracleCallableStatement.java:4739) at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeUpdate(OraclePreparedStatementWrapper.java:1350) at treinamento.dao.GenericaDao_Proc.executePrepered(GenericaDao_Proc.java:70) at treinamento.dao.Usuario_Proc_Dao.addUsuarioProc(Usuario_Proc_Dao.java:30) at treinamento.dao.Usuario_Proc_DaoTest.testAddUsuarioProc(Usuario_Proc_DaoTest.java:57) Test treinamento.dao.Usuario_Proc_DaoTest FAILEDtest:Deleting: /tmp/TEST-treinamento.dao.Usuario_Proc_DaoTest.xmlBUILD SUCCESSFUL (total time: 3 seconds)
GOSTEI 0
Anthony Accioly
28/05/2011
Nilo,
Se esse é aquele procedure que você postou no fórum de Oracle, veja que ele só tem três argumentos. Não se esqueça de anotar os parâmetros com IN.
Nessa caso você teria que passar um número e duas Strings para a chamada do procedure.
Você pode setar tanto por posição quanto nome conforme exemplos anteriores.
Abraços
Se esse é aquele procedure que você postou no fórum de Oracle, veja que ele só tem três argumentos. Não se esqueça de anotar os parâmetros com IN.
PROCEDURE sp_restricoes( ptabela IN NUMBER, popr IN VARCHAR2, pusuario IN VARCHAR2)
Nessa caso você teria que passar um número e duas Strings para a chamada do procedure.
String query = "{ call sp_restricoes(?,?,?) }Você pode setar tanto por posição quanto nome conforme exemplos anteriores.
Abraços
GOSTEI 0
Nilo Souza
28/05/2011
Era isso mesmo, funcionou. Muito obrigado mais uma vez!!Um grande abraço a todos!!
GOSTEI 0