MySQL ResultSet scrollable/updatable not working as expected - java

I have a test JDBC program that tries to alter the Scrollability and Updatability features of a ResultSet. Unfortunately, all the combinations of TYPE_ and CONCUR_ seem to produce the same result (TYPE_SCROLL_INSENSITIVE and CONCUR_READ_ONLY).
Even with the default (TYPE_FORWARD_ONLY) it's possible to scroll through the ResultSet. Can anyone explain why this is?
I am using MySQL 5.6 and JDK7. Here is the code:
public class ResultSetTest3 {
public static void main(String[] args)
{
Connection conn;
try {
conn = DriverManager.getConnection("jdbc:mysql://localhost/bd", "user", "password");
Statement sta = conn.createStatement();
sta.execute("DELETE FROM test");
sta.close();
PreparedStatement ps = conn.prepareStatement("INSERT INTO test VALUES(?, ?)");
for(int i=1; i<=100; i++)
{
ps.setInt(1, i);
ps.setString(2, "Teste " + i);
ps.addBatch();
}
ps.executeBatch();
ps.close();
System.out.println("TYPE_FORWARD_ONLY CONCUR_READ_ONLY");
result(conn, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
System.out.println("===================================");
System.out.println("TYPE_SCROLL_INSENSITIVE CONCUR_READ_ONLY");
result(conn, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
System.out.println("===================================");
System.out.println("TYPE_SCROLL_SENSITIVE CONCUR_READ_ONLY");
result(conn, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY);
System.out.println("===================================");
System.out.println("TYPE_FORWARD_ONLY CONCUR_UPDATABLE");
result(conn, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
System.out.println("===================================");
System.out.println("TYPE_SCROLL_INSENSITIVE CONCUR_UPDATABLE");
result(conn, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
System.out.println("===================================");
System.out.println("TYPE_SCROLL_SENSITIVE CONCUR_UPDATABLE");
result(conn, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
System.out.println("===================================");
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void result(Connection conn, int type, int update) throws SQLException
{
Statement sta = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = sta.executeQuery("SELECT * FROM test");
System.out.println(rs.getConcurrency() + " " + update);
System.out.println(rs.getType() + " " + type);
try
{
rs.absolute(10);
System.out.println(rs.getInt(1) + " - " + rs.getString(2));
rs.relative(20);
System.out.println(rs.getInt(1) + " - " + rs.getString(2));
rs.previous();
System.out.println(rs.getInt(1) + " - " + rs.getString(2));
rs.first();
System.out.println(rs.getInt(1) + " - " + rs.getString(2));
try {
System.out.println("AGORA!!!");
Thread.sleep(20000);
} catch (Exception e) {
System.out.println(e);
}
rs.absolute(3);
System.out.println(rs.getInt(1) + " - " + rs.getString(2));
}
catch(SQLException e)
{
System.out.println("Not Scrollable");
}
try
{
rs.next();
rs.next();
rs.next();
rs.next();
rs.deleteRow();
rs.next();
rs.updateString(2, "TesteUpdate");
rs.insertRow();
}
catch(SQLException e)
{
System.out.println("Not Updatable");
}
rs.close();
sta.close();
}
}

As Mark Rotteveel mentions in a comment to the question, MySQL caches ResultSet data by default (also discussed in a blog article by
Ben J. Christensen here). An apparent side-effect of this caching is that MySQL Connector/J will "upgrade" a TYPE_FORWARD_ONLY ResultSet to actually be scrollable:
Statement s = dbConnection.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
ResultSet rs = s.executeQuery("SELECT * FROM testdata");
rs.last();
System.out.println(String.format("Current row number: %d", rs.getRow()));
rs.previous();
System.out.println(String.format("Current row number: %d", rs.getRow()));
displays
Current row number: 3
Current row number: 2
According to the blog article cited above, the way to prevent caching and "stream" the ResultSet data is to use Statement.setFetchSize:
Statement s = dbConnection.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
s.setFetchSize(Integer.MIN_VALUE);
ResultSet rs = s.executeQuery("SELECT * FROM testdata");
rs.next();
System.out.println("Data from first row: " + rs.getString(2));
System.out.println("now let's try rs.last() ...");
try {
rs.last();
System.out.println("... Okay, done.");
} catch (Exception e) {
System.out.println("... Exception: " + e.getMessage());
}
resulting in
Data from first row: Gord
now let's try rs.last() ...
... Exception: Operation not supported for streaming result sets

Try in this way to create a Scroll-Insensitive, read only ResultSet object statement object.
Statement sta = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
instead of
Statement sta = conn.createStatement();
Do the same for PreparedStatement as well.
Through this ResultSet type the cursor can move in any direction. It is insensitive which means result set that does not reflect changes made while it is still open. It is default resultset type for MySql.
Must read Retrieving and Modifying Values from Result Sets

Related

Checking if username exists in MySQL Java

I have a register dialog that implements an action listener. If a user enters a name and it already exists, I want to print a message on the console. If the username does not exist, MySQL should add it into the database. Unfortunately this code won't work:
private void regButtonActionPerformed(java.awt.event.ActionEvent evt) {
if(!userBox.getText().equals(""))
{
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/genx", "root", "Warlock1989");
Statement stmt = con.createStatement();
String query = "SELECT name FROM accounts";
ResultSet rs = stmt.executeQuery(query);
while(rs.next())
{
String uname = rs.getString("name");
if(!uname.equals(userBox.getText()))
{
PreparedStatement pstmt = con.prepareStatement("INSERT INTO accounts(name) VALUES(?)");
pstmt.setString(1, userBox.getText());
pstmt.executeUpdate();
System.out.println("Username " + userBox.getText() + " has been registered.");
}
else
{
System.out.println("Username " + userBox.getText() + " already exists.");
}
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
Your current approach loads all records from database and tries to find the user which will cause memory exceptions if the database consists of huge records. So,
Do not fetch all records from database rather simply run the query using where name=? to check user already exists in the database as shown below:
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
ResultSet rs = null;
try {
String userInput = userBox.getText();
String query = "SELECT name FROM accounts where name=?";
pstmt1 = con.preparedStatement(query);
pstmt1.setString(1, userInput);
rs = pstmt1.executeQuery();
if(rs.next()) {
pstmt2 = con.prepareStatement("INSERT INTO accounts(name) VALUES(?)");
pstmt2.setString(1, userInput);
pstmt2.executeUpdate();
System.out.println("Username " + userInput + " has been registered.");
} else {
System.out.println("Username " + userInput + " already exists.");
}
} catch(SQLException sqlexe) {
//add logging
} finally {
if(pstmt1 != null)
pstmt1.close();
if(pstmt2 != null)
pstmt2.close();
if(rs != null)
rs.close();
}
Your current code does not release the resultsset & preparedstatement objects, so ensure that you are releasing the resources in the finally block.

How to pass variables into SQLite in java

I'm trying to create a SQLite for my game, and its working fine until I try to put some variables in the table HighScores.
If I try to put a variable it only works if I delete the "NOT NULL".
public void SQLite(){
Connection c = null;
Statement stmt = null;
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:test.db");
stmt = c.createStatement();
String sql = "CREATE TABLE HighScores " +
"(ID INT PRIMARY KEY NOT NULL," +
" POINTS INT NOT NULL, " +
" NAME CHAR(50) NOT NULL, " +
" TIME INT NOT NULL, " +
" LEVEL INT NOT NULL)";
stmt.executeUpdate(sql);
c.setAutoCommit(false);
System.out.println("Opened database successfully");
stmt = c.createStatement();
String sql2 = "INSERT INTO HIGHSCORES (ID,POINTS,NAME,TIME,LEVEL) " +
"VALUES (1, ?, 'rodrigo', 99, 1 );";
PreparedStatement ps = c.prepareStatement(sql2);
ps.setInt(1, 5);
stmt.executeUpdate(sql2);
stmt.close();
c.commit();
c.close();
} catch ( Exception e ) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(0);
}
}
Opened database successfully.
java.sql.SQLException: NOT NULL constraint failed: HighScores.POINTS
You are calling executeUpdate on stmt instead of the prepared statement. Since sql2 does not have any value for POINTS, it try to insert null hence the exception.
Change :
stmt.executeUpdate(sql2);
to
ps.executeUpdate();

The DataBase is Locked..inserting values in table using a Loop

I am making a restaurant management application in java using sqlite database. In application when order confirm button is pressed the application is supposed to insert into order table, insert into order dishes/Items and minuses the quantity of each ingredient used in dish that is added in an order..
When i tried following code it says "SQLExcption:The Database is Locked "
for (int i = 0; i < orderTable.getRowCount(); i++) {
pst = con.prepareStatement("select dishId from dishes where dishName = '" + orderTable.getValueAt(i, 1) + "'");
rs = pst.executeQuery();
int dishId = rs.getInt("dishId");
pst = con.prepareStatement("insert into orderDishes values(?,?,?)");
pst.setInt(1, currentOrderNumber);
pst.setInt(2, dishId);
pst.setInt(3, (int) orderTable.getValueAt(i, 0));
pst.executeUpdate();
pst = con.prepareStatement("select ingId , quantity from dishIng where dishId = '" + dishId + "'");
rs = pst.executeQuery();
while (rs.next()) {
ingReducedQuantity = rs.getInt("quantity");
ingId = rs.getInt("ingId");
pst1 = con1.prepareStatement("select qunatity from ingriedients where ingId = '" + ingId + "'");
rs1 = pst1.executeQuery();
previousQuantity = rs1.getInt("qunatity");
pst1.close();
rs1.close();
con1.commit();
newQuantity = previousQuantity - ingReducedQuantity;
// Here it gives exception
pst1 = con1.prepareStatement("update ingriedients set qunatity = '" + newQuantity + "' where ingId = '" + ingId + "'");
pst1.executeUpdate();
con1.commit();
}
}
I think exception comes in while loop before updating ingriedients table but i don,t know why..plz suggest some solution..
before every connection and statements you need to close any privious connection and statement
because sqlite does not support more than one active transactions, so before the first con1.prepareStatement (in the while loop ) in your code, close other previous connections and statements also, I mean pst, con, etc

Java SQLite database, insert entry giving nullPointerException

I am trying to create a generic method that can add an entry into a SQLite database, using Eclipse and Java.
When the table name is hardcoded it works fine, but when I try to pass in the table name as a string it is giving me a nullPointerException.
below is the method that creates that table:
public static void Table()
{
Connection c = null;
Statement stmt = null;
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:test.db");
System.out.println("Opened database successfully");
stmt = c.createStatement();
String sql = "CREATE TABLE IF NOT EXISTS COMPANY " +
"(ID INT PRIMARY KEY NOT NULL," +
" NAME TEXT NOT NULL, " +
" AGE INT NOT NULL, " +
" ADDRESS TEXT, " +
" SALARY REAL)";
stmt.executeUpdate(sql);
stmt.close();
c.close();
} catch ( Exception e ) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(0);
}
System.out.println("Table created successfully");
}
and here is the method that inserts an entry into the created table. I want to pass in the table name through the method rather than hard coding it:
public static void Insert(String table, int id, String name, int age, String address, String salary)
{
Connection c = null;
PreparedStatement pstmt = null;
try {
Class.forName("org.sqlite.JDBC");
c = DriverManager.getConnection("jdbc:sqlite:test.db");
c.setAutoCommit(false);
System.out.println("Opened database successfully");
String query="INSERT INTO "+table+" (ID,NAME,AGE,ADDRESS,SALARY) VALUES (?,?,?,?,?)";
PreparedStatement stmt = c.prepareStatement(query);
pstmt.setInt(1,id);
pstmt.setString(2,name);
pstmt.setInt(3, age);
pstmt.setString(4, address);
pstmt.setString(5, salary);
pstmt.executeUpdate();
pstmt.close();
c.commit();
c.close();
} catch ( Exception e ) {
System.err.println( e.getClass().getName() + ": " + e.getMessage() );
System.exit(0);
}
System.out.println("Records created successfully");
}
You have small mistake
just you have created two different PreparedStatement object
So change
PreparedStatement stmt = c.prepareStatement(query);
to
pstmt = c.prepareStatement(query);

How to get column to equals according in database

I got problem with this on IFELSE statement
what i should i do? for equals of my position to database ACCESS
. I want to do is if the Admin is correct they show the CP and Staff is correct they show the AS for getting on position to my database.
addStudents AS = new addStudents();
ControlPanel CP = new ControlPanel();
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager
.getConnection("jdbc:odbc:slcvJavaEnrollment");
Statement st = con.createStatement();
ResultSet rs = st
.executeQuery("SELECT * FROM loginUsers where Username='"
+ userTxt.getText() + "' and Password='"
+ passTxt.getText() + "'");
if (rs.getString("Position").contentEquals("Admin")) {
JOptionPane.showMessageDialog(null, "WELCOME ADMIN");
CP.show();
dispose();
con.close();
st.close();
} else if (rs.getString("Postion").contentEquals("Staff")) {
JOptionPane.showMessageDialog(null, "WELCOME STAFF");
AS.show();
dispose();
con.close();
st.close();
}
} catch (Exception e) {
System.out.println(e);
}
Your missing the while (rs.next()) to move the result set to the next result. Try this out. Also as #Learing pointed out, you spelled "Position" wrong in your else if.
while (rs.next()) {
if (rs.getString("Position").contentEquals("Admin")) {
JOptionPane.showMessageDialog(null, "WELCOME ADMIN");
CP.show();
dispose();
con.close();
st.close();
} else if (rs.getString("Position").contentEquals("Staff")) {
JOptionPane.showMessageDialog(null, "WELCOME STAFF");
AS.show();
dispose();
con.close();
st.close();
}
}
EDIT
To prevent SQL injection, you should use a PreparedStatment.
Try this instead of what you have
PreparedStatment pstmt = conn.prepareStatement("SELECT * from loginUsers WHERE Username=? and Password=?");
pstmt.setString(1, userTxt.getText());
pstmt.setString(2, passTxt.getText());
ResultSet rs = pstmt.executeQuery();

Categories

Resources