Difference between CreateStatement and PreparedStatement in JDBC [duplicate] - java

This question already has answers here:
Difference between Statement and PreparedStatement
(15 answers)
Closed 9 years ago.
Hi I am trying to learn JDBC.
and here is my question:-
What is the Use of PreparedStatement in JDBC Because We can achieve the same effect by using createStatement(); too.
I mean if there is a query like:
Select * from tbl_name where id = somevalue
Then We can achieve it by both PreparedStatement and createStatement(). As follows:
Using CreateStatement():
try {
DataInputStream dis=new DataInputStream(System.in);
System.out.println("Enter id :- ");
int id=Integer.parseInt(dis.readLine());
String q="Select * from tbl_name where id="+id;
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(q);
while(rs.next()) {
//fetching part
}
} catch(Exception ex){ ... }
Using PreparedStatement:
try {
PreparedStatement preStatement=conn.prepareStatement("Select * from tbl_name where id=?");
DataInputStream dis=new DataInputStream(System.in);
System.out.println("Enter id:- ");
int id=Integer.parseInt(dis.readLine());
preStatement.setInt(1, id);
ResultSet result = preStatement.executeQuery();
while(result.next()){
// fetch the data
}
}catch(Exception ex){ ... }
As both of these programs are capable of doing the same task.
Why there is provision of two different Methods? Also looping seems to be easy if avoid repeatation is the answer.
Can any one tell me which one is good to use ?
what is the provision of each of them?
What is the difference between them, and which one optimizes the code?

The prepared statement concept is not specific to Java, it is a database concept. Precompiling of statement means, when you execute a SQL query, database server will prepare a execution plan before executing the actual query, this execution plan will be cached at database server for further execution.
The advantages of Prepared Statements are:
As the execution plan get cached, performance will be better.
It is a good way to code against SQL Injection as escapes the input values.
When it comes to a Statement with no unbound variables, the database is free to optimize to its full extent. The individual query will be faster, but the down side is that you need to do the database compilation all the time, and this is worse than the benefit of the faster query.

With the createStatement the underlying database has to parse and compile the passed select query every time the statement is executed. This can impact performance. You can kind of "save" the query logic in a prepared statement and just pass in the query parameters, which could be the variable part of your query, every time the statement is executed.

Related

Getting Incorrect return in java accessing sql database

This is the code im using in java to query the database
connect = DriverManager.getConnection (url, "user", "pass");
state = connect.createStatement();
String meetID = "SELECT GamerTag FROM backup";
ResultSet rs = state.executeQuery(meetID);
while(rs.next()){
System.out.println(rs.toString());
}
Im not getting the values of the row in the database im getting this instead
com.mysql.jdbc.JDBC4ResultSet#108137c9
You're printing the result of the toString method of the Recordset object, which appears to print out the object's name and hashcode.
Instead, try to print the value of a column. Perhaps using getString:
System.out.println(rs.getString("GamerTag"));
The documentation for Java's recordset looks confusing, you might be better off searching for examples.
What do you expect rs.toString() should do it will just print the hash of the resultsetObject if you want to get the column values you should do this way
while(rs.next()){
System.out.println(rs.getString("yourFirstColumnName")+" "+
rs.getString("yourSecondColumnName")+" "+
rs.getString("yourThirdColumnName"));
}
Really you should use PreparedStatement. In your case though you are not using any parameterizedQuery but One of the major benefits of using PreparedStatement is better performance. PreparedStatement gets pre compiled.
In database and there access plan is also cached in database, which allows database to execute parametric query written using prepared statement much faster than normal query because it has less work to do. You should always try to use PreparedStatement.
So you can do something like this
String query = "SELECT GamerTag FROM backup"
PreparedStatement st =connect.prepareStatement("query");
ResultSet rs = st.executeQuery();

Inserting data into Multiple tables

