Here is my code:
public void actionPerformed(ActionEvent e)
{
JButton source = (JButton)e.getSource();
if(source == buttonShop)
{
try
{
Connection myConn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?autoReconnect=true&useSSL=false", "xxx", "xxx");
Statement myStmt = myConn.createStatement();
ResultSet myRs1 = myStmt.executeQuery("select * from shop");
while(myRs1.next())
{
shop += myRs1.getString("ID_SHOP")+" "+myRs1.getString("NAME")+" "+myRs1.getString("ADRESS")+" "+myRs1.getString("PHONE")+"\n";
}
}catch(Exception exc){
exc.printStackTrace();
};
notifyObserver1();
shop = "";
}
else if(source == buttonEmployee)
{
try
{
Connection myConn = DriverManager.getConnection("jdbc:mysql://localhost:3306/database?autoReconnect=true&useSSL=false", "xxx", "xxx");
Statement myStmt = myConn.createStatement();
ResultSet myRs2 = myStmt.executeQuery("select * from employee");
while(myRs2.next())
{
employee += myRs2.getString("ID_EMPLOYEE")+" "+myRs2.getString("ID_SHOP")+" "+myRs2.getString("NAME")+" "+myRs2.getString("SURNAME")+"\n";
}
}catch(Exception exc){
exc.printStackTrace();
};
notifyObserver2();
employee = "";
}
}
This is a database app. I don't want to copy-paste every Connection myConn =... and Statement myStmt =... fragment to all button sources. How to make it 'global' to be visible out of actionPerformed method?
First You should have a Db Utility say 'DBUtil' class with at least a getConnection method.
This getConnection should create a connection or return it from pool depending upon your implementation.
DBUtil Class:
static Connection getConnection()
After that create two helper methods to handle both of the scenarios, something like:
getEmployeeDetails(){}
getShopDetails(){}
Inside these methods you should ideally use:
try(Connection conn = DBUtil.getConnection();
PreparedStatement st = conn.prepareStatement("Your Qry");
ResultSet rs = st.executeQuery()){
// Do Something
}
Some good points:
Use PreparedStatements
Use Try with Resource to prevent resource leaks or handle it manually
As a good practice, create, initialize and close the resource within a single method. You should not pass the resources to other methods for processing, this type of design can lead to major leak issues.
You can also make one generalized method, pass the query string to that, do some conditional processing and then return the final result to caller. This generalized method will handle db communication.
Related
I am currently making a programme that communicates with an SQL database, after I make a query I obviously have to close the connections, I can close the connection fine, but I cannot close the actual statement itself. Is this necessary to close or does it close because it is a function of the connection itself? The code works perfectly fine I was just curious if this statement was needed. Here is the code, there error is highlighted towards the end of the returnEmployeeSalary function:
public class GroundControlToMajorTom {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
System.out.println(returnEmployeeSalary("ivy"));
}
public static String returnEmployeeSalary(String name) throws ClassNotFoundException, SQLException {
HashMap<String, String> infoHR = connectionInfoHR();
String query = "SELECT salary FROM employees WHERE first_name = '" + name + "'";
Class.forName("com.mysql.cj.jdbc.Driver");
Connection con = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);
rs.next();
String id = rs.getString("salary");
return id;
st.close(); /////////// ERROR IS HERE /////////////
con.close();
}
public static HashMap<String, String> connectionInfoHR() {
HashMap<String, String> infoHR = new HashMap();
infoHR.put("url", "jdbc:mysql://localhost:3306/sql_hr");
infoHR.put("uname", "root");
infoHR.put("pass", "");
return infoHR;
}
}
The problem is that you have statements after the return statement. Given return ends the normal flow of a method, the subsequent close methods aren't executed.
However, your code doesn't take into account abrupt exits of a method through an exception. In such situation, you won't properly close resources like statements and connections.
The appropriate solution is to use try-with-resources. Your code would then look like:
try (Connection con = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
Statement st = con.createStatement();
ResultSet rs = st.executeQuery(query);) {
rs.next();
return rs.getString("salary");
}
At the end of the try-with-resources block, the result set, statement and connection will be closed, in the right order, even if closing of one of these fails.
You need to close your resultSet ,statement then your database connection to release all resources from the database.
try this :
Connection connection = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
try {
Statement statement = connection.createStatement();
try {
ResultSet resultSet = statement.executeQuery(query);
try {
rs.next();
return rs.getString("salary");
} finally {
resultSet.close();
}
} finally {
statement.close();
}
} finally {
connection.close();
}
You could follow this article for more information :
How to Close JDBC Resources Properly – Every Time
Update :
Since Java 7 you could use this :
try (Connection connection = DriverManager.getConnection(infoHR.get("url"), infoHR.get("uname"), infoHR.get("pass"));
Statement statement = connection.createStatement()) {
try (ResultSet resultSet = statement.executeQuery(query)) {
rs.next();
return rs.getString("salary");
}
}
So I'm currently working on a project that will be using a database but its my first time trying fiddling with it on java.
But I'm already seeing my first problem is how would i make one single file that handles connection while other files handles GET/ADD/UPDATE/DELETE (one for each table) what would properly be the best way on doing this ?
To not having to place connection values in each file and do the connection
I though about extending the connection class with the other classes but idk if its a great idea.
import java.sql.*;
public class DatabaseConnection {
public static void main(String[] args) {
final String url = "jdbc:postgresql://localhost:5432/Database";
final String user = "dbuser";
final String password = "dbpass";
try(Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("Connection successful!");
} catch (SQLException e) {
System.out.println("Connection failure.");
e.printStackTrace();
}
}
}
What would be the best approach?
Maybe i'm wrong, but i think you need connection pool.
Try to find instruction here https://www.baeldung.com/java-connection-pooling
You could move the database connection related code to a utility class, and use the PreparedStatement class to precompile the SQL Query
public class doSomething {
Connection conn = null;
PreparedStatement pst = null;
public static void main(String [] args){
conn = DatabaseConnection.connect()
String qry = "Select * from table_name";
pst = (PreparedStatement) conn.prepareStatement(qry);
}
}
I'll try my best to make this as clear as possible since I'm new to Java. If there are parts which are unclear to you, please let me know. I apologize beforehand if the structure of my coding is messy.
I'm making a combobox event wherein if an item is selected (or changed), it will display items of that database and if the Update button is clicked, the program will connect to the database based on the item selected in the combobox.
The problem is that the variable cn after the if-else statement, has an error of "variable may have not been initialized".
Please note that I would like to focus on the condition since it is where I'm having difficulties and that the Update part is not a concern at this time.
private void btn_UpdateActionPerformed(java.awt.event.ActionEvent evt)
{
String value2 = (String) combobox_location.getSelectedItem();
String value4 = (String) combobox_category.getSelectedItem();
try
{
if(value2.equals(value4))
{
Connection cn = db.itemconnector.getConnection();
}
String sql = "UPDATE items set location = '"+value2+"' where id = '"+value4+"' " ; //Please ignore this line for the now
PreparedStatement ps1 = cn.prepareStatement(sql);
ps1.execute();
JOptionPane.showMessageDialog(null, "Update Successful");
PreparedStatement ps2 = cn.prepareStatement(ref);
ResultSet rs = ps2.executeQuery();
DefaultTableModel tm = (DefaultTableModel)itemTable.getModel();
tm.setRowCount(0);
while(rs.next())
{
Object o[] = {rs.getInt("id"), rs.getString("location"), rs.getString("product_name"),rs.getString("product_category"),rs.getString("product_description"),rs.getInt("product_stock"), rs.getFloat("product_price"), rs.getString("product_status")};
tm.addRow(o);
}
}
catch (Exception e)
{
System.out.println("Update Error!");
}
}
I have a package db that has itemconnector class for database connection and here is my code I've written in it. I hope I have provided all necessary details for your assistance. If you need more info, please let me know. Thank you.
package db;
import java.sql.*;
public class itemconnector {
/**
*
* #return
* #throws Exception
*/
public static Connection getConnection() throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection cn = (Connection)
DriverManager.getConnection("jdbc:mysql://192.168.1.50:3306/sales","root","");
return cn;
}
public static Connection getConnection1() throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection cn = (Connection)
DriverManager.getConnection("jdbc:mysql://192.168.1.50:3306/sales1","root","");
return cn;
}
public static Connection getConnection2() throws Exception
{
Class.forName("com.mysql.jdbc.Driver");
Connection cn = (Connection)
DriverManager.getConnection("jdbc:mysql://192.168.1.50:3306/sales2","root","");
return cn;
}
}
Well, I'm trying to use SQLite in my Libgdx game, but don't know how.
public class Main {
public static void main(String[] args){
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.title = Game.TITLE;
config.width = Game.V_WIDTH * Game.SCALE;
config.height = Game.V_HEIGHT * Game.SCALE;
new LwjglApplication(new Game(), config);
}}
What I need to do in my main? lol
I've been looking for this but, all I can find is related to Android application.
I already have the driver in my ref libraries, and connection class..
What I usually do when using a database with an application, is make a ConnectionFactory, that returns a new connection to the database.
public class ConnectionFactory {
public static Connection getConnection() {
Connection con = null;
Class.forName("org.sqlite.JDBC");
con = DriverManager.getConnection("jdbc:sqlite:test.db"); //change to whatever db you want
return con;
}
}
now we have a ConnectionFactory that can pump out connections to our database. Now when we want to interact with the database, you can get the connection appropriately. inside your main, it might look something like this:
public static void main(String[] args) {
Connection con = null;
String firstName = null, lastName = null;
try {
con = ConnectionFactory.getConnection();
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM myTable where myId = ?");
pstmt.setInt(1, /*some id here, ill put this as example:*/ 1234567);
//execute the query and put into result set so we can get the values.
ResultSet rs = pstmt.executeQuery();
//the resultset iterates through rows, by calling next
if( rs.next() ) //could be while(rs.next()) if expecting multiple rows
{
firstName = rs.getString("firstName"); //column name you want to grab here
lastName = rs.getString("lastName");
}
} catch(SQLException sqle) {
sqle.printStackTrace();
}
finally {
try {
con.close(); //dont forget to close your connection to database!
} catch(SQLException sqle) {
sqle.printStackTrace();
}
}
}
You will need to create tables within the SQLite database and insert records before you can do any interactions though, so keep that in mind.
I'm getting the following execption when executing sql statements
SQLServerException: The server failed to resume the transaction.
Desc:69d00000016.
I know that the following DAO implementation is not correct. I want to know what is the correct implementation for the following code and if the fact that my connFactory is declared as static can cause the above error.
private static DbConnectionFactory connFactory;
protected myDAO() {
myDAO.connFactory = DbConnectionFactoryHome.getHome().lookupFactory("facName");
}
public myReturn myAccessMethod(final int cod) throws BaseException {
Connection conn = null;
CallableStatement stmt = null;
ResultSet resSet = null;
myReturn ret= null;
try {
conn = myDAO.connFactory.getConnection();
stmt = conn.prepareCall("{call name (2)}");
stmt.setInt(1, cod);
resSet = stmt.executeQuery();
if (resSet.next()) {
ret = new myReturn(resSet.getInt("someValue"));
}
}
catch (SQLException sqle) {
throw new myException(sqle.getMessage(), (Throwable)sqle);
}
finally {
try {
if (resSet != null) {
resSet.close();
}
if (stmt != null) {
stmt.close();
}
if (conn != null) {
conn.close();
}
}
}
return ret;
}
Should I remove the static modifier from the connFactory or implement a singleton, so when the constructor is called again the factory is not recreated?
I would make your DBConnectionFactory a singleton. A good example of how to do this can be found here: Singleton DB Connectionfactory.
However, I am not sure that the your issue is with the db connection factory being static. It may actually be with the way you are extracting results with the result set. Make sure you process all your results. You should include a more complete stack trace. You may want to look into why you are getting: "The server failed to resume the transaction." There is an article about how what causes this error and how to fix it here: Failed to resume transaction
Try doing something like this:
CallableStatement stmt = connection.prepareCall("{call name (2)}");
stmt.setInt(1, cod);
stmt.execute();
ResultSet rs = (ResultSet)stmt.getObject(index);
//Loop results
while (rs.next()) {
ret = new myReturn(resSet.getInt("someValue")
}