Unable to get multiple Table entities through Stored procedure using hibernate - java

Here is my stored Procedure
Create PROCEDURE [dbo].getUserAndEnum
AS
BEGIN
select * from user_master where id =1
select * from enum_master where id = 1
End
With hibernate i written
Session session = HibernateFactory.getSessionFactory().openSession();
Transaction tr = session.beginTransaction();
SQLQuery qr=session.createSQLQuery("getUserAndEnum");
List list = qr.list();
In list i am getting only the user object ..what about my enum_master row with id 1
P.S enum_master row with id 1 is there in DB
Thanks.

'Rules/limitations for using stored procedures' in hibernate documentation states that
"The procedure must return a result set. Note that since these servers can return multiple result sets and update counts, Hibernate will iterate the results and take the first result that is a result set as its return value. Everything else will be discarded."
(reference : http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/querysql.html#sp_query)
As stated, the second resultset in your case is being ignored.
You would need to use jdbc for getting both result sets. Either you can make separate classes for doing so, or alternatively, hibernate offers you methods for performing traditional jdbc operations via its session's 'doWork' and 'doReturningWork' methods...
A simple example could be:
List<Object> res = session.doReturningWork(new ReturningWork<List<Object> /*objectType returned*/>() {
#Override
/* or object type you need to return to process*/
public List<Object> execute(Connection conn) throws SQLException
{
CallableStatement cstmt = conn.prepareCall("CALL YOUR_PROCEDURE");
//Result list that would return ALL rows of ALL result sets
List<Object> result = new ArrayList<Object>();
try
{
cstmt.execute();
ResultSet rs = cstmt.getResultSet(); // First resultset
while (rs.next()) {//Read items/rows of first resultset
// .
// Process rows of first resultset
result.add(obj); // add items of resultset 1 to the returning list object
}
cstmt.getMoreResults(); // Moves to this Statement object's next result, returns true if it is a ResultSet object
rs = cstmt.getResultSet(); // Second resultset
while (rs.next()) {
// .
// Process rows of second resultset
result.add(obj); // add items of resultset 2 to the returning list object
}
rs.close();
}
finally
{cstmt.close();}
return result; // this should contain All rows or objects you need for further processing
}
});

Related

rs.next() is returning false in while statement

So, I'm trying to extract msgID and msgStatus values from database for each reference Id(variable msgRefList) stored in the list object and I'm trying to store these extracted values in String objects for further processing. But rs.next() method is returning false and hence it is not going into the while loop where the assignment statements are. I checked in database with the query that i'm using in the code and it shows one record in the result, but still rs.next() is returning false. Screenshot attached with the database results.
Below is the actual code that i'm using
List<String> msgRefList = listofRefrnceValues:
try {
Connection connect = connectToDB(ENV);
for(String reference: msgRefList){
String query="select ID, MSG_STS from TABLE where INSTR_ID = ?";
PreparedStatement stmt = connect.prepareStatement(query);
stmt.setString(1,reference);
ResultSet rs = stmt.executeQuery();
if(rs!=null){
while(rs.next()) {
P_MID = rs.getString("P_MID");
P_MSG_STS = rs.getString("P_MSG_STS");
}
}
}
}catch (Exception e) {
e.printStackTrace();
}
You have some typos in your SQL-Query-String in java. Instead of TABLE you probably meant MINF (your real table) also all of your properties don't have the prefix P_ and ID is probably MID. So change:
String query="select ID, MSG_STS from TABLE where INSTR_ID = ?";
To:
String query="select P_MID, P_MSG_STS from MINF where P_INSTR_ID = ?";
And you'll be fine.

JDBC getDouble returns 0.0

I am new to Java and JDBC.
I am trying to get a double value from a database through JDBC and make a global variable equal to that value. Here's what I did.
public class Console {
String sql;
Statement stmt;
Connection conn;
ResultSet rs;
//Category Total
public static double num;
public Console(){
try{
Class.forName("com.mysql.jdbc.Driver");
System.out.println("Connecting to database...");
conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?autoReconnect=true&useSSL=false","user","password");
stmt = conn.createStatement();
System.out.println("Connected database successfully...");
sql = "SELECT sum(a) FROM table";
while(rs.next()) {
rs = stmt.executeQuery(sql);
num = rs.getDouble("sum(a)");
}
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String args[]) {
System.out.println(num);
}
}
When I run the program it prints 0.0 although the actual value is not.
You need to get your result set prior to the while loop, and then iterate through it
rs = stmt.executeQuery(...);
while (rs.next()) {
// and process your results row by row here...
}
Otherwise (as you've discovered) your rs variable is unset
Your result set won't contain sum(a) as a column name. You can get the result positionally (e.g. getInt() can take an index integer) or rename your result column (e.g. select sum(a) as sum FROM table) and reference it like that.
You haven't intialized the ResultSet with executing the query. Then you can loop the result set.
sql = "SELECT sum(a) FROM table";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
ResultSet rs = preparedStatement.executeQuery();
while (rs.next()) {
num = rs.getDouble("sum(a)");
}
You have been getting the results in the loop, but you have to do it before reach the loop.
You are getting 0.0 because of the behavior of JDBC driver.
From java doc
Returns: the column value; if the value is SQL NULL, the value
returned is 0
To know that last read value was null from Resultset, you can use method rs.wasNull() method. it will return true if the last column value read was SQL NULL and false otherwise.
It's good practice to assign a column alias to calculated results like sum(a) and retrieve the values using that alias.
Also good practice is to use Java's try-with-resources.
The try-with-resources statement ensures that each resource is closed at the end of the statement.
Also, if your SQL statement would return NULL, e.g. in case the table is empty or no rows apply to the conditions in your WHERE clause, the ResultSet.getDouble method will return the value 0.
sql = "SELECT sum(a) AS sum_a FROM table"; // assign alias sum_a to the expression sum(a)
try( ResultSet rs = stmt.executeQuery( sql ) ) { // get a resultset object in a try-with-resources statement, to auto-close it at the end
rs.next( ); // for the query you have, checking if there's a next row is actually not necessary; there's always a result for your query
num = rs.getDouble("sum_a"); // retrieve the column value by its alias
} // rs will be closed for you at this point

Expecting multiple ResultSets, but only get one

I have a stored procedure which returns multiple result sets as follows,
create proc test as
begin
select '1'
select a,b into #temp from TABLE1
select * from #temp
select '2'
select 'Done'
end
And my java call is,
CallableStatement stmt = null;
String procString= "EXEC test";
stmt = conn.prepareCall(procString);
boolean results = stmt.execute();
System.out.println(results);
do {
if(results) {
rs = stmt.getResultSet();
while (rs.next()) {
System.out.println(rs.getString(1) + ", " );
}
rs.close();
}
System.out.println();
results = stmt.getMoreResults();
System.out.println("results - "+results);
} while(results);
So as per the above snippet, the output should have all the 4 selects. But I just get the first select and nothing else. I just removed the second select which does insert into temp table, after which I get all the 4 selects.
Why does this happen?
You are misinterpreting the meaning of the boolean returned by getMoreResults:
There are no more results when the following is true:
// stmt is a Statement object
((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))
Returns:
true if the next result is a ResultSet object; false if it is an update count or there are no more results
As you haven't got a SET NOCOUNT ON in your stored procedure, the SELECT ... INTO ... will generate an update count. This will be returned after the first select. Only when getMoreResults returns false and getUpdateCount returns -1 can you be sure that there are no more results.
Your current code will exit the do .. while as soon as getMoreResults has returned false. You either need to add SET NOCOUNT ON to your stored procedure, or process multiple results taking into account the update counts.
To correctly process multiple results with update counts 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();
}
I copied the above from my answer to another question, it is similar but not exactly the same. The rest of that answer might provide some more details: Java SQL: Statement.hasResultSet()?

get one result at a time from database (when more than one result exists)

I have a database in which more than one row has the same value.
Eg,
Column1 Column2
A X
A Y
A Z
A resultset gets all the values of column 2 as a single string.
How to get each unique value from database (or from result set)?
(I use java)
Thanks in advance.
Have a look at
SELECT columna ,
(SELECT GROUP_CONCAT(DISTINCT columnb SEPARATOR ' ') FROM test
WHERE columna=t.`columna` ) as columnb_string
FROM `test` t GROUP BY columna
Here is Fiddle Example
What is the query/code you are using to get all of column two as a string? It is always a good idea to test your query in the database system itself or you could use SQLFiddle to ensure you are getting the results you are expecting from your query
From the Doc:
A ResultSet object maintains a cursor pointing to its current row of data. Initially the cursor is positioned before the first row. The next method moves the cursor to the next row, and because it returns false when there are no more rows in the ResultSet object, it can be used in a while loop to iterate through the result set.
Read the rest of Java Doc for ResultSet
A typical approach to getting values from the data base is to
//Construct a statement
String yourStatement = "Select COLUMN_B from aTable WHERE COLUMN_A LIKE 'A'" // EDITED
PreparedStatement aPrepStatement = null;
ResultSet rs = null;
List<String> aList = new ArrayList<String>(); // ADDED
try
{
aPrepStatement = yourConnection.prepareStatement(yourStatement)
rs = aPrepStatement.executeQuery();
while(rs.next())
{
// You are now in the first row of data depending on your query
// String column1 = rs.getString(1); // 'A' In the table you descrbed above (for first iteration
String column2 = rs.getString(1); // 'X' In the table you descrbed above
// Now do what you need to with the data
aList.add(column2) // EDITED
}
}
catch (Exception ex) {
// deal with any exceptions that arise
ex.printStackTrace();
}
finally
{
//Close your Resultset and prepared statement (this will possibly need a try catch block also
if(rs != null)
rs.close();
if(aPrepStatement != null)
aPrepStatement.close();
}
// ADDED BELOW
for(String s: aList)
System.out.println(s) // should give output
// X
// Y
// Z
Doc for PreparedStatement and Connection

Calling Sybase Adaptive Server Enterprise's "sp_help" from JDBC

In order to query the database meta data in Sybase ASE, I found this relevant answer (not the accepted one), to be ideal:
From a Sybase Database, how I can get table description ( field names and types)?
Unfortunately, I can't seem to find any documentation, how I'm supposed to call sp_help from JDBC. According to the documentation, sp_help returns several cursors / result sets. The first one contains information about the table itself, the second one about the columns, etc. When I do this:
PreparedStatement stmt = getConnection().prepareStatement("sp_help 't_language'");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
System.out.println(rs.getObject(1));
// ...
}
I only get the results from the first cursor. How to access the other ones?
When you have multiple result sets you need to use the execute() method rather than executeQuery().
Here's an example:
CallableStatement cstmt;
ResultSet rs;
int i;
String s;
...
cstmt.execute(); // Call the stored procedure 1
rs = cstmt.getResultSet(); // Get the first result set 2
while (rs.next()) { // Position the cursor 3
i = rs.getInt(1); // Retrieve current result set value
System.out.println("Value from first result set = " + i);
// Print the value
}
cstmt.getMoreResults(); // Point to the second result set 4a
// and close the first result set
rs = cstmt.getResultSet(); // Get the second result set 4b
while (rs.next()) { // Position the cursor 4c
s = rs.getString(1); // Retrieve current result set value
System.out.println("Value from second result set = " + s);
// Print the value
}
rs.close(); // Close the result set
cstmt.close(); // Close the statement
You also need to call getUpdateCount() as well as getMoreResults() to read the entire result set. Here is some code I used to call sp_helpartition to retrieve partition information from a SYBASE DB.
try {
connection = getPooledConnection(poolName);
statement = connection.createStatement();
CallableStatement callable = connection.prepareCall(
"{ call sp_helpartition(?) }");
callable.setString(1,tableName);
callable.execute();
int partitions = 0;
/*
* Loop through results until there are no more result sets or
* or update counts to read. The number of partitions is recorded
* in the number of rows in the second result set.
*/
for (int index = 0 ; ; index ++){
if (callable.getMoreResults()){
ResultSet results = callable.getResultSet();
int count = 0 ;
while (results.next()){
count++;
}
if (index == 1){
partitions = count;
}
} else if (callable.getUpdateCount() == -1){
break ;
}
}
return partitions ;
} catch (Exception e) {
return 0 ;
} finally {
statement.close();
connection.close();
}
Thanks to Martin Clayton's answer here, I could figure out how to query Sybase ASE's sp_help function generically. I documented some more details about how this can be done in my blog here. I worked support for multiple JDBC result sets into jOOQ. In the case of sp_help, calling that function using the jOOQ API might look like this:
Factory create = new ASEFactory(connection);
// Get a list of tables, a list of user types, etc
List<Result<Record>> tables = create.fetchMany("sp_help");
// Get some information about the my_table table, its
// columns, keys, indexes, etc
List<Result<Record>> results = create.fetchMany("sp_help 'my_table'");

Categories

Resources