Is there any way to improve performance of prepared statements? It's about many select queries. I do the queries like this way:
String query = "SELECT NAME, ADDRESS "
+ "FROM USERS "
+ "where ID = ? "
+ "group by NAME, ADDRESS";
PreparedStatement pstmt = connection.prepareStatement(query);
for(long id: listIDs){
pstmt.setLong(1, id);
ResultSet rs = pstmt.executeQuery();
...
}
The database is MySQL.
It's the server that prepares the queries (that's why you need a connection). To improve performance of prepared statements you have to tune the DB server itself (indexes, etc...).
Another way, is writing queries that only get the results you want.
Another idea is to cache in client side the data you know you'll be using a lot, this way you won't be querying the DB for the same data again and again.
Two suggestions:
Make sure the ID field is indexed.
Combine many small queries into one, for example by using WHERE ID IN (...).
For a more detailed discussion of the latter, see Batching Select Statements in JDBC.
You might also want to investigate whether your JDBC driver supports statement caching. I know oracle's JDBC driver does support.
Related
Trying to delete record from my database, but I get the error "Unknown column '' in 'where clause'".
private void deleteUser() {
String query = "DELETE FROM user WHERE Name =" + tfemail.getText() + "";
executeQuery(query);
showUsers();
}
You can't write queries this way. Imagine someone put in the tfemail field this text:
"Joe' OR FALSE"
and let's see what that would do to your SQL query:
DELETE FROM user WHERE Name = 'Joe' OR FALSE;
bye, database!
Some dbs let you execute stuff on the server the db engine runs on. Which means this trick can be used to completely hack the machine or format the disk entirely. bye, entire machine.
This also means your executeQuery method needs to be removed - that abstraction ('here is some SQL, please run it') is rarely useful (as it cannot contain any user input), and entices you to write security leaks.
The solution is prepared statements:
PreparedStatement ps = con.prepareStatement("DELETE FROM user WHERE Name = ?");
ps.setString(1, "Joe");
ps.executeUpdate();
This solves your problem, and does so safely - ps.setString(1, "Joe' OR FALSE"); is now no longer an issue (the DB engine or JDBC driver guarantees that it will take care of the problem; the effect would be to delete the entry in your user table that literally reads "Joe' OR FALSE").
Furthermore, storing passwords in a database is not an acceptable strategy; the solution is e.g. bcrypt: Use a hashing algorithm designed specifically to store passwords.
String query = "DELETE FROM user WHERE Name ='" + tfemail.getText() + "'";
^ ^
|___________add___________|
I have a java servlet application and I'm using a prepared query to update a record in a SQL Server Database table.
Lets say I want to execute UPDATE MyTable SET name = 'test' WHERE id = '10'. (Yes, id is a varchar)
I used the following code to make this happen:
PreparedStatement pstmt = con.prepareStatement("UPDATE MyTable SET name = ? WHERE id = ?");
pstmt.setString(1, getName() );
pstmt.setString(2, getID() );
pstmt.executeUpdate();
I found out that while I was running a JMeter script to simulate 2 users, this statement causes a deadlock in my database.
I wanted to check what my values were in the SQL Profiler so I used the following code, so I could check the values.
String query = String.format("UPDATE MyTable SET name = '%s' WHERE id = '%s' ", getName(), getID() );
PreparedStatement pstmt = con.prepareStatement(query);
pstmt.executeUpdate();
Suddenly my deadlock was gone! It's a shame the last approach is vulnerable to SQL injection.
Is there somebody who can tell me what is going on and/or how to fix it?
Ok I finally found the problem and solution to my problem.
It seemed that the combination of the jTDS JDBC driver with MSSQL was the 'problem'.
This article explained my situation exactly. And with the help of this FAQ I was able to set the datasource to the right configuration.
From what I understand:
If you have statement that uses a String-like index (Like in my situation), the table performs an index SCAN instead of an index SEEK. This causes the whole table to be locked and vulnerable to deadlocks.
I hope this will help other people too.
so I have a software which basically downloads 1.5K game server address from my MySQL db. It then pings all of them and then upload the information such as online players back to the database. The process looks like this:
Download server address
Ping the servers and get information
Upload information back to the database
So far I have been able to solve the part where it download the server host name and pings them but the problem arises when updating the servers.
To update I thought about using a for loop to construct one BIG string of many update statements and execute it at once but this is prone to sql injections. So idealy one would want to use prepared statements.
The SQL update statement i'm using is:
UPDATE serverlist SET `onlineplayers` = '3', maxplayers = '10',
name = 'A game server' WHERE `ip` = 'xxx.xxx.xxx.xxx' AND `port` = 1234;
So my question is: How can i execute all the 1.5K updates statements using parameterized queries?
If you google for "jdbc bulk update" you'll get lots of results like this one or this one.
The latter has an example like this:
try {
...
connection con.setAutoCommit(false);
PreparedStatement prepStmt = con.prepareStatement(
"UPDATE DEPT SET MGRNO=? WHERE DEPTNO=?");
prepStmt.setString(1,mgrnum1);
prepStmt.setString(2,deptnum1);
prepStmt.addBatch();
prepStmt.setString(1,mgrnum2);
prepStmt.setString(2,deptnum2);
prepStmt.addBatch();
int [] numUpdates=prepStmt.executeBatch();
for (int i=0; i < numUpdates.length; i++) {
if (numUpdates[i] == -2)
System.out.println("Execution " + i +
": unknown number of rows updated");
else
System.out.println("Execution " + i +
"successful: " numUpdates[i] + " rows updated");
}
con.commit();
} catch(BatchUpdateException b) {
// process BatchUpdateException
}
Sounds like you want to do a batch SQL update. Prepared statements are your friend. Here's an example of using prepared statements in batch:
http://www.mkyong.com/jdbc/jdbc-preparedstatement-example-batch-update/
Using prepared statements makes setting parameters easier and it allows the DB to efficiently perform multiple updates. Executing multiple SQL strings would work but would be inefficient since each SQL string would be sent to the DBMS, parsed, compiled, then executed. With prepared statements the SQL is parsed and compiled once then reused for future updates with different parameters.
Another important step that you should be aware about during MySQL batch update / insert is JDBC Connection propertie rewriteBatchedStatements=true ( false by default ). Without it batch mode is useless.
It cost me 1 day to "fix bug" till I found out this.
When you have small number of lines and close client-to-DB location ( 1ms ping ) , you even can't realize that you in "fake batch mode" , but when I switch environment to remote client ( ping=100ms ) and 100k lines to update , it would take 4hours of "batch mode update" with default rewriteBatchedStatements=false and just 2minutes with rewriteBatchedStatements=true
Create a prepared statement:
String sql = "update serverlist SET onlineplayers = ?, maxplayers = ?, name = ? where ip = ? and port = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
Then loop through your list, and at each iteration, do
stmt.setInt(1, onlinePlayers);
stmt.setInt(2, maxPlayers);
stmt.setString(3, name);
stmt.setString(4, ip);
stmt.setInt(5, port);
stmt.executeUpdate();
For better performance, you could also use batch updates.
Read the JDBC tutorial.
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.
Could someone please give me a link on how to create a query in JDBC that gets a variable name in the WHERE statement, or write an example, to be more specific, my code looks something like this:
private String getLastModified(String url) {
String lastModified = null;
ResultSet resultSet;
String query = "select LastModified from CacheTable where " +
" URL.equals(url)";
try {
resultSet = sqlStatement.executeQuery(query);
}
Now I need the syntax that enables me to return a ResultSet object where URL in the cacheTable equals url from the method's argument.
thanks
The easiest way would be
String query = "select LastModified from CacheTable where url = '" + url +"'";
You should use bind variables though:
String query = "select LastModified from CacheTable where url = ?";
prepStmt = conn.prepareStatement(query);
prepStmt.setString(1, url);
rs = prepStmt.executeQuery();
To take it one step further you should really use DBUtils from apache-commons or Sping JDBC framework. A lot of JDBC work is mundane and error prone due to the number of steps involved with it. Both links have working examples for you to get started.
These helper libraries will make your life much more comfortable :-).
To clear a misconception: JDBC and SQL are two entirely different things. Databases only understand the SQL language. It's a (semi)standard which you can learn here. JDBC is just a Java API which enables you to execute SQL language using Java code. Nothing less, nothing more. JDBC is not a Java way of writing SQL language or so. It's just the messenger between Java code and the database. You can learn JDBC here.
That said, yes, the PreparedStatement is the way to go to set values in a SQL query. It not only eases setting fullworthy Java objects in a SQL string using the setXXX() methods, but it also saves you from SQL injection attacks.