I'm creating an Android application where I've a login system using MySql. I'm using a Thread for the login.
private static boolean isValid = false;
public static boolean login(final String username, final String password) {
new Thread(new Runnable() {
#Override
public void run() {
try{
Class.forName("com.mysql.jdbc.Driver");
Connection con= DriverManager.getConnection(
"jdbc:mysql://*****/***","*****","******");
Statement stmt=con.createStatement();
String query = "SELECT passHash FROM test WHERE username = '"+ username +"'";
ResultSet rs=stmt.executeQuery(query);
System.out.println(query + " <----");
while(rs.next()) {
isValid = BCrypt.checkpw(password, rs.getString(1));
System.out.println(isValid + "<.daspdfsafpa");
}
System.out.println(isValid +" 1");
con.close();
System.out.println(isValid +" 2");
}
catch(Exception e)
{
System.out.println(e);
}
}
}).start();
try{
Thread.currentThread().join();
}
catch(InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("blafasf");
return isValid;
}
When I'm using the Thread.currentThread.join(); the app never runs the return isValid;. So my method will never get returned when I'm using the .join() , and if I remove it the method will be returned before the thread is done. How can I fix this issue?
I want the method to run through the thread before returning the isValid in the bottom of the method.
Any ideas?
I'm still looking for a solution on this. How can I make this is another way to still make it work?
Related
I am building a basic java application to load some files into a mysql database. I am able to load the files up and populate my tables without any problems. However after speaking to someone who reviewed my code, I am apparently not correctly closing my connections and wasting resources. Where am I not closing up the connections? Have I done this incorrectly?
I am using the try-with-resources construct within my DbSinger class to execute prepared statements to my database, which should automatically close the connection so long as the AutoCloseable interface is implemented, which it is in the parent class of Db. The close() method however is never reached. The DbSinger is instantiated inside my main() and then runs it's single method populateSingers() with an ArrayList of Singer objects.
Connection Class
public class SQLConnection {
private static final String servername = "localhost";
private static final int port = 3306;
private static final String user = "ng_user";
private static final String pass = "ng";
private static final String db = "ng_music";
private static final String connectionString = "jdbc:mysql://" + servername + ":" + port + "/" + db;
public Connection provide() {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
return DriverManager.getConnection(connectionString, user, pass);
}
catch (SQLException | ClassNotFoundException e) {
throw new SQLConnectionException(e);
}
}
public class SQLConnectionException extends RuntimeException {
SQLConnectionException(Exception e) {super(e);}
}
}
Abstract parent class
public abstract class Db implements AutoCloseable{
private Connection connection;
Db() {
SQLConnection sqlC = new SQLConnection();
this.connection = sqlC.provide();
}
#Override
public synchronized void close() throws SQLException {
if(connection != null) {
connection.close();
connection = null;
System.out.println("Connection closed");
}
}
Connection getConnection() {
return connection;
}
boolean checkIfPopulated(String query){
try {
PreparedStatement ps = getConnection().prepareStatement(query);
ResultSet rs = ps.executeQuery();
return !rs.next();
} catch (SQLException e) {
e.printStackTrace();
}
return true;
}
}
Concrete class to execute queries to database for singers table
public class DbSinger extends Db {
public DbSinger() {
super();
}
public void populateSingers(ArrayList<Singer> singers) {
String populateSingersQuery = "insert into ng_singers(name, dob, sex) values(?,?,?)";
if(!checkIfPopulated("select * from ng_singers")){
System.out.println("Singer Table is already populated");
return;
}
try (PreparedStatement ps = getConnection().prepareStatement(populateSingersQuery)) {
for (Singer s : singers) {
ps.setString(1, s.getName());
ps.setDate(2, java.sql.Date.valueOf(s.getDob()));
ps.setString(3, s.getSex());
ps.addBatch();
}
ps.executeBatch();
System.out.println("Singers added to table");
} catch (SQLException e) {
e.printStackTrace();
}
}
}
My code is able to execute is able to run fine and does what it needs to, but I want to understand why and where I am not closing connections, and to understand how I can resolve this. Or at least understand if I am approaching this wrong.
In your case, you need to instantiate DBSinger class in try-with-resources statement to close the underlying connection.
Instead of doing:
DbSinger dbSinger = new DbSinger();
You need to do:
try (DbSinger dbSinger = new DbSinger()) {
// Your other code
}
This way the close() method you are overriding in your Db class will be called automatically.
Also, close the preparedStatement you created in your checkIfPopulated method by:
try (PreparedStatement ps = getConnection().prepareStatement(query)) {
// Other codes
}
Your code is old way. And you do need close manually. However, with Java 8, you can use try with resource like below,
try (Connection conn = ds.getConnection();
Statement stmt = conn.createStatement()) {
try {
stmt.execute(dropsql);
} catch (Exception ignore) {} // ignore if table not dropped
stmt.execute(createsql);
stmt.execute(insertsql);
try (ResultSet rs = stmt.executeQuery(selectsql)) {
rs.next();
} catch (Exception e2) {
e2.printStackTrace();
return("failed");
}
} catch(Exception e) {
e.printStackTrace();
return("failed");
}
I am trying to run few queries using a multithreaded approach, however I think I am doing something wrong because my program takes about five minute to run a simple select statement like
SELECT * FROM TABLE WHERE ID = 123'
My implementation is below and I am using one connection object.
In my run method
public void run() {
runQuery(conn, query);
}
runQuery method
public void runQuery(Connection conn, String queryString){
Statement statement;
try {
statement = conn.createStatement();
ResultSet rs = statement.executeQuery(queryString);
while (rs.next()) {}
} catch (SQLException e) {
e.printStackTrace();
}
}
Finally in the main method, I start the threads using the snippet below.
MyThread bmthread = new MyThread(conn, query);
ArrayList<Thread> allThreads = new ArrayList<>();
double start = System.currentTimeMillis();
int numberOfThreads = 1;
for(int i=0; i<=numberOfThreads; i++){
Thread th = new Thread(bmthread);
th.setName("Thread "+i);
System.out.println("Starting Worker "+th.getName());
th.start();
allThreads.add(th);
}
for(Thread t : allThreads){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
double end = System.currentTimeMillis();
double total = end - start;
System.out.println("Time taken to run threads "+ total);
Update : I am now using separate connection for each thread.
ArrayList<Connection> sqlConn = new ArrayList<>();
for(int i =0; i<10; i++){
sqlConn.add(_ut.initiateConnection(windowsAuthURL, driver));
}
loop:
MyThread bmthread = new MyThread(sqlConn.get(i), query);
As rohivats and Asaph said, one connection must be used by one and only one thread, that said, consider using a database connection pool. Taking into account that c3p0, DBCP and similars are almost abandoned, I would use HikariCP which is really fast and reliable.
If you want something very simple you could implement a really simple connection pool using a thread safe collection (such as LinkedList), for example:
public class CutrePool{
String connString;
String user;
String pwd;
static final int INITIAL_CAPACITY = 50;
LinkedList<Connection> pool = new LinkedList<Connection>();
public String getConnString() {
return connString;
}
public String getPwd() {
return pwd;
}
public String getUser() {
return user;
}
public CutrePool(String connString, String user, String pwd) throws SQLException {
this.connString = connString;
for (int i = 0; i < INITIAL_CAPACITY; i++) {
pool.add(DriverManager.getConnection(connString, user, pwd));
}
this.user = user;
this.pwd = pwd;
}
public synchronized Connection getConnection() throws SQLException {
if (pool.isEmpty()) {
pool.add(DriverManager.getConnection(connString, user, pwd));
}
return pool.pop();
}
public synchronized void returnConnection(Connection connection) {
pool.push(connection);
}
}
As you can see getConnection and returnConnection methods are synchronized to be thread safe. Get a connection (conn = pool.getConnection();) and don't forget to return/free a connection after being used (pool.returnConnection(conn);)
Don't use the same connection object in all threads. Give each thread a dedicated database connection.
One Connection can only execute one query at a time. You need multiple connections available to execute database operations in parallel. Try using a DataSource with a connection pool, and make each thread request a connection from the pool.
I'm making a program where you login and it takes you into a into a different frame after you log in.. That part of the program works, but I'm having trouble getting it to return the user's name and other data from the database. It connects to the database, but it won't return the information inside JTextField. If I can find out how to do firstName, I can figure out the rest. I'm using Eclipse as my IDE and SQLite Manager as the database.
There are 2 tables
Login (username,password)
Student(SID,firstName,GradeLevel, and more)
Also username is there ID start with an S (like S01 and so forth).
Here's the code.
public class student extends JFrame {
private JTextField textField;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
student frame = new student();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private void ShowInfo() {
try{
String query="SELECT firstName From Student,Login Where firstname=?";
PreparedStatement ps=conn.prepareStatement(query);
ps.setString(1, "firstName");
ResultSet rs= ps.executeQuery();
while (rs.next()) {
textField.setText(rs.getString("firstName"));
System.out.print(""+textField);
}ps.close();
conn.close();
} catch ( Exception ex)
{
JOptionPane.showMessageDialog(null,ex);
}
}
}
private void ShowInfo() {
try{
String query="SELECT firstName From Student,Login Where firstname=?";
PreparedStatement ps=conn.prepareStatement(query);
ps.setString(1, "firstName");
ResultSet rs= ps.executeQuery();
if(rs.next()) {
textField.setText(rs.getString(1));
System.out.print(""+textField); //you are getting data
}ps.close();
conn.close();
} catch ( Exception ex)
{
JOptionPane.showMessageDialog(null,ex); //you have a error
}
}
there were sevral thing which were wrong in the code. first one is there should be something wrong with sql statment Student,Login Where firstname.
you should change this line textField.setText(rs.getString(1));
and you have a while loop to extract the data but and you are planning on having a textfield to store data. that is pointless if you are expecting more than one output from your resultset you need something more than a jtextfield maybe a jtable. bt i have changed your while loop to a if loop to get one single output from the resultset.and the other thing i notice in your application is you are not calling the showInfo method.
I have created two swing.JFrames.
login GUI and user GUI. what I want is when it's switches to login gui to user gui, there is a Jlabel in user GUI which needs to be changed as ("you're logged in as" + username);
I tried this code in userjframe source code.
`loggedInAsLable.setText("you're logged in as" + username);`
in a method and it's called in main method of user jframe. but for some reasons
it doesn't work.
how can I run some methods when a Jframe is becoming visible?
public class CustomerServiceOfficerUI extends javax.swing.JFrame {
private static Statement st;
ResultSet rs;
Connection con = null;
Login loginUI = new Login(); // gets current user Id
Employee cso = new CustomerServiceOfficer(); //creates new customer service officer object
/**
* Creates new form CustomerServiceOfficer
*/
public CustomerServiceOfficerUI() {
initComponents();
}
public void getCSOdetails() {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/flyingcarsdb", "root", "");
System.out.println("database connected");
} catch (ClassNotFoundException | SQLException ex) {
System.out.println("Error: " + ex);
}
try {
// Retrieve customer service officer details
st = con.createStatement();
String query = "select * FROM customerserviceofficer WHERE Id = '" + loginUI.getCurrentUserId() + "'";
rs = st.executeQuery(query);
while (rs.next()) {
//Assign the details with setters
cso.setFname(rs.getString("Fname"));
cso.setEmail(rs.getString("Email"));
}
} catch (Exception ex) {
System.out.println("Error : " + ex);
}
loggedInAsLable.setText("you're logged in as : " + cso.getId());
//this is where LABLE is changed, 'cso.getId()' returns the user ID
}
If you really need to update your JFrame when it becomes visible (as your last statement suggests), you can use the the WindowListener to call your getCSODetails() method.
public CustomerServiceOfficerUI() {
initComponents();
this.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e)
{
this.getCSODetails();
}
#Override
public void windowDeiconified(WindowEvent e)
{
this.getCSODetails();
}
#Override
public void windowActivated(WindowEvent e)
{
this.getCSODetails();
}
});
}
I've included three activation events - opening, activation and deiconfication; you can remove any of them to limit the update to a specific event suiting your needs. If you need to update the label only once the window is opened, remove the methods windowDeiconified() and windowActivated().
Note, however, that the getCSODetails() method is designed quite poorly and calling it whenever the window becomes visible/focused would incur a performance penalty and the responsiveness of your GUI will be heavily influenced by performance of your database. I guess that the customer details you're displaying are not changed during a login session, so it would be more appropriate to perform the query once, cache the details and then display them from the cache.
try this:
public class CustomerServiceOfficerUI extends javax.swing.JFrame {
private static Statement st;
ResultSet rs;
Connection con = null;
Login loginUI = new Login(); // gets current user Id
Employee cso = new CustomerServiceOfficer(); //creates new customer service officer object
/**
* Creates new form CustomerServiceOfficer
*/
public CustomerServiceOfficerUI() {
initComponents();
}
public void getCSOdetails() {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("jdbc:mysql://localhost:3306/flyingcarsdb", "root", "");
System.out.println("database connected");
// Retrieve customer service officer details
st = con.createStatement();
String query = "select * FROM customerserviceofficer WHERE Id = '" + loginUI.getCurrentUserId() + "'";
rs = st.executeQuery(query);
while (rs.next()) {
//Assign the details with setters
cso.setFname(rs.getString("Fname"));
cso.setEmail(rs.getString("Email"));
}
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
loggedInAsLable.setText("you're logged in as : " + cso.getId());
loggedInAsLable.repaint();
}
});
} catch (Throwable ex) {
System.out.println("Error : " + ex);
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
loggedInAsLable.setText("There is a problem with your code : " + ex);
loggedInAsLable.repaint();
}
});
} finally {
}
//this is where LABLE is changed, 'cso.getId()' returns the user ID
}
It's me again and I just can't seem to get this code to work. I'm basically asking for any advice on why the button does nothing when clicked. Would you like me to attach the source code?
The method I'm trying to implement:
public static void UserInput() {
try {
stmt = connect.createStatement();
ResultSet res = stmt.executeQuery("SELECT * FROM " + tableName);
while (res.next()) {
if (res.getString("Username").equals(usernameField.getText())) {
if (res.getString("Password").equals(passwordField.getPassword())) {
JOptionPane.showMessageDialog(null, "Correct", "Correct",
JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(null, "Error. Incorrect "
+ "username or password.", "Error",
JOptionPane.ERROR_MESSAGE);
}
} else {
JOptionPane.showMessageDialog(null, "Error. Incorrect "
+ "username or password.", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
res.close();
stmt.close();
connect.close();
} catch (SQLException sqlExcept) {
sqlExcept.printStackTrace();
}
}
And here's how I'm calling it:
if(firstTime == false) {
JavaDB jdb = new JavaDB();
}
JavaDB window = new JavaDB("");
window.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
}
And here's the actionListner:
submit = new JButton("Submit");
c.add(submit);
submit.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent e ) {
if(e.getSource().equals(submit)) {
UserInput();
}
}
}); ;
If you need anymore let me know. I've been teaching myself Java and I don't really know what to learn so any tips will be welcomed. I'm also new to stack overflow and posting code so any thing you can give me will be more than appreciated. Thanks in advance.
Edit: I now added a class for event handling with the Thread inside of it like this;
public class ButtonHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
if(e.getSource().equals(submit)){
Thread th = new Thread(new JavaDB());
th.start();
th.run();
try {
th.wait();
} catch (InterruptedException e1) {
}
}
else{
System.exit(0);
}
}
And I changed UserInput to run(). However,now when I click the submit button,The GUI disappears. Just for a reference you might need, here's my main method:
public static void main(String args[]) throws SQLException,
InterruptedException {
createConnection();
boolean firstTime = firstTime();
if (firstTime) {
JavaDB db = new JavaDB("");
db.createAccount();
try {
connect = DriverManager
.getConnection("jdbc:derby:\\KeithDB;shutdown=true");
} catch (SQLException XJ015) {
}
}
if (firstTime == false) {
JavaDB jdb = new JavaDB();
Thread th = new Thread();
}
JavaDB window = new JavaDB("");
window.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
Anything else you need,let me know
PasswordDemo, as shown in How to Use Password Fields, would be a good starting point for your study, and it would make an effective sscce.
Addendum: Absent a complete example or knowledge of what database you are using, I got the following result,
Version: H2 1.3.157 (2011-06-25) 1.3
by running the following modification to PasswordDemo against H2 Database:
if (isPasswordCorrect(input)) {
try {
Connection conn = DriverManager.getConnection(
"jdbc:h2:mem:", "sa", "secret");
DatabaseMetaData metaData = conn.getMetaData();
System.out.println("Version:"
+ " " + metaData.getDatabaseProductName()
+ " " + metaData.getDatabaseProductVersion()
+ " " + metaData.getDatabaseMajorVersion()
+ "." + metaData.getDatabaseMinorVersion());
} catch (SQLException ex) {
ex.printStackTrace(System.err);
}
} ...
Addendum: I got the following result,
Version: Apache Derby 10.6.2.1 - (999685) 10.6
by running the following modification to PasswordDemo against Apache Derby:
if (isPasswordCorrect(input)) {
try {
EmbeddedDataSource ds = new EmbeddedDataSource();
ds.setDatabaseName("/home/trashgod/.netbeans-derby/dbtest");
Connection conn = ds.getConnection("sa", "secret");
DatabaseMetaData metaData = conn.getMetaData();
System.out.println("Version:"
+ " " + metaData.getDatabaseProductName()
+ " " + metaData.getDatabaseProductVersion()
+ " " + metaData.getDatabaseMajorVersion()
+ "." + metaData.getDatabaseMinorVersion());
} catch (SQLException ex) {
ex.printStackTrace(System.err);
}
} ...
I finally got it to work! I had another constructor with the same variable names and my call to the JTextFields were mistaken to be the call to the other constructor. The foo statements really helped!!! Thank you everyone!