I am trying to design a Java swing application. I want to experiment and use an MVC type of architecture whereby my UI is separated from the actual logic to access data and connect to a database. I have decided that I need to create a custom class that contains all the logic to connect to the database and then simply call methods from this class in my action event for any particular form and button. This way I can switch databases and all I need to do (if I have a large code base with many many forms) is change the JDBC connection string to connect to oracle instead of MySQL. So far I have the code to connect to a database but I am trying to figure out how I can make this a class.
try
{
Class.forName("com.mysql.jdbc.Driver");
Connection con=(Connection)DriverManager.getConnection("jdbc:mysql://localhost:3306/prototypeeop","root","triala");
Statement stmt=con.createStatement();
ResultSet rs=stmt.executeQuery(sql);
I will then return the result set from a member function of my connection class to process and display on the screen.
Just create a separate class and delegate to him a getting of connection to database:
public class ConnectionManager {
private static String url = "jdbc:mysql://localhost:3306/prototypeeop";
private static String driverName = "com.mysql.jdbc.Driver";
private static String username = "root";
private static String password = "triala";
private static Connection con;
private static String urlstring;
public static Connection getConnection() {
try {
Class.forName(driverName);
try {
con = DriverManager.getConnection(urlstring, username, password);
} catch (SQLException ex) {
// log an exception. fro example:
System.out.println("Failed to create the database connection.");
}
} catch (ClassNotFoundException ex) {
// log an exception. for example:
System.out.println("Driver not found.");
}
return con;
}
}
Then get the connection in a code as follows:
private Connection con = null;
private Statement stmt = null;
private ResultSet rs = null;
con = ConnectionManager.getConnection();
stmt = con.createStatement();
rs = stmt.executeQuery(sql);
You can try MySQL JDBC Utilities API for MySQL connectivity.
This API offers very cool features and also fulfill your requirement!
Two ways you can make it
Override determineCurrentLookupKey() method of Spring's AbstractRoutingDataSource class.
You can create a class which will return Connection based on system.
You can either use fancier stuff like Hibernate or if your database usage is simple then you can try Commons DbUtils
Ceremonial connection code
String db = "jdbc:h2:mem:;INIT=runscript from 'classpath:/prototypeeop.sql'";
//for H2 in-memory database:
Connection DriverManager.getConnection(db);
Remember the core classes and interfaces in Commons DbUtils are QueryRunner and ResultSetHandler.
Related
I'm creating a JavaFX application, I've connected to the database fine. However when i look to get data from the tables i get the error
org.h2.jdbc.JdbcSQLException: Table "LECTURE" not found; SQL
statement: SELECT NAME FROM Lecture [42102-192]
and I'm 100% sure i'm connected to the database and the table is definitely there, any suggestions on why this is?
hear is my connection code and the code i am running just so you can see
public class ConnectionFactory {
//static reference to itself
private static ConnectionFactory instance = new ConnectionFactory();
public static final String URL = "jdbc:h2:file:~/db\\.";
public static final String USER = "notepad";
public static final String PASSWORD = "password";
public static final String DRIVER_CLASS = "org.h2.Driver";
//private constructor
private ConnectionFactory() {
try {
Class.forName(DRIVER_CLASS);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private Connection createConnection() {
Connection connection = null;
try {
connection = DriverManager.getConnection(URL, USER, PASSWORD);
} catch (SQLException e) {
System.out.println("ERROR: Unable to Connect to Database.");
}
return connection;
}
public static Connection getConnection() {
return instance.createConnection();
}
}
And the query being run
private void onLoadYearSelect() {
try {
Connection con = ConnectionFactory.getConnection();
Statement stat = con.createStatement();
String query = "SELECT NAME FROM Lecture";
ResultSet years = stat.executeQuery(query);
while(years.next()){
yearSelect.setValue(years.getString("NAME"));
System.out.println(years.getString("NAME"));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public void initialize(){
onLoadYearSelect();
}
If it says the table doesn't exist, then it really doesn't exist.
Most likely, you are not actually connecting to the correct database. In fact, by default, if the connection string points to a non-existent database, it just creates an empty database on the fly, which would explain your error.
It's probably too late now (because there is probably a 2nd database created already somewhere), but to avoid this confusion, it's not a bad idea to include IFEXISTS=TRUE in the connection string so that it fails if the database doesn't exist, rather than creating an empty one that will mask the true problem.
public static final String URL = "jdbc:h2:file:~/db\\.;IFEXISTS=TRUE";
However, one thing you can still try to debug the problem, is to add IFEXISTS=TRUE to the connection string. Then move or rename the database you think it should be connecting to so as to make the connection string invalid. Basically, force it to fail. If the code still connects to the database successfully, then you'll know the connection string is not pointing to the location you think it is.
I know how to open data transaction with JDBC. But i think I can/must do something to increase data transaction performance. For example:
public class F_Koneksi {
private static final String JDBC_DRIVER;
private static final String DB_URL;
private static final String USER;
private static final String PASS;
static {
JDBC_DRIVER = "org.postgresql.Driver";
DB_URL = "jdbc:postgresql://localhost:5432/MyDatabase";
USER = "Username";
PASS = "Password";
}
private final Connection con;
private ResultSet rs;
private Statement stmt;
public F_Koneksi() {
Connection connect;
try {
Properties props = new Properties();
props.setProperty("user", USER);
props.setProperty("password",PASS);
props.setProperty("sslfactory", "org.postgresql.ssl.NonValidatingFactory");
props.setProperty("ssl", "true");
forName(JDBC_DRIVER);
connect = getConnection(DB_URL, props);
} catch (SQLException|ClassNotFoundException se) {
connect = null;
}
con = connect;
}
public boolean Update(String Query) {
try {
Query = Query.replaceAll("`", "\"");
System.out.println(Query);
Statement stmt = con.createStatement();
stmt.executeUpdate(Query);
return true;
} catch (SQLException ex) {
ex.printStackTrace();
return false;
}
}
And when i must close my connection or turning auto commit off?
What can I do to improve my app data transaction performance? How is the proper way to make data transaction? Or any tips to do it better?
When i must close my connection?
If you are running in a Java EE environment (i.e. on an app server) then you can get and close connections as you wish, since most Java EE environments will pool JDBC connections for you unless you explicitly disable connection pooling.
If you are running in a Java SE environment, this depends on how you are getting the connection. For this example, it looks like you are doing a bunch of static imports (which is bad practice by the way) and you are but from waht I can tell you are using DriverManager to get your connection. If this is true and you are using DriverManager, then getting connections is very expensive! Especially once you start using a remote database. You will want to try to cache your connections. Alternatively, you could use a javax.sql.ConnectionPoolDataSource and use getPooledConnection() which will have much higher performance for get/close scenarios and take care of the connection caching for you.
When should I turn auto-commit on/off?
Auto commit on or off isn't a huge deal. I always like to leave auto-commit on, since it is less error prone by leaving the commit responsibility up to the JDBC driver.
What will help out your performance a lot is if you batch your Statements.
For example:
try(Statement statement = conn.createStatement()){
statement.addBatch("update people set firstname='Alice' where id=1");
statement.addBatch("update people set firstname='Bob' where id=2");
statement.addBatch("update people set firstname='Chuck' where id=3");
statement.executeBatch();
}
i have a java application which connects to mysql database using MYSQL connector. problem is when application started, MYSQL process list shows many connections than i requested in process list (attached image).
i have two threads running which connects to database within 5 seconds and 11 seconds. but, when i refresh mysql process list, it shows server's host ports are changing rapidely than threads are running. normally its changing 3-5 ports per second. can someone please guide me any optimizing issues or any changes to test with this?
thanks
P.S.
I have created a class which connects to DB at initialization and that class's object is in a places where needs DB connectivity. and that class having all methods which using to query from DB.
EDIT
my database connectivity class code is
public class Data{
static Connection con; //create connection
static Statement stmt; //create statement
static ResultSet rs; //create result set
static HostRead hr = new HostRead();
static int db_port = 3306;
static String db_root = "127.0.0.1";
static String db_name = "chsneranew";
static String db_user = "root";
static String db_pass = "";
/**Constructer method*/
public Data(){
this(db_root,db_port,db_name,db_user,db_pass);
if(getConnection()==null){
System.out.println("error in database connection");
}
else{
con = getConnection();
}
}
protected void finalize() throws Throwable {
try {
System.out.println("desctroyed");
con.close();
} finally {
super.finalize();
}
}
public static Connection getConnection(){
try{
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn = DriverManager.getConnection("jdbc:mysql://"+db_root+":"+db_port+"/"+db_name, db_user, db_pass);
stmt = conn.createStatement();
return conn;
}
catch(ClassNotFoundException er){
JOptionPane.showMessageDialog(null,"Error found ...\nDataBase Driver error (Invalid Drivers)\nUsers Cant login to system without database\n\nContact System Administrator","Error",JOptionPane.ERROR_MESSAGE);
return null;
}
catch(Exception er){
JOptionPane.showMessageDialog(null,"Error found ...\nDataBase Access error (Invalid Authentication)\nOr\nDataBase not found. Details are not be loaded \n\nUsers Cant login to system without database\n\nContact System Administrator","Error",JOptionPane.ERROR_MESSAGE);
return null;
}
}
public String getUserName(){
try{
Statement stmt2 = getConnection().createStatement();
ResultSet rss2;
String sql = "SELECT name FROM gen";
rss2 = stmt2.executeQuery(sql);
if(rss2.next()){
return rss2.getString("name");
}
}
catch(Exception er){
er.printStackTrace();
}
return null;
}
}
i am calling getUserName()method in my threads. using
Data d = new Data();
d.getUserName();
conn.close();
You need to close the connection, the connection is not closed that is why it is still there in the list. You need to Connection conn above so that it may be visible to rest of the code.
You are calling the getConnection() method three times when you want to read the data via the getUserName() method. Two times in the constructor when your constructor of the Data class is called (one for the if(...) check, one for the con = getConnection() line) and one time when you actually want to read the data at the getConnection().createStatement() line. So you have three connections to the database, and that is just the getUserName method...
Rewrite your code that only one connection is established and this connection is reused for any further execution.
I deployed my first Java web application a couple of days ago and realized a strange thing was happening. After a period of time all the dynamic content and functionality that relied on a connection to my database (testimonial submission, admin login) stopped working. It seems like this is happening every 24 hours or so. Every morning I realize it isn't working again.
I solve the issue by going in to the Tomcat web application manager and clicking "reload" on the web app in question. Immediately the dynamic features of the website work again.
My server is running Tomcat 7 and MySQL and the web app uses the JDBC driver to establish the connection to the database. I've made no alterations to Apache or Tomcat settings.
I have other web apps written in PHP that work persistently without fault it just seems to be this Java web app that has this problem.
What would cause this to happen and how can I make it so the web app doesn't need to be reloaded before it can establish a database connection again?
EDIT: attached some code for database connection
Database connection
public class DBConnection {
private static Connection conn;
private static final Configuration conf = new Configuration();
private static final String dbDriver = conf.getDbDriver();
private static final String dbHostName = conf.getDbHostname();
private static final String dbDatabaseName = conf.getDbDatabaseName();
private static final String dbUsername = conf.getDbUsername();
private static final String dbPassword = conf.getDbPassword();
public Connection getConnection(){
try{
Class.forName(dbDriver);
Connection conn = (Connection) DriverManager.getConnection(dbHostName + dbDatabaseName, dbUsername, dbPassword);
return conn;
} catch(Exception e){
e.printStackTrace();
}
return conn;
}
public void disconnect(){
try{
conn.close();
} catch (Exception e){}
}
}
Controller for login form:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String form = request.getParameter("form");
// check login details
if(form.equals("loginForm")){
String username = request.getParameter("username").trim();
String password = request.getParameter("password").trim();
password = loginService.hashPassword(password);
boolean isValidUser = loginService.checkUser(username, password);
if(isValidUser){
Cookie loggedIn = new Cookie("loggedIn", "true");
loggedIn.setMaxAge(60*60*24);
response.addCookie(loggedIn);
out.print("success");
}else{
out.print("nope");
}
}
}
Login service checks login details are correct:
public boolean checkUser(String username, String password){
boolean isValid = false;
try{
sql = "SELECT username, password FROM morleys_user WHERE username=? AND password=? AND isActive=1 LIMIT 1";
prep = conn.prepareStatement(sql);
prep.setString(1, username);
prep.setString(2, password);
rs = prep.executeQuery();
if(rs.next()){
return true;
}
}catch(Exception e){
e.printStackTrace();
}finally{
connection.disconnect();
}
return isValid;
}
UPDATE
If I understand correctly I should not be handling a direct connection to a database and instead be using a service that will manage connections for me.
This is my example of establishing a DataSource connection to a MysQL database.
Establish a new DataSource instance of this class:
package uk.co.morleys;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
public class DataSourceFactory {
public static DataSource getMySQLDataSource() {
Properties props = new Properties();
FileInputStream fis = null;
MysqlDataSource mysqlDS = null;
try {
fis = new FileInputStream("db.properties");
props.load(fis);
mysqlDS = new MysqlDataSource();
mysqlDS.setURL(props.getProperty("MYSQL_DB_URL"));
mysqlDS.setUser(props.getProperty("MYSQL_DB_USERNAME"));
mysqlDS.setPassword(props.getProperty("MYSQL_DB_PASSWORD"));
} catch (IOException e) {
e.printStackTrace();
}
return mysqlDS;
}
}
Instantiating a new DataSource for checking user login details
public boolean checkUser(String username, String password){
boolean isValid = false;
DataSource ds = DataSourceFactory.getMySQLDataSource();
Connection con = null;
ResultSet rs = null;
PreparedStatement ps = null;
try{
con = ds.getConnection();
sql = "SELECT username, password FROM morleys_user WHERE username=? AND password=? AND isActive=1 LIMIT ";
ps = con.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
rs = ps.executeQuery();
if(rs.next()){
return true;
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try {
if(rs != null) rs.close();
if(ps != null) ps.close();
if(con != null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return isValid;
}
Given that you've never heard of a connection pool before I'm assuming that you not are not very effectively managing database resources.
The most basic way to access the database is to obtain a connection, execute some statements & close the connection.
In the code you provided I don't see you obtaining or closing a connection, so I assume that you create a single connection when you start your application and keep the connection open "forever". After a certain amount of time your MySql server decides to kill the connection as it's been open for too long.
When you create and close a connection each time you need one, you normally won't encounter any connection timeouts, but you might experience a lot overhead from creating a connection each time your application needs one.
This is where a connection pool comes in; a connection pool manages a number of database connections and your application borrows one each time it needs one. By properly configuring your connection pool the pool will normally transparently take care of broken connections (you might for example configure the pool to renew a connection once it's x minutes/hours old).
You also need to pay attention to resource management; e.g. close a statement as soon as you no longer need it.
The following code demonstrates how your "check user" method can be improved:
public boolean checkUser(String username, String password) throws SQLException {
//acquire a java.sql.DataSource; the DataSource is typically a connection pool that's set-up in the application of obtained via jndi
DataSource dataSource = acquireDataSource();
//java 7 try-with-resources statement is used to make sure that resources are properly closed
//obtain a connection from the pool. Upon closing the connection we return it to the pool
try (Connection connection = dataSource.getConnection()) {
//release resources associated with the PreparedStatement as soon as we no longer need it.
try(PreparedStatement ps = connection.prepareStatement("SELECT username, password FROM morleys_user WHERE username=? AND password=? AND isActive=1 LIMIT 1");){
ps.setString(1, username);
ps.setString(2, password);
ResultSet resultSet = ps.executeQuery();
return resultSet.next();
}
}
}
Common connections pools are Apache Commons-DBCP and C3P0.
As managing sql resources can be quite repetitive and cumbersome you might want to consider using a template: for example Spring's JdbcTemplate
Example C3p0 configuration:
public ComboPooledDataSource dataSource(String driver, String url, String username,String password) throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
dataSource.setAcquireIncrement(1);
dataSource.setMaxPoolSize(100);
dataSource.setMinPoolSize(1);
dataSource.setInitialPoolSize(1);
dataSource.setMaxIdleTime(300);
dataSource.setMaxConnectionAge(36000);
dataSource.setAcquireRetryAttempts(5);
dataSource.setAcquireRetryDelay(2000);
dataSource.setBreakAfterAcquireFailure(false);
dataSource.setCheckoutTimeout(30000);
dataSource.setPreferredTestQuery("SELECT 1");
dataSource.setIdleConnectionTestPeriod(60);
return dataSource;
}//in order to do a "clean" shutdown you should call datasource.close() when shutting down your web app.
MySQL times out the connection after some period of time. The standard way to deal with this is to use a properly configured connection pool (with a configured DataSource) instead of using DriverManager directly.
The connection pool will check for and discard "stale" connections.
Currently, I load the below custom driver (TestDriver.java), get a connection, create a Statement, execute a query, gets the results and close the connection. I open and close a connection for each query. Is this common practice or is there an standard way to share the open connections?
public static void main(String[] args) {
Class.forName("com.sql.TestDriver");
java.sql.Connection conn = DriverManager.getConnection("jdbc:test://8888/connectme", props);
Statement stmt = conn.createStatement;
ResultSet rs = stmt.executeQuery("select * from table");
//loop through rs and pull out needed data
conn.close();
}
public class TestDriver implements java.sql.Driver{
private final TestSchema schema;
private Properties props = null;
static {
try {
DriverManager.registerDriver(new TestDriver());
} catch (SQLException e) {
e.printStackTrace();
}
protected TestDriver() throws SQLException {
schema = TestSchemaFactory.getInstance().getDbSchemaFromFile(SCHEMA_FILE);
//loads in and parses a file containing tables, columns used for business logic
}
public Connection connect(String url, Properties info)
throws SQLException {
TestSqlConnection conn=null;
//connect logic here
return conn; //will return an instance of TestSqlConnection
}
#Override
public boolean jdbcCompliant() {
return false;
}
}
Yes, it's more common to use a database connection pool. This will allow connections to be reused without the overhead or closing/re-opening. Here's a link to DBCP which is one implementation of a database connection pool: http://commons.apache.org/dbcp/
Ideally you should write a separate factory class (can be static)
say ConnectionFactory which returns a connection object.
Also I see that you are not using try/catch/finally block while creating
connection.I strongly suggest to close the connection in finally
clause otherwise you program may suffer from connection leak if any
exception is raised and causes abrupt behavior.
Ideally you should close the connection after your operation is complete in finally
clause.In web based application if you are using connections pool
then closing connection will return the connection back to pool and
will be available for use.