How to access the resultset values using multi threads - java

I have created below JDBC program to get the record from database
Class.forName("oracle.jdbc.driver.OracleDriver");
String url="jdbc:oracle:thin:#db-user-rw-a.qa.amazon.com:1100/MONEY";
String username = "amazon212313";
String password = "XXXXX";
System.out.println("Connecting database...");
Connection connection = null;
if (connection == null)
{
try {
connection = DriverManager.getConnection(url, username,password);
System.out.println("Database connected!");
}
catch (Exception ex)
{
System.out.println("Database Connection Failed...!!!");
System.out.println(ex);
}
}
Statement statement=connection.createStatement();
ResultSet rs1=statement.executeQuery("select account_number,flag,flag2,flag3,flag4,flag5,flag6,flag7,amount from transaction_p2");
ResultSetMetaData metadata = rs1.getMetaData();
int columnCount = metadata.getColumnCount();
System.out.println(columnCount);
while(rs1.next())
{
// account_number in if condition
if(rs1.getString(1).contains("2195281819521610731"))
{
System.out.println(rs1.getString(1));
}
}
connection.close();
I have more than 99000 records in data base and the above program is working fine but its taking huge time to retrieve the specific account number values. It's taking more than 20 minutes (Some times beyond that) to retrieve the value.
Is there any other way to speed up the search value in result set. Like creating 100 thread to search the specific account number if it found then It should return the value.
Also, there is possibly a duplicate account number in the database. All I want that I need multithreads to access the resultset and search the specific account number and return all the found account number as per if condition.
Share yours idea to achieve this task.
Updated the program with WHERE clause and observed below in console:
Updated Code:
ResultSet rs1=statement.executeQuery("select account_number,flag,flag2,flag3,flag4,flag5,flag6,flag7,amount from transaction_p2 where account_number=2195281819521610731");
ResultSetMetaData metadata = rs1.getMetaData();
int columnCount = metadata.getColumnCount();
System.out.println(columnCount);
System.out.println(rs1.next()+"\t boolean value");
while(rs1.next())
{
// account_number in if condition
System.out.println(rs1.getString(1));
}
Output:
Connecting database...
Database connected!
12
false boolean value
If I used execute() instead of executeQuery() which is returning "TRUE" but not sure how can i get resultset details.
The above account number queried in db and got result.

Why not just add the condition to your query?
instead of
select account_number,flag,flag2,flag3,flag4,flag5,flag6,flag7,amount from transaction_p2
do
select account_number,flag,flag2,flag3,flag4,flag5,flag6,flag7,amount from transaction_p2 where account_number like '%2195281819521610731%'
the last part (where account_number like '%...%') will tell SQL to only include the results whose account_number contains the given string.

Related

java.sql.SQLException: No value specified for parameter 5. update database