String insert1 = "INSERT INTO Table1(Col1, col2, col3)"
+ "VALUES(?,?,?)";
String insert2 = "INSERT INTO Table2(Colx, coly)"
+ "VALUES(?,?)";
Connection conn = aConn;
PreparedStatement ps = null;
try {
ps = conn.prepareStatement(insert1);
// ps.addBatch(insert2);
I'm trying to Insert Data into multiple tables at a time, and it seems like addBatch(String sql) is not defined for PreparedStatement.
Is there any alternate way?
First of all, a PreparedStatement is used to cache a single SQL statement. This has the advantage that the driver/database might optimize the statement since it is expecting many of them and since it is a parameterized statement. If you want to use it for two different SQL statements you need two PreparedStatements.
In order to add rows to the statement you need to set your parameters using set*(1,...), set*(2,...), set*(3,...), etc. and then call addBatch() (no arguments!). Finally you submit the batch of statements using executeBatch().

Execute more than one statement at once in JDBC

I am using MySQL Database. The following piece creates a record and gets the id from the created record:
insertStmt = connection
.prepareStatement("INSERT INTO bugs (summary, status, report_date) VALUES (?, ?, ? )");
//...
insertStmt.executeUpdate();
idQuery = connection.prepareStatement("SELECT LAST_INSERT_ID()");
rs = idQuery.executeQuery();
if (rs != null) {
rs.next();
return new Long(rs.getLong(1)).toString();
}
Now, if two threads execute this and their execution is interleaved, say, the first thread inserts the record followed by the insertion by the second thread, after which the first thread calls last_insert_id() which will be incorrect for this thread as the second thread has already inserted a record.
This might be overcome using synchronization, however. Is there a way we can execute the two statements in a single database call?
LAST_INSERT_ID works per-connection, and as your question states you can have a race condition if two statements in two threads use the same connection.
You have two ways around this:
1: Use a separate connection per thread (not easy, but this is really the best option for scaling and sense; use connection pooling)
2: Use the form of executeUpdate that records the auto-generated key in the same API call, allowing you to read it back later using getGeneratedKeys so that you don't have to use LAST_INSERT_ID in a second query, so avoiding the race condition. There's a similar form of prepareStatement that you can use in prepared statements.
Option 2 is probably what you want in the short term. The link in option 2 goes straight to that API. This link is a MySQL article outlining how to use it.
According to https://dev.mysql.com/doc/refman/5.7/en/connector-j-reference-configuration-properties.html, you should be able to add ?allowMultiQueries=true to your JDBC connection string. Then you would be able to pass multiple statements, separated by semicolons, in Statement#execute(String sql) calls.
Edit: or, use a stored procedure that does what you want. Or, as you said, synchronize the Java code.
You can try using a Multiquery, combined the Insert and the Select Last_INSERT_ID() in the same string.
1) prepare the connection for using the multiquery:
"jdbc:mysql://"+host+"/"+database+"?allowMultiQueries=true"
2) Combine The Insert Query with the Select:
multiQuerySqlString="INSERT INTO bugs (summary, status, report_date) VALUES (1, 2, 3 ); SELECT LAST_INSERT_ID()"
3) esecute the query and expecting multiple result sets:
boolean isResultSet = statement.execute();
ResultSet res = statement.getResultSet();
if isResultSet = statement.getMoreResults();
// Second ReulstSet object
res = cs.getResultSet();
I hope it works
If you have to do this all on a single connection you can ask the driver to return the generated ID:
insertStmt = connection.prepareStatement("...",PreparedStatement.RETURN_GENERATED_KEYS );
insertStmt.executeUpdate();
ResultSet rs = insertStatement.getGeneratedKeys();
Long id = null;
if (rs != null)
{
rs.next();
id = rs.getLong(1);
}
connection.commit();
return id;
Depending on the driver you might need a different prepareStatement() call that takes the column names as the second parameter:
insertStmt = connection.prepareStatement("INSERT ", new String[] {"ID"});
But even in with the above code you should be doing the concurrent inserts on different physical connections to be able to properly control your transactions.

Can not issue data manipulation statements with executeQuery() [duplicate]

