I have a scenario where I have to connect to virtual center and get data. I have implemented a singleton class so that two threads cannot access the VC at the same time, as it has give concurrent access issue. My code is as follows:
public class Connector {
private static Connector instance ;
private Connector(String urlStr, String username, String password) {
connect(urlStr, username, password);
}
public static synchronized Connector getInstance(String urlStr, String username, String password) {
if (instance == null){
instance = new Connector(urlStr,username,password);
System.out.println("creating instance");
}
return instance ;
}
public void connect(String urlStr, String username, String password) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
try {
//code to connect to VC
}
} catch (RuntimeException e) {
connectException = e;
} finally {
Thread.currentThread().setContextClassLoader(cl);
}
}
public void disconnect() throws RuntimeFault, RemoteException {
//code for disconnect
}
}
}
I called this from another class in the following way:
Connector c = Connector.getInstance(dburl, dbuser, dbpass);
c.connect(dburl, dbuser, dbpass);
//code for getting data
c.disconnect();
Now if I have 2 simultaneous requests to get data from viruatal center, one of them fails saying "session is not authenticated".
Can you help we with a better way to deal with the issue.
And as the same instance is used always, how can we differentiate if its a different Virtual Center.
Your sequence
connect
do stuff
disconnect
is not atomic which means it is possible that
Thread 1 connects
Thread 2 connects
Thread 1 does stuff
Thread 1 disconnects
Thread 2 tries to do stuff and fails.
Structure your class so that clients cannot fail to connect, fail to disconnect, or interleave operations with another.
Your API could allow code that wants to use a connection to pass in an object that uses a connection while it is connected, and returns a result of using that connection:
public interface ConnectionTask<T> {
public T useConnection(Connection c);
}
and then instead of getInstance write a useConnection that does
public synchronized <T> T useConnection(ConnectTask<T> c) {
connect();
try {
return c.useConnection(this);
} finally {
disconnect();
}
}
and make connect and disconnect private so that clients cannot misuse them.
You are only retaining exclusive access to the connection in the first method.
I suggest you add a Lock like ReentrantLock which you lock in the first method and unlock when you release the connection.
Another approach is to use a visitor pattern which may be safer.
interface UsesConnector {
public void useConnector(Connector connector);
}
public class Connector {
private static final Connector connector = new Connector();
public static synchronized void useConnector(String urlStr, String username, String password, UsesConnector usesConnector) {
connector.connect(urlStr, username, password);
try {
usesConnector.useConnector(connector);
} finally {
connector.disconnect();
}
}
}
Related
I am working with Spring Boot and Dart. When I hit the URL (using POSTMEN/Browser) to insert some data in MySql I got the response correctly. But WHen I send the 3 requests consecutively from Flutter Front-end using Dart language it most of the time returned the result of 2 GET request and through the error for the 3rd request and most of the time it works for all request.
Following is the connection service that I am using on backend to store the data.
ConnectionService.java
#Service
public class ConnectionService {
private static final Logger log = LoggerFactory.getLogger(ConnectionService.class);
Connection connection = null;
#Value("${spring.datasource.url}")
String datasourceUrl = "jdbc:mysql://localhost/databaseName?autoReconnect=true&useSSL=false";
public Connection createConnection() throws SQLException {
connection = DriverManager.getConnection(datasourceUrl, "root", "root");
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
return connection;
}
public void closeConnection() {
try {
connection.close();
} catch (Exception e) {
log.error(e.toString());
}
}
}
I am creating the object of the Connection service class and call the createConnection() to create the connection and closeConnection() to close that one.
Controller.java
#RestController
#RequestMapping("/user")
public class UserController {
#Autowired
ConnectionService connectionService;
#GetMapping(path = "/test")
public void testFunction(#RequestParam(name = "abc") String abc) throws SQLException
{
Connection connection = connectionService.createConnection();
if (abc.isExist(param1,param2,connection))
{
//some code
connectionService.closeConnection();
} else
{
//some operation
connectionService.closeConnection();
}
}
Guide me to resolve this issue.
Thanks
They problem is that instead of closing the instance connection that I have created locally I am closing the main connectionService instance. This is the problem.
Now connectionService.closeConnection();
It should be connection.closeConnection();
I am learning about MySQL database and I cannot quite understand one concept. Lets say there are two methods in the same class as the one shown below. Now, do i have to use Connection connect = dbConnection.getDBConnection(); in each method or is there a different way to declare one connection and use it across multiple methods?:
private void setUpdateButton(ActionEvent event) {
try{
Connection connect = dbConnection.getDBConnection();
Statement stmt = connect.createStatement();
if(txtID.getText().trim().isEmpty()||txtFirstName.getText().trim().isEmpty() || txtSecondName.getText().trim().isEmpty() ||
txtGender.getText().trim().isEmpty() || txtAge.getText().trim().isEmpty() || txtHomeAddress.getText().trim().isEmpty() || txtPhoneNumber.getText().trim().isEmpty()) {
showAlert("Invalid Input!", "All fields need to be populated before updating.");
}else {
String sqlQuery ="update student_information set Age ='"+Integer.parseInt(txtAge.getText())+"',Name ='"+txtFirstName.getText()+"',Surename='"+txtSecondName.getText()
+"',Gender='"+txtGender.getText()+"',Address='"+txtHomeAddress.getText()+"',PhoneNumber='"+txtPhoneNumber.getText()+"'where ID="+Integer.parseInt(txtID.getText());
stmt.executeLargeUpdate(sqlQuery);
setTxtArea();
showConfAlert("Update Completed!", "Record has been updated!");
Creating connections is a costly operation, so I think you should open the connection at the application startup, and close it on exit.
If your program is not multi thread you would be fine with a simple global object, otherwise other strategies should be used.
You can create a singleton for your app with a method returning the connection.
public class App {
private static App self;
private Connection connection;
private App(){
}
public synchronized App getInstance(){
if(self == null){
self = new App();
}
return self;
}
public synchronized Connection getConnection()throws SQLException {
if(connection==null || !isValid(connection)){
// Create a new connection
}
return connection;
}
private boolean isValid(Connection conn) {
// Check if the connection is valid otherwise return false
return false;
}
public static synchronized void close(){
try{
self.connection.close();
} catch (SQLException e){
// Swallow exception
} finally {
self = null;
}
}
}
You can get the connection anywhere like this:
Connection conn = App.getInstance().getConnection();
You should make sure to close the connection on exit, maybe with a shutdown hook.
You could also, create a wrapper around your connection that forwards all connection methods to the original connection , with the exception of close that marks the connection available , this way you create something like 1 connection pool.
If the connection is available you return it otherwise you either wait or throw or do what is most appropriate for your application.
I need to use a connection pool in a standalone (as in non-web) Java application. Where I work, we are not allowed to use APIs without going through layers of security, and the job needs to be completed soon. Below is my attempt at creating this connection pool.
I have unit tested this code and tested it within the context of the overall application a hundred times and in all cases the tests passed with zero errors, and in addition the performance of each run is just under three thousand times faster than a simple connect, retrieve data, disconnect in serial approach; however, I still have nagging concerns that there could be issues with this approach that I simply haven't unearthed yet. I would appreciate any advice anyone has concerning the below code. This is my first post on this site; please let me know if I've made any errors in etiquette. I did search this site about this problem before posting. Please see below the code for an invocation example. Thanks. --JR
package mypackage;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Note: This class is only instantiated once per application run.
* Multiple instantiations, as specified in the release notes,
* are not supported.
*/
public class ConnectionManager {
// Use a blocking queue to store the database connections.
// The application will only be called once, by a single user,
// but within the application many threads will require
// a connection.
private BlockingQueue<Connection> connectionQueue = null;
// Load the connection queue with a user-defined number of connections.
// Params contains a map of all non hard-coded variables in the
// application.
public ConnectionManager(int howMany, Map<String, Object> params) {
Database database = new Database();
connectionQueue = new ArrayBlockingQueue<Connection>(howMany);
for(int i = 0; i < howMany; i++) {
connectionQueue.add(database.getConn(params));
}
}
// Return a connection from the queue, waiting up to 15 minutes to do so.
// 15 minutes is hard-coded because it is the standard time-out for all
// processes at our agency. This application must complete in less
// than fifteen minutes (is currently completing in thirty five seconds).
public Connection getConnection() {
Connection conn = null;
try {
conn = connectionQueue.poll(15, TimeUnit.MINUTES);
}
catch(InterruptedException e) {
e.printStackTrace();
}
catch(SQLException e) {
e.printStackTrace();
}
return conn;
}
// Returns a connection to the connection queue.
public void returnConnectionToManager(Connection conn) {
connectionQueue.add(conn);
}
// Called on the last line of the application program's dispatcher.
// Closes all active connections (which will only exist if there
// was a failure within one of the worker threads).
public void closeAllConnections() {
for(Connection conn : connectionQueue) {
try {
conn.close();
}
catch(SQLException e) {
e.printStackTrace();
}
}
}
}
Invocation example:
...
private ConnectionManager cm;
...
public Table(Map<String, Object> params, String method) {
...
cm = (ConnectionManager) params.get("cm");
}
// Execute a chunk of SQL code without requiring processing of a
// result set. Acquires connection from pool via cm.getConnection
// and releases connection via cm.returnConnectionToManager.
// (Database is just a helper class with simple methods for
// closing prepared statement, result sets, etc.)
private void execute(String sql) {
PreparedStatement ps = null;
Connection conn = null;
try {
conn = cm.getConnection();
ps = conn.prepareStatement(sql);
ps.execute();
}
catch (SQLException e) {
e.printStackTrace();
}
finally {
database.closePreparedStatement(ps);
cm.returnConnectionToManager(conn);
}
}
Your code looks good, but there is one serious problem, that clients of your API needs to take care of getting and releasing connection, one of them forget, and memory/resource leak is ready.
Make a one place in which you posts your queries to execute, in this place take connection, execute query and return the connection to the pool. It will secure you that the connections are returned. If you need to invoke multiple queries one after another in a single connection make the method accept an array or list of SQL queries to execute in order. The idea is to encapsulate each request to the db, so you manage all connections. It could be donethat you write an interface that has en execute(Connection conn) which you need to implement, and you could have then some Service that takes such object gives it a connection and then releases the resources back to connection pool.
Something like:
interface SqlWork {
execute(Connection conn);
}
SqlWork myWork = new SqlWork () {
execute(Connection conn) {
// do you work with the conn here
}
}
class SqlExecutionService {
ConnectionManager cm = ...;
public void execute(SqlWork sqlWork) {
Connection conn = null;
try {
conn = cm.getConnection();
sqlWork.execute(conn);
} catch (Your exceptions here) {
//serve or rethrow them
}
finally
{
if (conn!=null) {
cm.returnConnectionToManager(conn);
}
}
}
}
Example of use:
SqlExecutionService sqlExecService = ...;
sqlExecService.execute(myWork);
I've implemented an RMI interface with these current files;
MyClient.java - Clientside code
MyServer.java - Serverside code
Adder.java - Interface
AdderRemote.java - Remote _implements Adder_
DataAccess.java - Contains all the methods to interveen between server and client
I have a vps which contains all files except the Client file in the directory
vps:~/rmi#
When testing this on it's own, ie: compiling on the server, doing
rmic AdderRemote
rmiregistry 5000&
(the port I have chosen)
java -classpath .:mysql-connector... MyServer
and then locally doing the same process but running the MyClient java instead, it works. The problem I am facing is now implementing this into a project I have running in eclipse as a part of this;
I have an instance of MyClient in the main file which is then passed as parameters to the certain classes (This project implements the MVC pattern and is passed to fellow model class'), and I am now getting the error
java.rmi.NotBoundException: xox
after googling, the only response I could find was "Attempt to look up a name that is not bound.", But I'm not really sure what this means? I'll attach my code, and any help would be much appreciated.
MyClient.java
public class MyClient
{
public Adder stub;
public MyClient ()
{
try
{
stub = (Adder)Naming.lookup("rmi://92.222.2.96:5000/xox");
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
public static void connect(Adder stub) throws RemoteException
{
System.out.println(stub.connect());
}
Adder.java
public interface Adder extends Remote
{
public String connect() throws RemoteException;
}
AdderRemote.java
public class AdderRemote extends UnicastRemoteObject implements Adder
{
public AdderRemote() throws RemoteException
{
super();
da = new DataAccess();
}
DataAccess da;
public String connect() throws RemoteException
{
return da.connect();
}
DataAccess.java
public class DataAccess
{
// Connection info
static final String URL = "jdbc:mysql://92.222.2.96:3306/groupproj";
static final String DRIVER = "com.mysql.jdbc.Driver";
static final String USERNAME = "root";
static final String PASSWORD = "*****";
Connection c = null;
public String connect()
{
try
{
Class.forName(DRIVER).newInstance(); //Load DB driver
c = DriverManager.getConnection(URL, USERNAME, PASSWORD); //Establish connection to DB2
return "Connected.";
}
catch(Exception e)
{
return e.toString();
}
}
MyServer.java
public class MyServer
{
public static void main ( String args[] )
{
try
{
Adder stub = new AdderRemote();
Naming.rebind("rmi://92.222.2.96:5000/xox", stub);
}
catch ( Exception e )
{
System.out.println(e);
}
}
public static void connect(Adder stub) throws RemoteException
{
try
{
stub.connect();
}
catch(Exception e)
{
System.out.println("Could not connect to the DB.");
}
}
I gathered that because the files on the server are located in the directory "rmi" I renamed the xox to this, but this did not solve the problem, so I reverted it back to xox, which it worked before putting it into a java project.
Thank you
You must have got an exception doing the bind.
If you got a NotBoundException when looking up the same name in the same Registry you're supposed to have bound it to, you didn't bind it at all.
Notes:
You can only bind to a Registry that is running in the same host as yourself. For that reason it is convenient to always use "localhost" as the hostname when calling bind(), rebind(), or unbind().
You'd be better off letting the RemoteException and NotBoundException be thrown from the constructor of MyClient.
MyClient.connect() should not be static. In fact it cannot be static. Ergo this cannot be the real code.
From what we can see so far, your system isn't correctly designed. Your server should get a DBMS connection when it needs one, inside a remote method, on behalf of the client that is calling that method, and release it before exiting the method. Opening a new connection every time a client asks for one explicity and storing it into an instance variable of the remote object (a) will leak connections and (b) won't work when concurrent clients come to execute a query or update on the same connection.
I am trying to create a pool of channels/connections to a queue server and was trying to use ObjectPool but am having trouble using it from the example on their site.
So far I have threads that do work but I want each of them to grab a channel from the pool and then return it. I understand how to use it(borrowObject/returnObjects) but not sure how to create the intial pool.
Here's how channels are made in rabbitmq:
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
and my code just uses channel to do stuff. I'm confused because the only example I could find (on their site) starts it like this:
private ObjectPool<StringBuffer> pool;
public ReaderUtil(ObjectPool<StringBuffer> pool) {
this.pool = pool;
}
Which does not make sense to me. I realized this is common to establishing database connections so I tried to find tutorials using databases and ObjectPool but they seem to use DBCP which is specific to databases(and I can't seem to use the logic for my queue server).
Any suggestions on how to use it? Or is there a another approach used for pools in java?
They create a class that creates objects & knows what to do when they are returned. That might be something like this for you:
public class PoolConnectionFactory extends BasePoolableObjectFactory<Connection> {
private final ConnectionFactory factory;
public PoolConnectionFactory() {
factory = new ConnectionFactory();
factory.setHost("localhost");
}
// for makeObject we'll simply return a new Connection
public Connection makeObject() {
return factory.newConnection();
}
// when an object is returned to the pool,
// we'll clear it out
public void passivateObject(Connection con) {
con.I_don't_know_what_to_do();
}
// for all other methods, the no-op
// implementation in BasePoolableObjectFactory
// will suffice
}
now you create a ObjectPool<Connection> somewhere:
ObjectPool<Connection> pool = new StackObjectPool<Connection>(new PoolConnectionFactory());
then you can use pool inside your threads like
Connection c = pool.borrowObject();
c.doSomethingWithMe();
pool.returnObject(c);
The lines that don't make sense to you are a way to pass the pool object to a different class. See last line, they create the pool while creating the reader.
new ReaderUtil(new StackObjectPool<StringBuffer>(new StringBufferFactory()))
You'll need a custom implementation of PoolableObjectFactory to create, validate, and destroy the objects you want to pool. Then pass an instance of your factory to an ObjectPool's contructor and you're ready to start borrowing objects.
Here's some sample code. You can also look at the source code for commons-dbcp, which uses commons-pool.
import org.apache.commons.pool.BasePoolableObjectFactory;
import org.apache.commons.pool.ObjectPool;
import org.apache.commons.pool.PoolableObjectFactory;
import org.apache.commons.pool.impl.GenericObjectPool;
public class PoolExample {
public static class MyPooledObject {
public MyPooledObject() {
System.out.println("hello world");
}
public void sing() {
System.out.println("mary had a little lamb");
}
public void destroy() {
System.out.println("goodbye cruel world");
}
}
public static class MyPoolableObjectFactory extends BasePoolableObjectFactory<MyPooledObject> {
#Override
public MyPooledObject makeObject() throws Exception {
return new MyPooledObject();
}
#Override
public void destroyObject(MyPooledObject obj) throws Exception {
obj.destroy();
}
// PoolableObjectFactory has other methods you can override
// to valdiate, activate, and passivate objects.
}
public static void main(String[] args) throws Exception {
PoolableObjectFactory<MyPooledObject> factory = new MyPoolableObjectFactory();
ObjectPool<MyPooledObject> pool = new GenericObjectPool<MyPooledObject>(factory);
// Other ObjectPool implementations with special behaviors are available;
// see the JavaDoc for details
try {
for (int i = 0; i < 2; i++) {
MyPooledObject obj;
try {
obj = pool.borrowObject();
} catch (Exception e) {
// failed to borrow object; you get to decide how to handle this
throw e;
}
try {
// use the pooled object
obj.sing();
} catch (Exception e) {
// this object has failed us -- never use it again!
pool.invalidateObject(obj);
obj = null; // don't return it to the pool
// now handle the exception however you want
} finally {
if (obj != null) {
pool.returnObject(obj);
}
}
}
} finally {
pool.close();
}
}
}