I have this error code in the dialog box: java.sql.SQLException: No value specified for parameter 5 when i try to update my JTable/JTextFields into my SQL database.
I have checked similar questions on the site, but non seem to have the solution to my problem. I have checked the database, i have checked my connection code, the update code and can't find where this extra parameter making the problem should be? Please help a new beginner!
So now i understand that the problem is at WHERE id=? as i suspected, but my id only exist as a row count/main key in my SQL DB, so it is going to be different depending on which row you choose/click on, so i can't set a specific value beforehand at the pst.setInt(5, ? ). What to insert instead then - so i dont lose the automatic row count on my clients list in the JTable?
//This method contains all codes for database connection.
private void upDateDB() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/num klienter", "root", "");
PreparedStatement pst = con.prepareStatement("SELECT * FROM klient");
ResultSet rs =pst.executeQuery();
ResultSetMetaData StData = rs.getMetaData();
q = StData.getColumnCount();
DefaultTableModel RecordTable = (DefaultTableModel)table.getModel();
RecordTable.setRowCount(0);
while(rs.next()){
Vector<String> columnData = new Vector<String>();
for (i = 1; i <= q; i++) {
columnData.add(rs.getString("id"));
columnData.add(rs.getString("Name"));
columnData.add(rs.getString("Birthday"));
columnData.add(rs.getString("Description"));
columnData.add(rs.getString("Other"));
}
RecordTable.addRow(columnData);
}} catch (Exception ex) {
JOptionPane.showMessageDialog(null, ex);
}}
updateButton.addActionListener(new ActionListener() {
public void actionPerformed (ActionEvent arg0) {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost/num klienter", "root", "");
PreparedStatement pst = con.prepareStatement("UPDATE klient SET Name=?,Birthday=?,Description=?,Other=? WHERE id=?");
table.getSelectedRow();
pst.setString(1, nameTxt.getText());
pst.setString(2, dayTxt.getText()+"-" + monthTxt.getText()+"-" + yearTxt.getText());
pst.setString(3, descriptionTxt.getText());
pst.setString(4, otherTxt.getText());
pst.executeUpdate();
JOptionPane.showMessageDialog(null, "Updated in database");
upDateDB();
}catch (Exception ex){
JOptionPane.showMessageDialog(null, ex);
}
Class.forName("com.mysql.cj.jdbc.Driver");
this can just be removed. It hasn't been neccessary for 20 years.
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/num klienter", "root", "");
This is a memory leak; the connection is opened, and will remain open forever; your SQL server won't allow more than a handful of open connections, so pretty soon your MySQL server will be unreachable by any service (including this java code) until you kill the java app which closes the connections. Use try with resources for all resources you create.
PreparedStatement pst = con.prepareStatement("SELECT * FROM klient");
This is also a resource and needs try-with-resources.
ResultSet rs =pst.executeQuery();
You guessed it. Try-with-resources a third time. If you find the code becoming unwieldy, JDBC is very low level and not all that great for 'end user' coding. Use a nice abstraction like JDBI or JOOQ.
columnData.add(rs.getString("Fødselsdag"));
non-ASCII in your column names? That's never going to go well. I strongly suggest you don't do it this way.
q = StData.getColumnCount();
for (i = 1; i <= q; i++) {
This is bizarre. q holds the column count - that's the number of columns in your query. And then you hardcode the 5 column names, so q is always 5. Then, you add all 5 values (id, Navn, Fødselsdag, etc), and then do that 5 times, for a total of 25 runs, and your data repeated 5 times. It is not clear what you are trying to accomplish by asking for the known information (get the column count from the metadata, which you already know).
PreparedStatement pst = con.prepareStatement("UPDATE klient SET Navn=?,Fødselsdag=?,Beskrivelse=?,Andet=? WHERE id=?");
I count 5 ?, but only 4 pst.setString statements. You forgot pst.setInt(5, theValue).
The update code gets all the same caveats about try-with-resources.
pst.setString(2, dayTxt.getText()+"-" + monthTxt.getText()+"-" + yearTxt.getText());
Not how you do date stuff with DBs. There is a pst.setDate, but optimally you should use pst.setObject, passing an instance of java.time.LocalDate. Whether MySQL actually supports that - not sure, you'd have to check.
The solution for my problem was to insert the 5th pst. statement for the id=? like this:
pst.setInt(5,table.getRowCount());

How to parse values for the result set's .equals function?

image showing my jFrame
I am making a frame which shows records in the sql table one-by-one using text fields as shown. While writing the code for the next button, I need to know the position of the result set to go to the next record. For this purpose, I used a do-while loop with an "if" condition. Following is my code:
try{
Connection conn=null;
Statement stmt=null;
ResultSet rs=null;
String url="jdbc:mysql://localhost/MYORG", userid="root", pwd="shreyansh";
conn=DriverManager.getConnection(url,userid,pwd);
stmt=conn.createStatement();
String query="select * from emp;";
rs=stmt.executeQuery(query);
String search=jTextField1.getText();
String search1=jTextField2.getText();
double search2=Double.parseDouble(jTextField3.getText());
String search3=jTextField3.getText();
rs.first();
do{
if(rs.equals(new Object[] {search, search1, search2, search3}))
break;
}while(rs.next());
rs.next();
String nm=rs.getString("Name");
String desg=rs.getString("Designation");
double pay=rs.getDouble("Pay");
String city=rs.getString("City");
jTextField1.setText(nm);
jTextField2.setText(desg);
jTextField3.setText(pay + "");
jTextField4.setText(city);
}catch(Exception e){
JOptionPane.showMessageDialog(null, e.getMessage());
}
But it shows an error "after end of Result Set".
Please help me with this.
Any suggestions to make my code better are also welcome.
Thanks in Advance!!
You can't use ResultSet.equals for this, because that is not what the Object.equals contract is for. It is for checking if an object is equal to another object of the same (or at least compatible) type. A ResultSet will therefor never be equal to an array of object values.
It looks like you want to select a single row from the emp table that matches your search values, in that case the correct solution is to ask the database for only that row. Selecting all rows and then filtering in your Java application is very inefficient, because the database has to send all rows to your application, while finding data is exactly what a database is good at.
Instead, you should use a where clause with a prepared statement:
try (Connection connection = DriverManager.getConnection(url, userid, pwd);
PreparedStatement pstmt = connection.prepareStatement(
"select * from emp where Name = ? and Designation = ? and Pay = ? and City = ?")) {
pstmt.setString(1, search);
pstmt.setString(2, search1);
pstmt.setDouble(3, search2);
pstmt.setString(4, search3);
try (ResultSet rs = pstmt.executeQuery()) {
if (rs.next() {
String nm = rs.getString("Name");
String desg = rs.getString("Designation");
double pay = rs.getDouble("Pay");
String city = rs.getString("City");
jTextField1.setText(nm);
jTextField2.setText(desg);
jTextField3.setText(String.valueOf(pay));
jTextField4.setText(city);
} else {
// handle not found case
}
}
}

Java: SQL Query: rs.next() is false after updating a column

I have a strange problem. I have a database and I want to change the values of a column. The values are safed in an Arraylist (timelist).
In order to write the values in the right row, I have a second Arrylist (namelist). So I want to read the first row in my Database, than I check the namelist and find the name. Than i take the matching value out of the timelist and write it into the database into the column "follows_date" in the row, matching to the name.
And than I read the next row of the Database, until there are no more entries.
So the strange thing is, if I change nothing in the database, the while(rs.next()) part works.
For example:
ResultSet rs = statement.executeQuery("SELECT username FROM users");
while(rs.next()){
// read the result set
String name = rs.getString("username");
System.out.println("username = " + name); //liest die namen
}
}
This would print me every name after name. But when I change the table, the while loop ends after that. (no error, the program just finishes)
ResultSet rs = statement.executeQuery("SELECT username FROM users");
while(rs.next()){
// read the result set
String name = rs.getString("username");
System.out.println("username = " + name); //writes the name
//look, if name is in Arraylist "namelist"). if yes, than write the matching date from "timelist" into the database.
if (namelist.contains(name)){
System.out.println("name found: "+ name);
int listIndizi = namelist.indexOf(name); //get index
Long indiziDatum = (long) timelist.get(listIndizi); //get date from same Index
System.out.println(indiziDatum); // print date so i can see it is correct (which it is)
statement.executeUpdate("UPDATE users SET follows_date ="+ indiziDatum +" WHERE username = '"+name+"'"); //updates the follows_date column
}
}
Everything works fine, except that now, the while loop doesn't continues after the first passage, but ends.
The resultSet of a statement is closed and will not return further results if you execute another statement. Create a new separate statement object for the update and everything should work as excepted.
Statement statement1 = connection.createStatement();
Statement statement2 = connection.createStatement();
ResultSet resultSet1 = statement1.executeQuery("SELECT username FROM users");
while(resultSet1.next()){
...
statement2.executeUpdate("UPDATE users ..."));
}
As to Why it happens:
Here is the explanation from the official documentation:
A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results.
Alternative Approach:
From your sample, it seems you are trying to update the "same" row in your resultSet, you should consider using an Updatable ResultSet.
Sample code from the official documentation:
public void modifyPrices(float percentage) throws SQLException {
Statement stmt = null;
try {
stmt = con.createStatement();
stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet uprs = stmt.executeQuery(
"SELECT * FROM " + dbName + ".COFFEES");
while (uprs.next()) {
float f = uprs.getFloat("PRICE");
uprs.updateFloat( "PRICE", f * percentage);
uprs.updateRow();
}
} catch (SQLException e ) {
JDBCTutorialUtilities.printSQLException(e);
} finally {
if (stmt != null) { stmt.close(); }
}
}

Java jdbc preparedstatements how can I check for empty row

I am implementing a forgot_password type feature on my application and I can not find how to check if I have any rows returned. The user first enters his/her email and then I search the database if the email is found proceed otherwise stop and tell them their email has not been found; This is my code
Connection dbConnection=null;
dbConnection= DB.getConnection();
PreparedStatement preparedStatement= dbConnection.prepareStatement("Select email,password from profiles where email=?");
preparedStatement.setString(1, User_Email);
preparedStatement.executeQuery();
// This code is not working below empty null rows still say email found
if(preparedStatement==null)
{
return ok("Email not found");
}
else
{
return ok("Email Found");
}
The User_Email string works correctly and I have verified but it seems that
preparedStatement==null does nothing
Nah, you're going about it the wrong way. executeQuery() returns a ResultSet. You just need to check if ResultSet has rows.
ResultSet rs = preparedStatement.executeQuery();
if (rs.next()) {
//example
String email = rs.getString(1);
String pw = rs.getString(2);
}
else{
//no results!!
}

Retrieve Data from a SQL Query (SELECT FROM WHERE) in java

Well I was wondering if there is any other way to get data from a SQL Query.
What I mean is that the "main" code that I always find is
Connection con = (connect to db)
PreparedStatement st = con.prepareStatement(....);
ResultSet rs = ps.executeQuery();
while (rs.next())
{
//do something
}
But if I want to retrieve specific data for example lets assume that my query is
Connection con = L2DatabaseFactory.getInstance().getConnection();
PreparedStatement ps = con.prepareStatement("SELECT login,email FROM accounts WHERE login=?");
ps.setString(1, account);
ResultSet rs = ps.executeQuery();
while (rs.next())
{
if (rs.getString("login").equals(account))
{
email = rs.getString("email");
break;
}
}
Is there any other way except that while loop to retrieve data?
The if condition inside the while loop is completely redundant - the where clause takes care of it and assures that any data returned from this query would have a login field that's equal to the value of account.
If you're sure there's no more than one row like this (e.g., the login column is a unique identifier in your table), you could just replace the while loop with an if:
// Check that such a logic exists
if (rs.next()) {
email = rs.getString("email");
}
// for good measures, just double check there isn't more than one
// of these logins:
if (rs.next()) {
throw new Exception ("This cannot be!"); // Or something more sensible
}

Categories