I'm trying to implement the following code in Java EE 8 (Java 11) to access a datasource in Wildfly 20. The objective is to close implicitly the JNDI context and the SQL connection:
try (InitialContext context = new InitialContext();
Connection conn = ((DataSource) context.lookup(pool)).getConnection()) {
// use the connection
}
catch (NamingException e) {
logger.error(e.getMessage());
}
catch (SQLException e) {
logger.error(e.getMessage());
}
Problem is that context is not closeable, as I get the compilation error:
The resource type InitialContext does not implement java.lang.AutoCloseable
I'm trying to avoid adding finally to close the context, is there a way to achieve this?
Try-with-resources works only with objects that are AutoCloseable. One way to do this without using finally is by wrapping the InitialContext in a wrapper that implements AutoCloseable that performs the necessary action in its close() method. Something like this:
public class AutoCloseableWrapper implements AutoCloseable {
private final InitialContext context;
public AutoCloseableWrapper(InitialContext context) {
this.context = context;
}
public InitialContext getContext() {
return this.context;
}
#Override
public void close() throws Exception {
this.context.close();
}
}
Use it like this:
try (AutoCloseableWrapper wrapper = new AutoCloseableWrapper(new InitialContext());
Connection conn = ((DataSource) wrapper.getContext().lookup(pool)).getConnection()) {
// ...
}
Related
I created a JDBC connection pool (jdbc/WILLIAMSON) in Glassfish server using JNDI in Netbeans, I want to use this in all servlets so instead of writing the following code in every servlet
InitialContext context = new InitialContext();
//The JDBC Data source that we just created
DataSource datasource = (DataSource)
context.lookup("jdbc/WILLIAMSON");
Connection connection = null;
connection = ds.getConnection();
I created a class DBCONN and tried to call an object of this class in every servlet but getting error "variable context might not have been initialized". See my code is below:
public final class DBCONN {
private static final InitialContext context;
private static final DataSource datasource;
static{
try {
context = new InitialContext();
datasource=(DataSource) context.lookup("jdbc/WILLIAMSON");
} catch (NamingException ex) {
Logger.getLogger(DBCONN.class.getName()).log(Level.SEVERE,
null, ex);
}
}
private DBCONN() {
// I am confused how to use this method, pls guide me
}// ERROR HERE VARIABLE context MIGHT NOT HAVE BEEN INITIALIZED
public static Connection getConnection() throws SQLException {
return datasource.getConnection();
}
}
I'm calling the datasource.getConnection() in servlet HOME.java
DBCONN datasource = new DBCONN();
Connection connection = null;
connection = datasource.getConnection();// I am accessing a static
method so warning coming accessing static method getConnection(), how
to avoid it???
Change the line to private static InitialContext context = null;. The compiler is warning you that under certain circumstances, context might not be created.
static{
context = new InitialContext();
try {
datasource=(DataSource) context.lookup("jdbc/WILLIAMSON");
} catch (NamingException ex) {
Logger.getLogger(DBCONN.class.getName()).log(Level.SEVERE, null, ex); }
I have a 3-layer application with a client-container, EJB-container (business-layer and data-access-layer). I want to make transactions in my client by using BMT. My EJBs on the EJB-container are all working with CMT.
But I am not sure if that actually works, since the client is not working in an EJB-container. The client injects the EJBs of the EJB-container with lookups on a Context object, which seem to work fine. I declared my client-side class as:
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
Is this correct? I guess the client side class which is used by my GUI has to be a singleton.
I have these objects:
private Context jndiCntx;
private UserTransaction tx;
#PostConstruct
public void initialize() throws Exception {
jndiCntx = new InitialContext();
tx = (UserTransaction) jndiCntx.lookup("java:comp/UserTransaction");
tx.begin();
}
And this PostConstruct initializes the transaction.
Here is where I get a NullPointerException (in commitOrder()):
#Override
public void commitOrder() throws ApplicationException {
try {
tx.commit();
} catch (Exception e) {
e.printStackTrace();
throw new ApplicationException("", "commitOrder() failed!");
}
}
#Override
public void cancelOrder() throws ApplicationException {
try {
tx.rollback();
} catch (Exception e) {
throw new ApplicationException("", "cancelorder() failed!");
}
}
So it seems like that I don't get a UserTransaction object. I am slightly confused by the different ways of using contexts and transactions. What am I doing wrong? And by the way: What is the difference between using a Transaction with a TransactionManager and using a UserTransaction?
How to get same connection from a DataSource in multiple classes? Is it possible?
Suppose I have a DataSource which I pass to 2 classes. The DataSource is using a Connection Pooling.
Then I call a method in 1st Class which get a Connection from the DataSource, uses that Connection and then closes that Connection.
Then I call a method in 2nd Class which get a Connection from the DataSource, uses that Connection and then closes that Connection.
Is it possible to be sure that the method in 2nd Class will get the same Connection which was used by method in 1st Class?
This is the example code:
This is the 1st class whose method will be called by the unit of work:
public class Class1 {
private DataSource dataSource = null;
public Class1(DataSource dataSource) {
this.dataSource = dataSource;
}
public void class1Method1() throws Exception {
Connection conn = null;
try {
conn = dataSource.getConnection();
... // do your work
} finally {
try {
if (conn != null)
conn.close();
} catch (Exception e) {
} finally {
conn = null;
}
}
}
}
This is the 2nd class whose method will be called by the unit of work:
public class Class2 {
private DataSource dataSource = null;
public Class2(DataSource dataSource) {
this.dataSource = dataSource;
}
public void class2Method1() throws Exception {
Connection conn = null;
try {
conn = dataSource.getConnection();
... // do your work
} finally {
try {
if (conn != null)
conn.close();
} catch (Exception e) {
} finally {
conn = null;
}
}
}
}
And this is my unit of work:
InitialContext initialContext = null;
DataSource dataSource = null;
Class1 class1 = null;
Class2 class2 = null;
initialContext = new InitialContext();
dataSource = (DataSource) initialContext.lookup("java:comp/env/jdbc/MyDB");
class1 = new Class1(dataSource);
class2 = new Class2(dataSource);
class1.class1Method1();
class2.class2Method1();
Closing a connection releases the connection resources, see here and connections should always be closed. Depending on the DataSource implementation (e.g. connection pool) it could then for instance give that same connection back on the next getConnection call. But it does not have to do so, it can also terminate the first connection and return a new one each time.
For more info, see here and here.
As #EJP said in a comment, You would need to pass the Connection around into the other class before you close it. You'd also need to make sure the second class doesn't close it if you plan to use it later in the outer class. This is a low level solution and quite a headache.
You can use Spring or Java EE to solve this problem at a higher level. It lets you mark all your relevant methods to say, "these should be transactional". If you call one for the first time, a new transaction is started. When you leave that outer method, the transaction automatically ends. But, if that method calls another transactional method, it knows the transaction is still open so it reuses it. It removes a lot of headache.
I believe these two technologies use Aspect Oriented Programming under the hood.
Read more for JEE: http://docs.oracle.com/javaee/6/tutorial/doc/bncih.html
Read more for Spring: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html
I have many threads accessing MYSQL database, at first I didn't use connection pool so I had this error "You can't operate on a closed ResultSet"
I searched on Google and found out that I should used connection pool so I tried c3p0 API for implementation, but I still have the same problem and nothing changed.
so should I Synchronize getAllcountries method or there's another better solution.
public class DataSource {
private static DataSource datasource;
private ComboPooledDataSource cpds ;
private DataSource() throws IOException, SQLException, PropertyVetoException {
cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver"); //loads the jdbc driver
cpds.setJdbcUrl("jdbc:mysql://localhost/question_game");
cpds.setUser("root");
cpds.setPassword("");
cpds.setMaxPoolSize(500);
}
public static DataSource getInstance() throws IOException, SQLException, PropertyVetoException {
if (datasource == null) {
datasource = new DataSource();
return datasource;
} else {
return datasource;
}
}
public Connection getConnection() throws SQLException {
return this.cpds.getConnection();
}
public List<Country> getAllCountries() {
String query = "SELECT * FROM country order by name ";
List<Country> list = new ArrayList<Country>();
Country country = null;
ResultSet rs = null;
try {
try {
connection = DataSource.getInstance().getConnection();
} catch (IOException e) {
e.printStackTrace();
} catch (PropertyVetoException e) {
e.printStackTrace();
}
statement = connection.createStatement();
rs = statement.executeQuery(query);
while (rs.next()) {
//getting countries
}
} catch (SQLException ex) {
ex.printStackTrace();
} finally {
//DbUtil used to check if null
DbUtil.close(rs);
DbUtil.close(statement);
DbUtil.close(connection);
}
return list;
}
In addition to #stephen-c 's observation,
you basically have two options: either synchronize getAllCountries method, or make the database connection local to that method instead of having it as a class member.
As you have it now, 'connection' is a class member (available to all invocations of getAllCountries(), on all threads), so the connection is probably being overwritten by a second thread. Move it to a variable in the method, and then each invocation of the method will have its own connection.
I see a method called getConnection, I don't see where you are calling it. Instead, I see your getAllCountries method using a static DataSource object that is created like this:
new DataSource();
I searched on Google and found out that I should used connection pool so I tried c3p0 API for implementation, but I still have the same problem and nothing change
Yea ...
It looks like you just cut-and-pasted the code you found into your application without really thinking about it. Obviously ... you need to understand what the code is doing AND figure out how to use it in your application.
I am using JDBC connection pooling in Tomcat. To retrieve connections I have defined a connection factory as below:
public class ConnectionManager {
// reference to the ConnectionManager
private static ConnectionManager instance = null;
// Connection to MySQL database
private Connection connect = null;
private static DataSource ds = null;
// Logger
public static final Logger logger = Logger
.getLogger(ConnectionManager.class);
static {
try {
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/ConnectionManager");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Private Constructor .. since its a singleton
*
*/
private ConnectionManager() {
}
public static ConnectionManager getInstance() {
if (instance == null) {
instance = new ConnectionManager();
}
return instance;
}
public Connection getDbConnection() {
Connection conn = null;
try {
synchronized (DataSource.class) {
conn = ds.getConnection();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
public void closeDbConnection() throws SQLException {
conn.close();
}
}
Now I see that my code always gets stuck at conn = ds.getConnection(); line. Please let me know what I am doing wrong. From my DAO methods I am using the following to get connection: conn = ds.getConnection();
Clearly its a multi-threading issue. What should I do?
Most of your class seems geared around retrieving the JNDI datasource and using it to create connections. Not necessarily a bad idea but in this case you have introduced some bugs into your program with the additional complexity.
First off, your singleton is not a singleton. Your are not synchronizing the getInstance method so its possible to multiple threads to invoke this method at the same time. The best method in Java (unfortunately) for implementing singletons is via an enum:
public enum ConnectionManager {
INSTANCE;
}
Your second significant issue is that you are synchronizing on a class that you don't explicitly control. There is nothing preventing third party JARs or even other classes in your own application from synchronizing on the DataSource class, making it a rife target for deadlocking issues. I would take out all the superfluous methods from the class and remove the synchronize block:
public enum ConnectionManager {
INSTANCE;
private DataSource ds = null;
ConnectionManager() {
try {
final Context initCtx = new InitialContext();
final Context envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/ConnectionManager");
} catch (NamingException e) {
e.printStackTrace();
}
}
public Connection getConnection() throws SQLException {
if(ds == null) return null;
return ds.getConnection();
}
}
Now, most datasource implementations are thread safe in my experience, so the above code should work most of the time. But, we shouldn't rely on implementations we cannot control, so lets add a safe synchronization to the code, like so:
public enum ConnectionManager {
INSTANCE;
private DataSource ds = null;
private Lock connectionLock = new ReentrantLock();
ConnectionManager() {
try {
final Context initCtx = new InitialContext();
final Context envCtx = (Context) initCtx.lookup("java:comp/env");
ds = (DataSource) envCtx.lookup("jdbc/ConnectionManager");
} catch (NamingException e) {
e.printStackTrace();
}
}
public Connection getConnection() throws SQLException {
if(ds == null) return null;
Connection conn = null;
connectionLock.lock();
try {
conn = ds.getConnection();
} finally {
connectionLock.unlock();
}
return conn;
}
}
You don't have to add wrapper methods to close the connection, that is the responsibility of the calling code. Good luck.
#arya, seems like you are having the problem of connection leak, and because of that the pool is getting exhausted and the code just waits till it gets a new connection, To analyze the problem , use any of the database monitoring tools, or manually try to trace the leak (The point in code where you have consumed a connnection but forgot to return it to the pool after use).
Well I would say first try out your dataSource is working or not with a test source.
I suggest look at Apache Tomcat JNDI Data Resource How To, for Apache Tomcat 6.0 and for Apache Tomcat 7.0.
Look at the instructions carefully and analyse what's going wrong in your code, then update your question with specific problem.
That code is virtually guaranteed to cause connection leaks in a multithreaded system. closeDbConnection() closes only the last connection borrowed from pool - so if 10 threads have called getDbConnection(), and after that closeDbConnection(), only 1 connection is closed and 9 still alive. Repeat that several times and pool is exhausted (unless connection is cleaned up in finalize(), but that's probably not the case). I would get rid of the whole class, or reworked it to act only as a datasource locator.