I am building using java servlet/jsp. I have a class to handle database connection, but I dont know should I create each instance for each request or one instance for all requests.
For instance:
Scenario 1:
class HandleDB {
public static HandleDB getInstance(); // singleton pattern
public void initConnection();
public void releaseConnection();
}
then,
//at the beginning of a request:
HandleDB.getInstance().initConnection();
// handle tasks
// at the end of request
HandleDB.getInstance().releaseConnection();
Scenario 2:
class HandleDB {
public void initConnection();
public void releaseConnection();
}
//at the beginning of a request:
HandleDB db = new HandleDB();
db.initConnection();
// handle tasks
// at the end of request
db.releaseConnection();
db = null;
Which scenario should be used in practice?
Go with Scenario 2. The problem with Scenario 1 is that the same HandleDB instance will be shared by all requests and could lead to thread safety issues. Keep in mind that requests can be executed in parallel. The standard is to have one connection per thread/request.
Most Web applications use a connection pool (like C3P0 or Apache DBCP) to avoid having to create a new connection for each request. You get a connection from the pool at the beginning of the request and return it to the pool at the end of the request, so other requests can reuse it later.
Use Listeners LINK
public class AppServletContextListener implements ServletContextListener{
#Override
public void contextDestroyed(ServletContextEvent arg0) {
/// Destroy DB Connection
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
/// Create DB Connection
}
}
if you have batch of tasks you should create database connection only at beginning of first task then after finishing all task you should release or free db connection
for your case scenario 1 is applicable.
Related
I am working on a Spring project. I want to use scheduler in it and want to schedule it on a variable date. This date has to be taken from database. Is it possible to fetch data from database before server is getting started?
Two solutions come to my mind:
#PostConstruct annotated method of some #Component:
#Component
public class MyBean
{
#PostConstruct
public void init()
{
// Blocking DB call could go here
}
}
Application Events. For the ApplicationReadyEvent:
#Component
public class ApplicationReadyEventListener implements ApplicationListener<ApplicationReadyEvent>
{
#Override
public void onApplicationEvent(ApplicationReadyEvent event)
{
// DB call could go here
//
// Notice that if this is a web services application, it
// would potentially be serving requests while this method
// is being executed
}
}
I have a default standalone.xml configuration where there is a maximum of 20 connections to be active at the same time in the pool of connections to the database. With good reasons, I guess. We run an Oracle database.
There's a reasonable amount of database traffic as there is third party API traffic, e.g. SOAP and HTTP calls in the enterprise application I'm developing.
We often do something like the following:
#PersistenceContext(unitName = "some-pu")
private EntityManager em;
public void someBusinessMethod() {
someEntity = em.findSomeEntity();
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
em.update(someEntity);
cdiEvent.fire(finishedBusinessEvent);
}
However, in this case the database connection is acquired when the entity is fetched and is released after the update (actually when the entire transaction is done). About transactions, everything is container managed, no additional annotations. I know that you shouldn't "hold" the database connection longer than necessary, and this is exactly what I'm trying to solve. For one I wouldn't know how to programmatically release the connection nor do I think it would be a good idea, because you still want to be able to roll back for the entire transaction.
So? How to attack this problem? There's a number of options I tried:
Option 1, using ManagedExecutorService:
#Resource
private ManagedExecutorService mes;
public void someBusinessMethod() {
someEntity = em.findSomeEntity();
this.mes.submit(() -> {
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
em.update(someEntity);
cdiEvent.fire(finishedBusinessEvent);
});
}
Option 2, using #Asynchronous:
#Inject
private AsyncBean asyncBean;
public void someBusinessMethod() {
someEntity = em.findSomeEntity();
this.asyncBean.process(someEntity);
}
public class AsyncBean {
#Asynchronous
public void process() {
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
em.update(someEntity);
cdiEvent.fire(finishedBusinessEvent);
}
}
This in fact solved the database connection pooling issue, e.g. the connection is released as soon as the soap.callEndPoint happened. But it did not feel really stable (can't pinpoint the problems here). And of course the transaction is finished once you enter the a-sync processing, so whenever something went wrong during the soap call there was nothing roll backed.
wrapping up...
I'm about to move the long running IO tasks (soap and http calls) to a separate part of the application offloaded via queue's and feeding the result back in the application via queue's once again. In this case everything is done via transactions and no connections are held up. But this is a lot of overhead, thus before doing so I'd like to hear your opinion / best practices how to solve this problem!
Your queue solution is viable, but perhaps not necessary if you only perform read operations before your calls, you could split the transaction into 2 transactions (as you would also do with the queue) by using a DAO pattern.
Example:
#Stateless
private DaoBean dao;
#TransactionAttribute(TransactionAttributeType.NEVER)
public void someBusinessMethod() {
Entity e = dao.getEntity(); // creates and discards TX
e = soap.callEndPoint(e.getSomeProperty());
dao.update(e); // creates TX 2 and commits
}
This solutions has a few caveats.
The business method above can not be called while a transaction is already active because it would negate the purpose of the DAO (one TX suspended with NOT_SUPPORTED).
You will have to handle or ignore the possible changes that could have occurred on the entity during the soap call (#Version ...).
The entity will be detached in the business method, so you will have to eager load everything you need in the soap call.
I can't tell you if this would work for you as it depends on what is done before the business call. While still complex, it would be easier than a queue.
You were kind of heading down the right track with Option 2, it just needs a little more decomposition to get the transaction management happening in a way that keeps them very short.
Since you have a potentially long running web service call you're definitely going to need to perform your database updates in two separate transactions:
short find operation
long web service call
short update operation
This can be accomplished by introducing a third EJB as follows:
Entry point
#Stateless
public class MyService {
#Inject
private AsyncService asyncService;
#PersistenceContext
private EntityManager em;
/*
* Short lived method call returns promptly
* (unless you need a fancy multi join query)
* It will execute in a short REQUIRED transaction by default
*/
public void someBusinessMethod(long entityId) {
SomeEntity someEntity = em.find(SomeEntity.class, entityId);
asyncService.process(someEntity);
}
}
Process web service call
#Stateless
public class AsyncService {
#Inject
private BusinessCompletionService businessCompletionService;
#Inject
private SomeSoapService soap;
/*
* Long lived method call with no transaction.
*
* Asynchronous methods are effectively run as REQUIRES_NEW
* unless it is disabled.
* This should avoid transaction timeout problems.
*/
#Asynchronous
#TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public void process(SomeEntity someEntity) {
soap.callEndPoint(someEntity.getSomeProperty()); // may take up to 1 minute
businessCompletionService.handleBusinessProcessCompletion(someEntity);
}
}
Finish up
#Stateless
public class BusinessCompletionService {
#PersistenceContext
private EntityManager em;
#Inject
#Any
private Event<BusinessFinished> businessFinishedEvent;
/*
* Short lived method call returns promptly.
* It defaults to REQUIRED, but will in effect get a new transaction
* for this scenario.
*/
public void handleBusinessProcessCompletion(SomeEntity someEntity) {
someEntity.setSomething(SOMETHING);
someEntity = em.merge(someEntity);
// you may have to deal with optimistic locking exceptions...
businessFinishedEvent.fire(new BusinessFinished(someEntity));
}
}
I suspect that you may still need some connection pool tuning to cope effectively with your peak load. Monitoring should clear that up.
I've read about entities lifecycle, and the locking strategies, and I watched some videos about this but I'm still not sure I understand.I understand there is also a locking mechanism in the underlying RDBMS (I'm using mysql).
I would like to know at what point a transaction is committed / entity is detached and how does it affect other transactions from a locking point of view. At what point does an user have to wait till a transaction finishes ? I've made two different scenarios below. For the sake of understanding I'm asserting the table in the scenarios contains a lot of rows and the for loops takes 10 minute to complete.
Scenario 1:
#Stateless
public class AService implements AServiceInterface {
#PersistenceContext(unitName = "my-pu")
private EntityManager em;
#Override
public List<Aclass> getAll() {
Query query = em.createQuery(SELECT_ALL_ROWS);
return query.getResultList();
}
public void update(Aclass a) {
em.merge(a);
}
}
and a calling class:
public aRadomClass{
#EJB
AServiceInterface service;
public void method(){
List<Aclass> listAclass = service.getAll();
for(Aclass a : listAclass){
a.setProperty(methodThatTakesTime());
service.update(a);
}
}
}
Without specifying a locking strategy : If another user wants to makes an update to one row in the table and the for loop already began but is not finished. Does he have to wait till the for loop is completed ?
Scenario 2:
#Stateless
public class AService implements AServiceInterface {
#PersistenceContext(unitName = "my-pu")
private EntityManager em;
#Override
public List<Aclass> getAllAndUpdate() {
Query query = em.createQuery(SELECT_ALL_ROWS);
List<Aclass> listAclass = query.getResultList();
for(Aclass a : listAclass ){
a.setProperty(methodThatTakesTime());
em.merge(a);
}
}
}
Same question.
It is important what kind of class is your aRandomClass. If it is also an EJB, you should take a look in the transaction propagation. If it is a servlet, then the transaction is closed automatically right after your EJB method exits (no matter which one). That is done using dynamic proxies. So in scenario 1 the EJB container will open and close multiple transactions: one for service.getAll() and one for each service.update(a) call. In scenario 2, if method getAllAndUpdate() is called only once, a single transaction will be opened and it will be closed on method exit.
I have an Spring MVC app with an embedded database (HSQLDB) that I want to initialize after deployment. I know that I could use an xml script to define initial data for my datasource but, as long I'm using JPA + Hibernate, I would like to use Java code. Is there a way to do this?
Heavily updated answer (it was too complex before):
All you need is to add initializing bean to your context, which will insert all the necessary data into the database:
public class MockDataPopulator {
private static boolean populated = false;
#Autowired
private SessionFactory sessionFactory;
#PostConstruct
public void populateDatabase() {
// Prevent duplicate initialization as HSQL is also initialized only once. Duplicate executions
// can happen when the application context is reloaded - e.g. when running unit tests).
if (populated) {
return;
}
// Create new persistence session
Session session = sessionFactory.openSession();
session.setFlushMode(FlushMode.ALWAYS);
// Insert mock entities
session.merge(MockDataFactory.createMyFirstObject())
session.merge(MockDataFactory.createMySeconfObject())
// ...
// Flush and close
session.flush();
session.close();
// Set initialization flag
populated = true;
}
}
I'm dealing with a C# application with a EntityFramework backbone using a DbContext.
The application has two choices: connect to a remote SQL server express or connect to a local SQL compact 4.0 database in case the network connection is not available.
When my application starts, a thread is checking if a connection to the remote database is possible. Otherwise it automatically needs to switch the connection string and provider in order to connect to the local database.
So far I was trying to deal with this issue by modifying the connection string section in app.config and forcing the application to refresh the section, after saving the configuration. This approach is not the best since I need to have access rights to write into the app.config file.
Could you suggest a better approach?
Wrap the management of connection strings in a class, make that class a singleton, and use it to obtain the active connection string, like this:
public delegate void ConnectionChangedEventHandler(object sender, EventArgs e);
class ConnStringManager {
static public ConnStringManager Instance {get;private set;}
static {
Instance = new ConnStringManager();
}
public event ConnectionChangedEventHandler Changed;
private readonly string localConn;
private readonly string remoteConn;
public string ConnectionString {get; private set;}
private ConnStringManager() {
localConn = ... // Get local connection string from the config
remoteConn = ... // Get remote connection string from the config
TestAndSetConnectionString();
}
public void TestAndSetConnectionString() {
bool canUseRemote = true;
if (...) {
// Do some testing to see if remote DB is accessible
}
// Switch the connection string
var nextString = canUseRemote ? remoteConn : localConn;
bool changed = nextString != ConnectionString;
ConnectionString = nextString;
if (changed && Changed != null) {
Changed(this, EventArgs.Empty);
}
}
}
The DbContext constructor accepts either the name of the connection string, or the actual connection string you want to choose.
What you could do, is test your initial connection string - maybe with a quick ado connection or something simple, and then if it connects use it, otherwise connect using your other one.
Some pseudocode:
YourDbContext YourContext;
if (TestConnection())
{
YourContext = new YourDbContext("ConnectionString1");
}
else
{
YourContext = new YourDbContext("ConnectionString2");
}