I have given a pl/sql procedure that I am supposed to call from java code through jdbc.
public boolean deleteCompany(TimeStamp timestamp, Long companyId){
String str = "{call Delete_Company(?,?)}";
CallableStatement statement = null;
boolean deleted = false;
try{
statement = conn.prepareCall(str);
statement.setLong(1,companyId);
statement.setTimestamp(2,timeStamp);
statement.execute();
deleted = true;
return deleted;
}finally{
statement.close();
}
}
The problem is even if I send the wrong id number it obviously executes statement so varaible deleted becomes true. I tried .executeUpdate() method to be able to get affected row counts but it did not work properly cause when in both cases(when deletion/no deletion happened) it retrieved 1. I suppose the problem is the pl/sql procedure I am using just performs delete operation but not retrieve any result set object. So neither executeUpdate() nor getUpdateCount() methods does not help me. My question is there any way I can get affected row counts even if I have no result set object?
FYI: I understand that affected row count could be sent as a out parameter from pl/sql procedure, but I have no authority to make any change on the db side.
Since you can't change the stored procedure, one solution is to do the following
Get the number of rows before calling an update operation (select count(*) from your_tbl where .....)
Delete the records as you're already doing
Get the number of rows after the delete action and check if the number of affected rows is the same as in #1 (num_rows#1 - num_rows#3)
Other transactions can still make this approach somewhat unreliable because they can also change your table between steps #1 and #3.
If that's a concern for you, then you should use transactions (just place your Java code in a transaction).
Your statement.execute(); returns a boolean value and it always return true if the execution is success irrespective of what the procedure is doing on call. Further you can refer the below code for what you are looking.
...
boolean hadResults = cStmt.execute();
//
// Process all returned result sets
//
while (hadResults) {
ResultSet rs = cStmt.getResultSet();
// process result set
...
hadResults = cStmt.getMoreResults();
}
//
// Retrieve output parameters
//
// Connector/J supports both index-based and
// name-based retrieval
//
int outputValue = cStmt.getInt(2); // index-based
outputValue = cStmt.getInt("inOutParam"); // name-based
...
Related
i tryed this:
ResultSet existetabela = stm.executeQuery ("SELECT * FROM pessoajuridica WHERE protocolo =" + varConsult );
System.out.println(existetabela);
but it only return a strange String -> org.sqlite.RS#1f959518
i was expecting the value..
remembering, sql lite and java :S
i want to use the value that it return to compare, if it return any value, means that it exist, so it will not add to the sql, if dont return anything = can add!!!
("if exist" doesnt work for me, says that its a invalid argument in the sql command line --')
You can use ResultSet#next() method to test whether there was any result set returned:
if (existetabela.next()) {
// Result was fetched
// Assuming type of protocol is String (Can be anything)
String protocol = existetabela.getString("protocolo");
} else {
// No result
}
Now, let's move ahead to the major issue. You should use PreparedStatement, to save yourself from SQL Injection.
You need to iterate inside the result set to retrive the actual data that were found:
while (existetabela.next()){
System.out.println(existetabela.getObject("protocolo"));
}
Did you look at PreparedStatement ?
I have a stored procedure, I want to call it from JDBC, I got null pointer exception in the line"
while (restuls.next()) {
My code is:
Connection con = Database.getConnection();
CallableStatement callableStatement = null;
try {
String storedProcedure = "{call getAllCustomerAddresses(?,?,?,?,?,?,?)}";
callableStatement = con.prepareCall(storedProcedure);
callableStatement.setInt(1, this.getID());
callableStatement.registerOutParameter(2,
java.sql.Types.INTEGER);
callableStatement.registerOutParameter(3,
java.sql.Types.VARCHAR);
callableStatement.registerOutParameter(4,
java.sql.Types.INTEGER);
callableStatement.registerOutParameter(5,
java.sql.Types.INTEGER);
callableStatement.registerOutParameter(6,
java.sql.Types.INTEGER);
callableStatement.registerOutParameter(7,
java.sql.Types.VARCHAR);
callableStatement.execute();
System.out.println(callableStatement.getInt(2));
System.out.println(callableStatement.getString(3));
System.out.println(callableStatement.getInt(4));
System.out.println(callableStatement.getInt(5));
System.out.println(callableStatement.getInt(6));
System.out.println(callableStatement.getString(7));
ResultSet restuls = callableStatement.getResultSet();
while (restuls.next()) {
int addressID = restuls.getInt(2);
String label = restuls.getString(3);
int regionID = restuls.getInt(4);
int areaID = restuls.getInt(5);
int cityID = restuls.getInt(6);
String description = restuls.getString(7);
this.addresses.add(new CustomerAddressImpl(this, label,
description, RegionImpl.getInstance(regionID),
AreaImpl.getInstance(areaID), CityImpl
.getInstance(cityID), addressID));
}
look at the code, the System.out.println is working , and It is printing the right values from database, so why the results set is null please??
another thing, I must use result set because the stored procedure returns many rows.
I am really confusing why I can print the right values but the result set is null
Thanks in advance
Edit
If you want to give you the stored procedure tell me please
Stored Procedure
ALTER PROCEDURE [dbo].getAllCustomerAddresses(
#customerID INT,
#addressID INT OUTPUT,
#label VARCHAR(200) OUTPUT,
#regionID INT OUTPUT,
#areaID INT OUTPUT,
#cityID INT OUTPUT,
#description TEXT OUTPUT
)
AS
SET NOCOUNT Off;
SELECT #addressID = [ID],
#label = [label],
#regionID = [regionID],
#areaID = [areaID],
#cityID = [cityID],
#description = [description]
FROM Customer_Address
WHERE customerID = #customerID
execute() method of PreparedStatement returns true if result set presents and false otherwise. You do not check the return value of execute(). I think that if you do that you see that it is false.
The reason should be in your stored procedure that IMHO does not return value. So, try to analyze it to understand the problem.
Here are recommendations I can give you:
Use executeQuery() that directly returns ResaultSet instead of execute(). I think this is more convenient.
Avoid using stored procedures that couple your platform independent java code with specific type of database. Try to write all logic in java and use portable SQL statements only.
The last time I saw pure JDBC code was about 10 years ago. There are a lot of tools that help you to avoid writing SQL inside java code. Take a look on JPA, Hibernate, iBatis etc.
Your stored procedure doesn't actually produce a ResultSet because you are using output parameters (not 100% sure, I don't have a SQL Server handy to test).
You may just need to call CallableStatement.getObject(int) or CallableStatement.getObject(String) (or a type specific getter) to get the values instead. If you want to process as a ResultSet, then you should not use the output parameters in your stored procedures, but write the stored procedure as a select without assigning to output parameter. That will create a result set from the stored procedure
Another possibility might by that your stored procedure is first returning one or more update counts before returning the result set. The boolean return value of execute() indicates whether the first result is an update count or a ResultSet. You will need to repeatedly call getMoreResults() and getUpdateCount() to be sure you have processed every result.
Your posted stored procedure contains SET NOCOUNT OFF which signals to SQL Server (or Sybase) that you want update (and I believe select) counts returned as well, you might want to try using SET NOCOUNT ON.
You can also try to process the results of execute() like this to find out if there are indeed multiple update counts etc before the result set:
boolean result = pstmt.execute();
while(true)
if (result) {
ResultSet rs = pstmt.getResultSet();
// Do something with resultset ...
} else {
int updateCount = pstmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
// Do something with update count ...
}
result = pstmt.getMoreResults();
}
See also Java SQL: Statement.hasResultSet()?
My app uses MySQL on one platform and SQLite on another, as such there are differences, such as that when using query like DELETE FROM USERS:
On MySQL, PreparedStatement.getResultSet() will return null.
On SQLite, PreparedStatement.getResultSet() will throw java.sql.SQLException: no ResultSet available.
This may or may not be a bug in SQLite implementation (I think it is supposed to return null), but I have to deal with this somehow.
I could use a try { ... } catch (SQLException e) { ... } and if the exception message is "no ResultSet available", simply return null manually. This doesn't feel like a right way to do it though.
I could put up an if that makes a check on what JDBC driver is being used and react accordingly, but again, that doesn't feel like a good solution to the problem.
What I would really like is either a method like .hasResultSet() that returns a boolean OR a way to get the SQL command (SELECT, UPDATE, INSERT etc) from a statement that has been executed. I can find neither of the two in SQL API though.
When executing a query that returns an unknown amount of results, then you need to use execute(). This method returns a boolean indicating the type of result:
true: result is a ResultSet
false : result is an update count
If the result is true, then you use getResultSet() to retrieve the ResultSet, otherwise getUpdateCount() to retrieve the update count. If the update count is -1 it means there are no more results. Note that the update count will also be -1 when the current result is a ResultSet. It is also good to know that getResultSet() should return null if there are no more results or if the result is an update count, so the behavior of SQL Lite to throw an exception seems to be wrong.
Now if you want to retrieve more results, you call getMoreResults() (or its brother accepting an int parameter). The boolean return value of this method has the same meaning as that of execute(), so false does not mean there are no more results!
There are only no more results if the getMoreResults() returns false and getUpdateCount() returns -1 (as also documented in the Javadoc)
Essentially this means that if you want to correctly process all results you need to do something like:
PreparedStatement pstmt = connection.prepareStatement(...);
// ...
boolean result = pstmt.execute();
while(true)
if (result) {
ResultSet rs = pstmt.getResultSet();
// Do something with resultset ...
} else {
int updateCount = pstmt.getUpdateCount();
if (updateCount == -1) {
// no more results
break;
}
// Do something with update count ...
}
result = pstmt.getMoreResults();
}
The problem is that you use invalid method to perform delete operation. Instead of using getResultSet you should use Statement#execute(String)
IMHO the Exeption in SQLite implementation is more valid than null for MySQL. As delete do not return the set but a scalar value of delted rows.
I am trying to write java code to access a table 'customer' with columns 'customer_id', 'email', 'deliverable', and 'create_date'
I have
Connection conn = DriverManager.getConnection(connectionUrl, connectionUser, connectionPassword);
Statement constat = conn.createStatement();
String query = "SELECT * FROM customer WHERE customer_id LIKE " + customerId;
ResultSet rtn = constat.executeQuery(query);
Customer cust = new Customer(rtn.getInt("customer_id"), rtn.getString("email"), rtn.getInt("deliverable"), rtn.getString("create_date"));
conn.close();
return cust;
I am receiving the error:
java.sql.SQLException: Before start of result set
As far as I can tell, my error is in the line where I am creating a new Customer object, but I cannot figure out what I am doing wrong. Can anyone offer me some help? Thanks!
You must always go to the next row by calling resultSet.next() (and checking it returns true), before accessing the data of the row:
Customer cust = null;
if (rtn.next()) {
cust = new Customer(rtn.getInt("customer_id"),
rtn.getString("email"),
rtn.getInt("deliverable"),
rtn.getString("create_date"));
}
Note that you should also
use prepared statements instead of String concatenation to avoid SQL injection attacks, and have more robust code
close the connections, statements and resultsets in a finally block, or use the try-with-resources construct if using Java 7
Read the JDBC tutorial
You should call ResultSet.first() to move the result to the first position. The result set is a programming convention not to retrieve the whole result of the query and keep in memory. As such, its interface is quite low level and you must explicit select the row via methods like first(), last() or next() (each returns true to check if the requested row index is in the set)
You need to add
rtn.next();
before you use the result set.
Usually this is done as
while (rtn.next()) {
<do something with the row>
}
The scenario is like this:
for loop // runs say 200000 times
{
// here, i do a select from a database, fetching few rows which are expected to increase with every new iteration of for loop
// currently i am doing this select using simple JDBC call (using JDBC only is NOT a requirement)
// then i do some string matching stuff and then i either insert or update a particular row (in 95% cases i will insert)
// this insert or update is being done using Hibernate (using Hibernate over here is a requirement)
}
So the problem is, in every loop, I have to consider the each and every previously inserted/updated row. Due to this requirement, I have to do a JDBC call in each and every loop. And this JDBC call is taking the maximum time, bringing down the performance.
I want to know, is there any method using which I do not have to make a JDBC call in each iteration, but still I will be able to consider all the records including the one in the just previous insert/update? Anything like caching or some in-memory data structure or something like that?
Here is the code:
for loop // runs say 2000 times
{
String query = pdi.selectAllPatients(patientInfo);
Statement st = conn.createStatement();
ResultSet patientRs = st.executeQuery(query);
while (patientRs.hasNext())
{
// some string ops
}
// Create session for DB No.2
Session sessionEmpi = sessionFactoryEmpi.getCurrentSession();
sessionEmpi.beginTransaction();
if(some condition)
patientDao.insertPatient(patientInfo, sessionEmpi);
else
patientDao.insertref(patientInfo.getref(), sessionEmpi);
conn.commit();
}
public int insertPatient(PatientInfo input, Session session) throws SQLException {
try {
session.save(input.getPatient());
session.flush();
session.save(input.getref());
session.getTransaction().commit();
return 1;
} catch (Exception ex) {
session.getTransaction().rollback();
ex.printStackTrace();
return 0;
}
}
Is the performance of the SELECT consistent? Unless your data is fairly small, you'll likely have trouble caching all your changes in memory. You may also be able to batch the SELECTs, effectively unrolling the loop.
You can use the PreparedStatement interface instead of Statement interface as it avoids the unnecessary calls for firing the query to the database you just have to bind the data in for loop this will help you to improve performance!!
example:
PreparedStatement s =con.prepareStatement("select * from student_master where stu_id = ?");
for()
{
s.setString(1,"s002");
ResultSet rs = s.executeQuery();
}