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();
}
Related
I'm currently working on a college project, and I'm creating a very simple e-commerce style website.
I'm using JDBC driver manager and connection pool for the connection to the db, while using Tomcat 9.0 as the container.
The problem is: when I modify some product through the website (let's say the amount available for example), the website doesn't always reflect the changes, while I can always see the data correctly in MySql Workbench.
It actually works one time out of two on the same query:
I run the query for the first time after the changes -> it shows the old value
I run the query for the second time after the changes -> it shows the new value
I run the query for the third time after the changes -> it shows the old value
And so on.
I've already tried to set caching off (from the query, using the SQL_NO_CACHE), but it didn't seem to solve the problem, I've tried to use Datasource instead, but it causes other problems that most likely I won't have the time to solve.
This is the connection pool file, which I think might be problem, I'm not that sure tho:
public class DriverManagerConnectionPool {
private static List<Connection> freeDbConnections;
static {
freeDbConnections = new LinkedList<Connection>();
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
System.out.println("DB driver not found:"+ e.getMessage());
}
}
private static synchronized Connection createDBConnection() throws SQLException {
Connection newConnection = null;
String ip = "localhost";
String port = "3306";
String db = "storage";
String username = "root";
String password = "1234";
newConnection = DriverManager.getConnection("jdbc:mysql://"+ ip+":"+ port+"/"+db+"?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC", username, password);
newConnection.setAutoCommit(false);
return newConnection;
}
public static synchronized Connection getConnection() throws SQLException {
Connection connection;
if (!freeDbConnections.isEmpty()) {
connection = (Connection) freeDbConnections.get(0);
freeDbConnections.remove(0);
try {
if (connection.isClosed())
connection = getConnection();
} catch (SQLException e) {
connection.close();
connection = getConnection();
}
} else {
connection = createDBConnection();
}
return connection;
}
public static synchronized void releaseConnection(Connection connection) throws SQLException {
if(connection != null) freeDbConnections.add(connection);
}
}
I really hope you can help me, I haven't found any solution online!
I guess it is because of auto-commit is disabled. Please try using #Transactional or set auto-commit to true. You can also try to use db.commit after each statement.
As per your connection pool implementation, all connection in your pool seems to be auto committed false.
Please check you have properly committed the connection after executing the query or not.
So it might be the case that, when executing the query after changes with same connection it reflects those changes, done earlier and on other connections, old values are might get returned.
I tried to find the connection pool which allows to get connection by jdbc url but failed. Hikari connection pool doesn't allow do it, the same situation in c3po.
My use case is:
ConnectionPool.getConnection(jdbcUrl);
Does anybody know such connection pool in java world?
A Simple Guide to Connection Pooling in Java
Author - Baeldung
About Author
A Simple Implementation
To better understand the underlying logic of connection pooling, let's
create a simple implementation.
Let's start out with a loosely-coupled design, based on just one
single interface:
public interface ConnectionPool {
Connection getConnection();
boolean releaseConnection(Connection connection);
String getUrl();
String getUser();
String getPassword();
}
The ConnectionPool interface defines the public API of a basic
connection pool.
Now, let's create an implementation, which provides some basic
functionality, including getting and releasing a pooled connection:
public class BasicConnectionPool
implements ConnectionPool {
private String url;
private String user;
private String password;
private List<Connection> connectionPool;
private List<Connection> usedConnections = new ArrayList<>();
private static int INITIAL_POOL_SIZE = 10;
public static BasicConnectionPool create(
String url, String user,
String password) throws SQLException {
List<Connection> pool = new ArrayList<>(INITIAL_POOL_SIZE);
for (int i = 0; i < INITIAL_POOL_SIZE; i++) {
pool.add(createConnection(url, user, password));
}
return new BasicConnectionPool(url, user, password, pool);
}
// standard constructors
#Override
public Connection getConnection() {
Connection connection = connectionPool
.remove(connectionPool.size() - 1);
usedConnections.add(connection);
return connection;
}
#Override
public boolean releaseConnection(Connection connection) {
connectionPool.add(connection);
return usedConnections.remove(connection);
}
private static Connection createConnection(
String url, String user, String password)
throws SQLException {
return DriverManager.getConnection(url, user, password);
}
public int getSize() {
return connectionPool.size() + usedConnections.size();
}
// standard getters
}
Connection pooling is a well-known data access pattern, whose main
purpose is to reduce the overhead involved in performing database
connections and read/write database operations.
In a nutshell, a connection pool is, at the most basic level, a
database connection cache implementation, which can be configured to
suit specific requirements.
In this tutorial, we'll make a quick roundup of a few popular
connection pooling frameworks, and we'll learn how to implement from
scratch our own connection pool.
Why Connection Pooling?
The question is rhetorical, of course.
If we analyze the sequence of steps involved in a typical database
connection life cycle, we'll understand why:
Opening a connection to the database using the database driver Opening
a TCP socket for reading/writing data Reading / writing data over the
socket Closing the connection Closing the socket It becomes evident
that database connections are fairly expensive operations, and as
such, should be reduced to a minimum in every possible use case (in
edge cases, just avoided).
Here's where connection pooling implementations come into play.
By just simply implementing a database connection container, which
allows us to reuse a number of existing connections, we can
effectively save the cost of performing a huge number of expensive
database trips, hence boosting the overall performance of our
database-driven applications.
JDBC Connection Pooling Frameworks
From a pragmatic perspective, implementing a connection pool from the
ground up is just pointless, considering the number of
“enterprise-ready” connection pooling frameworks available out there.
From a didactic one, which is the goal of this article, it's not.
Even so, before we learn how to implement a basic connection pool,
let's first showcase a few popular connection pooling frameworks.
Apache Commons DBCP
public class DBCPDataSource {
private static BasicDataSource ds = new BasicDataSource();
static {
ds.setUrl("jdbc:h2:mem:test");
ds.setUsername("user");
ds.setPassword("password");
ds.setMinIdle(5);
ds.setMaxIdle(10);
ds.setMaxOpenPreparedStatements(100);
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
private DBCPDataSource(){ }
}
In this case, we've used a wrapper class with a static block to easily
configure DBCP's properties.
Here's how to get a pooled connection with the DBCPDataSource class:
connection con = DBCPDataSource.getConnection();
HikariCP
public class HikariCPDataSource {
private static HikariConfig config = new HikariConfig();
private static HikariDataSource ds;
static {
config.setJdbcUrl("jdbc:h2:mem:test");
config.setUsername("user");
config.setPassword("password");
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
ds = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return ds.getConnection();
}
private HikariCPDataSource(){}
}
Similarly, here's how to get a pooled connection with the
HikariCPDataSource class:
Connection con = HikariCPDataSource.getConnection();
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 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.
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.