I have a database and at present I am using the PreparedStatement to call data from the database using an SQL statement. However I know that once a PreparedStatement has finished the ResultSet closes.
I need an alternative to this (the resultset closing) as the Prepared Statement is run every time the user clicks a button and the input to the Prepared Statement can change however the ResultSet cannot take any new values.
Any thoughts would be appreciated.
You should copy the data from the ResultSet into objects of your own before closing the PreparedStatement.
For instance:
preparedStatement = conn.prepareStement("select * from people");
resultSet = preparedStatement.executeQuery();
//copying the value
while(resultSet.hasNext()){
String name = resultSet.getString("name");
String surname = resultSet.getString("surname");
//Person is a class of your own
Person person = new Person(name,surname);
//people is a Collection of Person created outside this loop
people.add(person);
}
Afterwards, make sure you close the PreparedStatement in a finnally block, and use the object in the people collection instead of using the ResultSet directly.
Related
Im trying to avoid SQL duplication. I found this code here how to prevent duplication. Java,SQL which is successful. I know rs.next will move the cursor, but how does it help avoid duplication (does it compare every value)? What is done is just checking is there another row and if there return true right?
Connection conn = // Connect to the database...
PreparedStatement ps =
conn.prepareStatement("SELECT username FROM login where username = ?";
ps.setString(1, value1);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
JOptionPane.showMessageDialog
(null,"username is already existed! please create new username.");
}
Your code is quite straightforward. You make a query that fetches ALL rows of the table login where username = XXX. Then you check whether there is any data in the ResultSet by executing the rs.next() function. This function returns a boolean value that is true when there is yet more data in the rs and false when there is no more data.
As you said, it also moves the cursor.
Does it compare every value(row)?
Yes. Your query looks every row up and checks whether username = XXX
why we use setInt with select query instead of using getInt when value is already there in database?
try {
conn = getConnection();
ps = conn.prepareStatement("SELECT * FROM circle where id =?");
ps.setInt(1, circleId);
Circle circle = null;
rs = ps.executeQuery();
if (rs.next()) {
//String s = rs.getString(circleId);
circle = new Circle(circleId, rs.getString("name"));
}
You're setting the value of the parameter to be used in the query. The ? in the SQL represents the parameter, and here you're giving it a value.
When you call getString() later, that's getting a value from the results of the query, which are very different from the parameters sent as part of the query.
Parameterized SQL allows safe inclusion of values into queries, without needing to escape them to prevent SQL injection attacks, or worrying about data type conversions. You should read the JDBC PreparedStatement tutorial for more details.
i have the below code, where I'm inserting records to a table. When I try to get resultset, it returns null. How to get the latest added row into a resultset?
String sql1 = "INSERT INTO [xxxx].[dbo].[xxxxxx](WORKFLOW_SEQ_NBR," +
" WORKFLOW_LOG_TYPE_CODE, WORKFLOW_STATUS_CODE, DISP_CODE, DISP_USER, DISP_COMMENT, DISP_TITLE, DISP_TS)" +
"VALUES(?,?,?,?,?,?,?,?)";
PreparedStatement pst = connect.prepareStatement(sql1);
pst.setString(1, ...);
pst.setString(2, ...);
...
...
...
pst.executeUpdate();
ResultSet rstest = pst.executeQuery();
// ResultSet rstest = pst.getResultSet();
EDIT: Resolved
added following method to go to the last added row
st.execute("Select * from [xxxx].[dbo].[xxxxxxxxx]");
ResultSet rstest = st.getResultSet();
rstest.afterLast();
GETLASTINSERTED:
while(rstest.previous()){
System.out.println(rstest.getObject(1));
break GETLASTINSERTED;//to read only the last row
}
When using a SQL statement such as INSERT, UPDATE or DELETE with a PreparedStatement, you must use executeUpdate, which will return the number of affeted rows. In this case there is simply no ResultSet produced by the sql operation and thus calling executeQuery will throw a SQLException.
If you actually need a ResultSet you must make another statement with a SELECT SQL operation.
See the javadoc for PreparedStatement#executeQuery and PreparedStatement#executeUpdate
Seems like this is an older question, but i'm looking for a similar solution, so maybe people will still need this.
If you're doing an insert statement, you can use the :
Connection.PreparedStatement(String, String[]) constructor, and assign those to a ResultSet with ps.getGeneratedKeys().
It would look something like this:
public void sqlQuery() {
PreparedStatement ps = null;
ResultSet rs = null;
Connection conn; //Assume this is a properly defined Connection
String sql = "insert whatever into whatever";
ps = conn.prepareStatement(sql, new String[]{"example"});
//do anything else you need to do with the preparedStatement
ps.execute;
rs = ps.getGeneratedKeys();
while(rs.next()){
//do whatever is needed with the ResultSet
}
ps.close();
rs.close();
}
Connection#prepareStatement() - Creates a PreparedStatement object for sending parameterized SQL statements to the database.
which means connect.prepareStatement(sql1); created the PreparedStatement object using your insert query.
and when you did pst.executeUpdate(); it will return the row count for SQL Data Manipulation Language (DML) statements or 0 for SQL statements that return nothing
Now if you again want to fetch the data inserted you need to create a new PreparedStatement object with Select query.
PreparedStatement pstmt = connect.prepareStatement("SELECT * FROM tableName");
then this shall give you the ResultSet object that contains the data produced by the query
ResultSet rstest = pstmt.executeQuery();
I need to take a table from one database and upload it to a different database.
So, I create two separate connection . Here is my code
Connection connection1 = // set up connection to dbms1
Statement statement = connection1.createStatement();
ResultSet result = statement.executeQuery("select * from ............. ");
Connection connection2 = // set up connection to dbms2
// Now I want to upload the ResultSet result into the second database
Statement statement2 = connection2.createStatement("insert into table2 " + result);
statement2.executeUpdate();
The above last lines do not work
How can i do this ? The bottomline is how to reuse a ready resultset
ResultSet is a ready java object . I hope there is a way add it to batch or something like this and executeUpdate , but not to write the result set to some temporary space (List, csv etc.) and the insert
The simplest way to do this is with a prepared statement for the insert. It lets you create a single statement object that can be used to run the query multiple times with different parameter values.
try (final Statement statement1 = connection1.createStatement();
final PreparedStatement insertStatement =
connection2.prepareStatement("insert into table2 values(?, ?)"))
{
try (final ResultSet resultSet =
statement1.executeQuery("select foo, bar from table1"))
{
while (resultSet.next())
{
// Get the values from the table1 record
final String foo = resultSet.getString("foo");
final int bar = resultSet.getInt("bar");
// Insert a row with these values into table2
insertStatement.clearParameters();
insertStatement.setString(1, foo);
insertStatement.setInt(2, bar);
insertStatement.executeUpdate();
}
}
}
The rows are inserted into table2 as you iterate through the results from table1, so there's no need to store the whole result set.
You can also use the prepared statement's addBatch() and executeBatch() methods to queue up all the inserts and send them to the database all at once, instead of sending a separate message to the database for each individual inserted row. But that forces JDBC to hold all the pending inserts in memory locally, which it seems you're trying to avoid. So the one-row-at-a-time inserts are your best bet in this case.
If you don't want to manually list out all the field names for every table in the database, you should be able to do this two-step process instead:
Copy the table schema using the answer in this question.
Use resultSet.getMetaData() to get the list of fields, and use that to drive a modified version of the SELECT/INSERT code in #Wyzard's answer.
I will post code here if I get it working.
If I'm not mistaken, a preparedStatement is destroyed from cache once a connection is closed. At the moment my app is setup so that I have a function to get POJO objects from the database based on the single POJO object passed in. I then have another function to get id's of ALL objects in that table for cases where I need a list, and then in the while loop of that function I get the entire objects one at a time.
However doing this doesn't take advantage of cached queries right? So what is the best way to have a generic getter SQL function that can make use of cached preparedstatements if it is a list of items or a single item? In PHP I can do this easily by checking if the passed in param is an array or not, but Java requires you to define the param object.
So for example, let's say users, here is what I currently have:
//Get user object
public User getUser(User user) throws SQLException {
Connection connection = connectionWrapper.getConnection();
String query = "SELECT firstName, lastName FROM users WHERE userId = ?";
PreparedStatement statement = connection.prepareStatement(query);
statement.setInt(1, user.getUserId());
ResultSet rs = statement.executeQuery();
if (rs.next()) {
//Get database details and set into object
}
rs.close();
statement.close();
connection.close();
}
//Get all users
public List<User> getAllUsers() throws SQLException {
List<User> userArr = new ArrayList<User>();
Connection connection = connectionWrapper.getConnection();
String query = "SELECT userId FROM users";
PreparedStatement statement = connection.prepareStatement(query);
ResultSet rs = statement.executeQuery();
while (rs.next()) {
int id = rs.getInt("userId");
User user = new User(id);
getUser(user);
userArr.add(user);
}
rs.close();
statement.close();
connection.close();
return userArr;
}
It would be nice to be able for the getUser function to handle both an individual object case like above and an array case where an array of user objects (with userId's set) are passed in and it loops through the array to get all objects before closing the connection. Is there a non-messy way to do this or should I just pass a User array to the getUser function in all cases, even if it's just one?
If what you're after is performance, then executing 5 queries to find 5 users given an array of 5 IDs is not really the best solution. You'd better execute a single query that loads all the users at once, using
select firstName, lastName FROM users WHERE userId in (?, ?, ?, ?, ?)
Similarly, your getAllUsers() method is extremely inefficient. It should execute a single query, instead of executing a query to get all the IDs, and then a query for every ID found.