Optimize PreparedStatements for either one or multiple queries- Java & MySQL - java

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.

Related

put data in List thenn insert it its values into database

I have to store questions in session afterward in List then insert them all into database by one click
my servlet
Question question = new Question(title, content, idExam);
request.getSession().setAttribute("question", question);
int quizKey = ExamDAO.add_question(question);
ArrayList<Question> ques = new ArrayList<Question>();
ques.add(question);
my dao
cnx = Connect.getConnection();
String req = "insert into question(title, content, id_examen) values(?,?,?)";
PreparedStatement st = cnx.prepareStatement(req, Statement.RETURN_GENERATED_KEYS);
st.setString(1, question.getTitre());
st.setString(2, question.getContenu());
st.setInt(3, question.getIdExamen());
st.executeBatch();
ResultSet rs = st.getGeneratedKeys();
if (rs.next()) {
quizKey = rs.getInt(1);
}
how to do that ?
Try st.executeUpdate(). This is usually used for manipulating statements like DELETE, INSERT or UPDATE. The method will return either the row count for SQL Data Manipulation Language (DML) statements or 0 for statements that return nothing.
If you have a List<Question> and you wish to insert all in one go then you have to utilize what is called as - batching or batch update. Refer here for more details
You will be iterating your list of questions and setting parameters for each question then adding that statement to batch (by using st.addBatch()) & then finally call - st.executeBatch().
In your code sample, you are executing a batch but there is only one prepared statement in that batch. You need as many prepared statements as number of questions in the list.
String req = "insert into question(title, content, id_examen) values(?,?,?)";
PreparedStatement st = cnx.prepareStatement(req, Statement.RETURN_GENERATED_KEYS);
for(Question question : ques){
st.setString(1, question.getTitre());
st.setString(2, question.getContenu());
st.setInt(3, question.getIdExamen());
st.addBatch();
}
st.executeBatch();
With this approach, you might have issues in collecting generated keys as illustrated in this SO question so if you really need those ids , you will have to turn off auto commit, execute updates in loop without batching, collected generated ids in a map or list for each insert statement and then finally commit your connection in the end.

displaying list of values in jsp

String sql = "SELECT ID, NAME, SALARY FROM EMPLOYEE";
public List<Employee> getAllEmployees(Connection con){
List<Employee> elist = new ArrayList();
try{
//prepared statement
//
//
}catch(){
//exception
}
return elist;
}
Guys, I have a java class which selects List of values from DB. So far my code is running good I did debugging and I can see my query in eclipse console. Now I need to display java returned value(LIST) with different data types in jsp page. I am stuckI somehow I need to loop javaclass return value or something and display in jsp page. Please help me I have spent 2 hrs and can't come up with anything. i am uisng struts 2.0 and Employee class contains setter/getter
String sql = "select ID, NAME, SALARY FROM EMPLOYEE";
PreparedStatement ps = con.prepareStatement(sql);
ResultSet rs = ps.executeQuery();
you have to store all the data into ResultSet. Than you have to create Arraylist.
List<Integer> values = new ArrayList<>();
values.add(index,rs.next());
values.add(index1,rs.next());
//This is way to your code. not complete code of yours.

Using PrepareStatement to get data with configurable table name

I'm trying to get some data from Oracle 11.2 using java and jdbc driver.
My goal is to get data from database using CallableStatement, but with no luck - I'm not able to put table name as parameter. I would like to have configurable table name in query. However, it would be good to keep it sanitized.
Here is an example..
public void getData() throws SQLException {
Connection conn = Config.getSQLConnection();
String query = "SELECT * FROM ?";
PreparedStatement st = conn.prepareStatement(query);
st.setString(1, Config.DATATABLE_NAME);
ResultSet rs = st.executeQuery();
if (rs.next()) {
System.out.println("SUCCESS");
System.out.println("ID:" + rs.getString("ID"));
} else {
System.out.println("FAILURE");
}
}
Is this the way it should work? Or am I missing something, or misused it?
A CallableStatement is used to make call to stored procedures.
From javadoc:
The interface used to execute SQL stored procedures
Use a PreparedStament instead for a normal select.
As an additional note don't pass the name of the table as parameter.
Create the query using concatenation.
Instead of
String query = "SELECT * FROM ?";
use
String query = "SELECT * FROM " + Config.DATATABLE_NAME;
You should use PreparedStatement instead of CallableStatement.
CallableStatement is an interface which is used to call stored procedures.

How do I get the variables in a column from java and sql?

So say a column is named Names I want to get a ArrayList of every variable inside of this column. Example:
Names
Test
Test1
Test3
River
World
Etc
I want to get all of that into an array list. Thanks for the help!
You're not giving much information in your question (e.g. what is the table you'd like to query), so here's a somewhat generic solution:
public List<String> retrieveAllColumnValues(Connection connection) throws SQLException {
String query = "SELECT Names FROM MyTable";
List<String> values = new ArrayList<>();
try (Statement stmt = connection.createStatement()) {
ResultSet rs = stmt.executeQuery(query);
while (rs.next()) {
values.add(rs.getString("Names"));
}
rs.close();
}
return values;
}
Getting data from the database through JDBC roughly consist of the following parts:
You have a Connection which you use for creating SQL Statements
When you execute the Statement, you get a ResultSet, which contains the values returned by your query
You iterate through the ResultSet and do what you need to with the values

Alternative to ResultSet for storing data from database

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.

Categories

Resources