This question already has answers here:
Cannot issue data manipulation statements with executeQuery()
(11 answers)
Closed 7 years ago.
I use com.mysql.jdbc.Driver
I need insert and get id.
My query:
INSERT INTO Sessions(id_user) VALUES(1);
SELECT LAST_INSERT_ID() FROM Sessions LIMIT 1;
error -
Can not issue data manipulation
statements with executeQuery()
How insert and get id?
You will need to use the executeUpdate() method to execute the INSERT statement, while you'll need to use the executeQuery() method to execute the SELECT statement. This is due to the requirements imposed by the JDBC specification on their usages:
From the Java API documentation for Statement.executeQuery():
Executes the given SQL statement, which returns a single ResultSet
object.
Parameters:
sql - an SQL statement to be sent to the database, typically a static SQL SELECT statement
and from the Java API documentation for Statement.executeUpdate():
Executes the given SQL statement, which may be an INSERT, UPDATE, or DELETE statement or an SQL statement that returns nothing, such as an SQL DDL statement.
Parameters:
sql - an SQL Data Manipulation Language (DML) statement, such as INSERT, UPDATE or DELETE; or an SQL statement that returns nothing, such as a DDL statement.
Your code (pseudo-code posted here) should appear as:
statement.executeUpdate("INSERT INTO Sessions(id_user) VALUES(1)"); // DML operation
statement.executeQuery("SELECT LAST_INSERT_ID()"); // SELECT operation
And of course, the MySQL documentation demonstrates how to perform the same activity for AUTO_INCREMENT columns, which is apparently what you need.
If you need to execute both of them together in the same transaction, by submitting the statements in one string with a semi-colon separating them like the following:
statement.execute("INSERT INTO Sessions(id_user) VALUES(1); SELECT LAST_INSERT_ID() FROM Sessions LIMIT 1;");
then you'll need to use the execute() method. Note, that this depends on the support offered by the Database and the JDBC driver for batching statements together in a single execute(). This is supported in Sybase and MSSQL Server, but I do not think it is supported in MySQL.
may be you are using executeQuery() but to manipulate data you actually need executeUpdate() rather than executeQuery()
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet generatedKeys = null;
try {
connection = m_Connection;
preparedStatement = (PreparedStatement) connection.prepareStatement(qString, Statement.RETURN_GENERATED_KEYS);
// ...
int affectedRows = preparedStatement.executeUpdate();
if (affectedRows == 0) {
throw new SQLException("Creating user failed, no rows affected.");
}
generatedKeys = preparedStatement.getGeneratedKeys();
int id = -1;
if (generatedKeys.next()) {
id = generatedKeys.getInt(1);
id = -1;
} else {
throw new SQLException("Creating user failed, no generated key obtained.");
}
} finally {
}
For non-select SQL statements you use ExecuteNonQuery();
To get the last inserted id, you can do this SQL statement.
SELECT LAST_INSERT_ID() AS last_id
Although there's probably an java wrapper for that select statement.
Links:
http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
http://wiki.bibalex.org/JavaDoc/org/bibalex/daf/handlers/dbhandler/DBConnection.html

Search a ResultSet for a specific value method?

Is there a ResultSet method that I can use that would search through a ResultSet and check whether it has the specific value/element?
Similar to ArrayList.contains() method.
If there isn't, you don't need to type up a search method, I'll make one :)
Thanks in advance.
Don't do the search in Java side. That's unnecessarily slow and memory hogging. You're basically taking over the job the DB is designed for. Just let the DB do the job it is designed for: selecting and returning exactly the data you want with help of the SQL language powers.
Start learning the SQL WHERE clause. For example, to check if an username/password mathes, do:
connection = database.getConnection();
preparedStatement = connection.prepareStatement("SELECT * FROM user WHERE username=? AND password=md5(?)");
preparedStatement.setString(1, username);
preparedStatement.setString(2, password);
resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
// Match found!
} else {
// No match!
}
Assuming you mean a SQL ResultSet, the answer is no, you have to write one. The JDBC driver usually won't retrieve all the rows at once (what if the query returned 1 million rows). You will have to read the rows and filter them yourself.

Categories