How do you handle error condition while writing stored procedure or accessing stored procedure from java?
stored procedure should return error code if some operation fails but if stored procedure itself fail than catching SQLException is only choice.
try {
CallableStatement stmt=con.prepareCall("{call insertR(?,?)}");
stmt.setInt(1,1011);
stmt.setString(2,"Amit");
stmt.execute();
} catch(SQLException e) {
e.printStack();
}
this piece of code is taken from oracle [docs][1] to answer.
public void
createProcedureShowSuppliers()
throws SQLException {
String createProcedure = null;
String queryDrop =
"DROP PROCEDURE IF EXISTS SHOW_SUPPLIERS";
createProcedure =
"create procedure SHOW_SUPPLIERS() " +
"begin " +
"select SUPPLIERS.SUP_NAME, " +
"COFFEES.COF_NAME " +
"from SUPPLIERS, COFFEES " +
"where SUPPLIERS.SUP_ID = " +
"COFFEES.SUP_ID " +
"order by SUP_NAME; " +
"end";
Statement stmt = null;
Statement stmtDrop = null;
try {
System.out.println("Calling DROP PROCEDURE");
stmtDrop = con.createStatement();
stmtDrop.execute(queryDrop);
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmtDrop != null)
{
stmtDrop.close();
}
}
try {
stmt = con.createStatement();
stmt.executeUpdate(createProcedure);
} catch (SQLException e) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}
[1]: https://docs.oracle.com/javase/tutorial/jdbc/basics/storedprocedures.html
When you call a stored procedure, it will execute in database server so if there any exception occurs that can be handled in EXCEPTION block in the stored procedure. If that stored procedure itself fails, it throws a SQL exception which can be handled by try/catch block and wrap it to your project specific exception.
Example
try {
CallableStatement stmt = con.prepareCall("{call geNamebyId(?)}");
stmt.setInt(1);
stmt.execute();
} catch(SQLException e) {
e.printStack();
}
Related
I a working with java and MYSQL. I want to insert 1000 elements into MYSQL database from java. I created a stored procedure with batch insertion .The problem is that if the insertion of first element or any other element failed due to some SQL exception, the execution will be stop. I want to insert other elements even if some insertion failed due to SQL exception. How is it possible?
public void insertXml(ArrayList<String> xmlCollection) throws SQLException {
Connection connection = null;
CallableStatement statement = null;
try {
connection = DbConnector.getConnection();
Application.getAppInstance().monitorCountProcedure("insertXmlToDB");
statement = connection.prepareCall("{call insertXmlToDB(?)}");
connection.setAutoCommit(false);
for (String xmlString : xmlCollection) {
//System.out.println("xmlstring="+xmlString);
statement.setString(1, xmlString);
statement.addBatch();
}
statement.executeBatch();
connection.commit();
System.out.println("insertXmlToDB stored procedure called successfully!" + statement);
} catch (Exception ex) {
ex.printStackTrace();
System.err.println("insertXmlToDB stored procedure error : " + ex.getMessage());
} finally {
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
// log.error("Could not close statement" + e.getMessage());
}
}
if (connection != null) {
try {
connection.setAutoCommit(true);
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
I am trying to run a PLSQL script which I have as a string value with the following method.
I first create the procedure
then I create a callStatement to call it
and finally I add some parameters
I get the error message:
ORA-06575: Package or function PROCEDURE_NAME is in an invalid state
Any ideas what I can do about that?
This is the code:
public IResult createAndExecuteCallable(String queryText, String procedureName, Object[] parameter) {
IResult result = new Result();
String procedure = "create procedure "+procedureName+"("+queryText+")";
Connection connection = this.getDatabaseConnection().getConnection();
try {
connection.setAutoCommit(true);
Statement stmt = connection.createStatement();
stmt.executeUpdate(procedure);
CallableStatement statement = connection.prepareCall("call "+procedureName+"()");
commonPreparedStatment(statement,parameter);
try {
statement.executeUpdate();
} catch(SQLException se){
result = new Result(se);
} finally {statement.close();}
} catch(Exception e){
result = new Result(e);
} finally {
closeConnection(connection);
}
return result;
}
Thanks to the comments and some other help I found the solution. Here is the new middle part of the code, now including compilation:
connection.setAutoCommit(true);
PreparedStatement createStatement = connection.prepareStatement(queryCreateText);
PreparedStatement compileStatement = connection.prepareStatement(queryCompileText);
CallableStatement statement = connection.prepareCall(queryCallText);
commonPreparedStatment(statement, parameter);
try {
createStatement.executeUpdate();
log.info("create ok");
} catch (SQLException ignored) {
log.info(ignored.getMessage());
} finally {
log.info(queryCompileText);
createStatement.close();
}
try {
compileStatement.executeUpdate();
log.info("compile ok");
} catch (SQLException ignoredToo) {
log.info(ignoredToo.getMessage());
} finally {
compileStatement.close();
}
try {
statement.executeUpdate();
log.info("execute ok");
} catch (SQLException se) {
result = new Result(se);
} finally {
statement.close();
}
One additional obstacle was the file content of the plsql code. It contained line breaks and Oracle did not accept them. So I had to remove them before creating the procedure in Oracle:
queryCreateText = queryCreateText.replace("\r\n", " ");
I have the following code:
try {
String sql = "SELECT COUNT(*) AS \"Jumlah\" FROM dokter";
ResultSet rs = connection.st.executeQuery(sql);
if(rs.next()){
abc = rs.getString("Jumlah").toString();
}
} catch (Exception e) {
System.out.println("\n Message: " + e.getMessage());
}
Why can't my ResultSet execute the given SQL?
Lose the alias, it's just an unnecessary complication. Just reference the ResultSet by the column's index:
try {
String sql = "SELECT COUNT(*) FROM dokter";
ResultSet rs = connection.st.executeQuery(sql);
if(rs.next()) {
abc = rs.getInt(1); // or getString(1) if you need it as a String
}
} catch (Exception e) {
System.out.println("\n Message: " + e.getMessage());
}
I suggest you use a PreparedStatement and a try-with-resources to close it (and your ResultSet). A count is not a String, and if you have a Connection connection then you might do something like
int count = 0;
try {
String sql = "SELECT COUNT(*) FROM dokter";
try (PreparedStatement ps = connection.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
count = rs.getInt(1);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
In my method show below find bug is specifying Fail to cleanup java.sql.Statement on checked Exception
public int updateSecurityCodeHistoryForMessage(String phone, String securityCodeHistoryId, String messageState, String messageId, String parentMessageId)
{
CaptivePortalLogger.appLog.error(MODULE+"Start : updateSecurityCodeHistoryForMessage::"+messageState);
int result=-1;
String query=null;
Connection con = null;
PreparedStatement pstmt =null;
try
{
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Available Connection : "+ CaptivePortalDBConnection.getNumIdleConnections());
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Active Connection : "+ CaptivePortalDBConnection.getNumActiveConnections() );
con = CaptivePortalDBConnection.getDataSource().getConnection();
CaptivePortalLogger.appLog.error(MODULE+" Before updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: ");
query="UPDATE tblsecuritycodehistory SET messagestate = ?,messageid = ? WHERE securitycodehistoryid = ? AND mobileno = ?";
CaptivePortalLogger.appLog.debug(MODULE + "for updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport Query : "+ query);
pstmt = con.prepareStatement(query);
pstmt.setString(1,messageState); //<b>line 556</b>
pstmt.setString(2,messageId);
pstmt.setString(3,securityCodeHistoryId);
pstmt.setString(4,phone);
result = pstmt.executeUpdate();
CaptivePortalLogger.appLog.error(MODULE+" After updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: result::"+result);
}
catch (Exception e) {
result = -1;
CaptivePortalLogger.traceLog.debug("Got an exception while updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport: ",e);
}
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try
{
if(pstmt!=null)
pstmt.close();
if(con !=null)
con.close();
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
catch(Exception e)
{
CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e);
}
}
CaptivePortalLogger.appLog.error(MODULE+"End : updateSecurityCodeHistoryForMessage");
return result;
}
I find lots of links on stack but none of them able to solve my problem(may be i m not able to understand them properly). Any help will be appreciated.
Thanks in Advance..........
After updaing my finally block with a solution specfied by #Mark problem persists
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try {
if(pstmt!=null)
pstmt.close();
} catch (Exception ex) {
// Log, ignore, etc
}
try {
if(con !=null)
con.close();
} catch (Exception ex) {
// Log, ignore, etc
}
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
After using #Jon suggestion , my problem get resolved. finally resolved code is ::
public int updateSecurityCodeHistoryForMessage(String phone, String securityCodeHistoryId, String messageState, String messageId, String parentMessageId)
{
CaptivePortalLogger.appLog.error(MODULE+"Start : updateSecurityCodeHistoryForMessage::"+messageState);
int result=-1;
String query=null;
Connection con = null;
PreparedStatement pstmt =null;
try
{
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Available Connection : "+ CaptivePortalDBConnection.getNumIdleConnections());
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : isSecurityCodeUsed) Active Connection : "+ CaptivePortalDBConnection.getNumActiveConnections() );
con = CaptivePortalDBConnection.getDataSource().getConnection();
CaptivePortalLogger.appLog.error(MODULE+" Before updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: ");
query="UPDATE tblsecuritycodehistory SET messagestate = ?,messageid = ? WHERE securitycodehistoryid = ? AND mobileno = ?";
CaptivePortalLogger.appLog.debug(MODULE + "for updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport Query : "+ query);
try
{
pstmt = con.prepareStatement(query);
pstmt.setString(1,messageState);
pstmt.setString(2,messageId);
pstmt.setString(3,securityCodeHistoryId);
pstmt.setString(4,phone);
result = pstmt.executeUpdate();
}
catch(SQLException e1)
{
CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e1);
}
finally{
if(pstmt!=null)
pstmt.close();
}
CaptivePortalLogger.appLog.error(MODULE+" After updateSecurityCodeHistoryForMessage into SendMessageAndReceiveReport: result::"+result);
}
catch (SQLException e2) {
result = -1;
CaptivePortalLogger.traceLog.debug("Got an exception while updateSecurityCodeHistoryForMessage in SendMessageAndReceiveReport: ",e2);
}
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try
{
if(con !=null)
con.close();
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
catch(SQLException e)
{
CaptivePortalLogger.traceLog.debug("Error in closing sqlReader.",e);
}
}
CaptivePortalLogger.appLog.error(MODULE+"End : updateSecurityCodeHistoryForMessage");
return result;
}
Look at this code:
if(pstmt!=null)
pstmt.close();
if(con !=null)
con.close();
Now consider that pstmt.close() can throw an exception... which means con.close() wouldn't be called.
If you're using Java 7, use a try-with-resources statement instead, but otherwise you should have a separate try/finally block for each resource.
try {
connection = ...;
try {
statement = ...;
} finally {
// Clean up statement
}
} finally {
// Clean up connection
}
I'd also strongly recommend against catching blanket Exception - it's better to catch specific exceptions which you can actually handle, and let other exceptions propagate up the stack. Also, you appear to be using integer values to signal success or failure of your method - that's not idiomatic Java; exceptions are preferred for error handling, in general.
The problem is that if pstmt.close() throws an Exception, then the connection is never closed.
Either do not close the statement in the finally (as drivers are required to close Statement objects if the Connection is closed), or put both in their own try..catch-block. Eg:
finally
{
CaptivePortalLogger.appLog.debug(MODULE+"Finally Start");
try {
if(pstmt!=null)
pstmt.close();
} catch (Exception ex) {
// Log, ignore, etc
}
try {
if(con !=null)
con.close();
} catch (Exception ex) {
// Log, ignore, etc
}
CaptivePortalLogger.sysOut.debug(MODULE + " (Method : updateSecurityCodeHistoryForMessage) Closing connections done ....");
}
Firebug is correct.
You should close all your SQL resources in a finally block, using individually wrapped calls to close methods.
You can do it with a utility class:
package persistence;
public class DatabaseUtils {
// similar methods for ResultSet and Connection
public static void close(Statement s) {
try {
if (s != null) {
s.close();
}
} catch (SQLException e) {
// Log the exception
}
}
}
Call the close method in a finally block in the method that created the resource.
Try to cleanup /close resource in separate try/catch/finally block otherwise if any one throw an exception then rest of will be remain unclosed.
I had requirement to perform two insert queries in two different tables.
I am using Oracle/Java Combination.
What are the options available in this case?
If you're trying to insert the same data into two separate tables you can use a multitable insert like this:
insert all
into table1(a, b)
into table2(a, b)
select 1 a, 2 b from dual;
The most straightforward method is to do two inserts sequentially using the same connection. Assuming that part of your point is that you want the two inserts to occur in the same transaction, then make sure you have disabled autocommit on the connection, and explicitly commit after the second insert.
Another option would be to write an Oracle stored procedure that does the inserts, and call it from Java with a PreparedStatement.
Sample from devdaily.
package com.devdaily.sqlprocessortests;
import java.sql.*;
public class BasicJDBCDemo
{
Connection conn;
public static void main(String[] args)
{
new BasicJDBCDemo();
}
public BasicJDBCDemo()
{
try
{
Class.forName("com.mysql.jdbc.Driver").newInstance();
String url = "jdbc:mysql://localhost/coffeebreak";
conn = DriverManager.getConnection(url, "username", "password");
doTests();
conn.close();
}
catch (ClassNotFoundException ex) {System.err.println(ex.getMessage());}
catch (IllegalAccessException ex) {System.err.println(ex.getMessage());}
catch (InstantiationException ex) {System.err.println(ex.getMessage());}
catch (SQLException ex) {System.err.println(ex.getMessage());}
}
private void doTests()
{
doSelectTest();
doInsertTest(); doSelectTest();
doUpdateTest(); doSelectTest();
doDeleteTest(); doSelectTest();
}
private void doSelectTest()
{
System.out.println("[OUTPUT FROM SELECT]");
String query = "SELECT COF_NAME, PRICE FROM COFFEES";
try
{
Statement st = conn.createStatement();
ResultSet rs = st.executeQuery(query);
while (rs.next())
{
String s = rs.getString("COF_NAME");
float n = rs.getFloat("PRICE");
System.out.println(s + " " + n);
}
}
catch (SQLException ex)
{
System.err.println(ex.getMessage());
}
}
private void doInsertTest()
{
System.out.print("\n[Performing INSERT] ... ");
try
{
Statement st = conn.createStatement();
st.executeUpdate("INSERT INTO COFFEES " +
"VALUES ('BREAKFAST BLEND', 200, 7.99, 0, 0)");
}
catch (SQLException ex)
{
System.err.println(ex.getMessage());
}
}
private void doUpdateTest()
{
System.out.print("\n[Performing UPDATE] ... ");
try
{
Statement st = conn.createStatement();
st.executeUpdate("UPDATE COFFEES SET PRICE=4.99 WHERE COF_NAME='BREAKFAST BLEND'");
}
catch (SQLException ex)
{
System.err.println(ex.getMessage());
}
}
private void doDeleteTest()
{
System.out.print("\n[Performing DELETE] ... ");
try
{
Statement st = conn.createStatement();
st.executeUpdate("DELETE FROM COFFEES WHERE COF_NAME='BREAKFAST BLEND'");
}
catch (SQLException ex)
{
System.err.println(ex.getMessage());
}
}
}
You can check with StoredProcedures and execute with PreparedStatement in JDBC api. That intern will return you two resultSets , which you can get with a method getMoreResults(). You can then process the resultsets separately.