I'm trying to implement the "One-session-per-http-request" pattern with Hibernate, and it works for the 1st request : The servlet's doGet() method opens the session, gets some stuff, and closes the session.
But when I refresh the browser, My DAO Singleton instance (whose constructor gets the session from the SessionFactory) gets called a second time, but still uses the old session object (the singleton constructor is NOT called again). I then obtain a "Session is closed" error.
I guess that the singleton instance must be kept in cache between HTTP requests, so : How can I get the DAO singleton constructor called again ? (or another elegant solution to have the fresh SessionFactory session object ?)
Thank you very much
The servlet :
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Gets the session, eventually creates one
Session s = HibernateUtil.currentSession();
// Gets data from singleton DAO instance
MySingletonDAO o = MySingletonDAO.getInstance();
List<Stuff> stuff = o.getAllTheStuff();
// send it to the view
request.setAttribute("foo",stuff);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue);
dispatcher.forward(request, response);
}
/* error handling blah blah */
finally {
// closing the session
HibernateUtil.closeSession();
}
MySingletonDAO.java :
public class MySingletonDAO {
// Usual singleton syntax
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private Session session;
private MySingletonDAO() {
session = HibernateUtil.currentSession();
System.out.println("This constructor is called only on the first HTTP transaction");
}
public List<Stuff> getAllTheStuff() {
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
A classical thread-safe HibernateUtil.java :
public class HibernateUtil {
private static final SessionFactory sessionFactory;
public static final ThreadLocal session = new ThreadLocal();
static {
try {
// Creates the SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he) {
throw new RuntimeException("Conf problem : "+ he.getMessage(), he);
}
}
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// Opens a new Session, if this Thread has none
if (s == null || !s.isOpen() ) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
What you're asking for doesn't make sense: if the constructor of the singleton was called at each request, it wouldn't be a singleton anymore. The session is indeed closed at the end of the request, but the DAO keeps a reference to the session, instead of getting it from your util class every time it's called.
Your DAO code should be
public class MySingletonDAO {
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private MySingletonDAO() {
}
public List<Stuff> getAllTheStuff() {
Session session = HibernateUtil.currentSession();
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
That said, transactions should be handled declaratively, and should be handled at the service layer rather than the DAO layer: a transaction typically uses deveral DAOs, the entities returned by the DAO should stay managed, and all the accesses and modifications made to these entities should be made inside the transaction.
I strongly recommend using a Java EE container, or Spring, to handle the transactions and the session handling for you. You should also use the standard JPA API rather than the proprietary Hibernate API.
Related
As far as I know session per request means we should use only one hibernate session per servlet request, not one session per transaction.
Consider this helper class:
public class HibernateUtil {
private static SessionFactory sessionFactory;
// this is called by the servlet context listener
public static void buildSessionFactory() {
// build session factory
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
// check if the entity user already exist in the database
public static User getUser(String email) {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
User user = (User)session.createQuery("from User c where c.emailAddress like :email").setParameter("email", email).uniqueResult();
session.getTransaction().commit();
return user;
}
// if getUser returns null, insert this user in the database
public static void insertUser(User user) {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(user);
session.getTransaction().commit();
}
}
Now each method has it's own session object, but when the register servlet gets called I have to do this:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = // initialise user
if (getUser(request.getParameter("email")) == null) { // session
insertUser(user); // another session
request.setAttribute("user", user);
request.getRequestDispatcher("homepage.jsp").forward(request, response);
} else {
request.setAttribute("message", "This account already exist");
populateFields(request);
request.getRequestDispatcher("register.jsp").forward(request, response);
}
}
Now, my register servlet effectively used two sessions, vilating the pattern. I've thought of possible ways to fix:
Set a global Session object in the hibernateUtil class, then prevent getUser from committing the transaction. I think this means every method can now use this session, even in multiple request if the transaction is not committed. My problem is what is my only operation is to get a user and nothing more?
Let getUser return the session and pass it to insertUser, I don't know, I'm not sure if it's good to pass session objects around.
Just get rid of the helper class and write the code directly in the servlet and remove the helper class. I really think it would simplify the management of sessions, but I might not be able to reuse some transactions.
What should I do? And are there better code that does what I want to do?
The best option in this case is to have a design like this:
Have an abstract Dao that will have a Session session as field and will allow the injection of this via constructor or setter (up to you). All your Daos will be subclasses of this class.
The service classes can create a Session session in their methods or receive it as parameter. In this way, the service may inject the session to the necessary daos used in its methods. This also enables the service to start and commit/rollback a transaction.
In case you want/need that services should be unaware of opening/closing hibernate sessions, then you may create a wrapper for the interfaces that will create a session, inject it to a service, and then execute the proper methods of the service(s). After executing the method, this wrapper will commit/rollback the operations done in the session.
If you use a framework like Spring that provides integration with Hibernate, you will see that they have a similar design:
Dao classes must allow the injection of HibernateTemplate via constructor parameter or setter.
Services will use dao interfaces as needed.
Use of <transactional> or #Transactional will create a proxy class that wraps your service to open the session, execute the proper method of the service, and commit/rollback the operations, depending on the configuration of the transaction management done there.
You can implement a filter that creates the session and then stores it in the request, so you can reuse it anywhere you have access to the request object:
public class SessionPerRequestFilter implements Filter {
public static final String SESSION_ATTRIBUTE_NAME = "myapp.hibernate.session";
private static SessionFactory sessionFactory;
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Locate the session on the request object
Session session = (Session) request.getAttribute(SESSION_ATTRIBUTE_NAME);
if(session == null) {
// Create a new session
session = HibernateUtil.getSessionFactory().openSession();
request.setAttribute(SESSION_ATTRIBUTE_NAME, session);
}
try {
// Continue the filter chain
chain.doFilter(request, response);
}
finally {
// Close the session
session.close();
}
}
#Override
public void destroy() {
}
}
In your servlets you then get the session by
Session session = (Session) request.getAttribute(SessionPerRequestFilter.SESSION_ATTRIBUTE_NAME);
Make sure you only close your transactions and not the session in your helper classes though.
I am using the JPA Framework to achieve Database Persistence of information.
This is how I used I created a class like this:
public class ManageConnection {
private static EntityManagerFactory emf = null;
private static EntityManager em = null;
private static String persitenceName="locationtracker";
public static EntityManager getEntityManager(){
if(emf==null || !emf.isOpen())
emf = Persistence.createEntityManagerFactory(persitenceName);
if(em==null || !em.isOpen())
em=emf.createEntityManager();
return em;
}
public static void closeEntityManager(){
if(em!=null && em.isOpen())
em.close()
}
}
Then in my servlet I am using like this:
public void doPost(blablah){
.
.
.
.
.
.
.
.
.
.
.
for(blah blah){
Manageconnection.getEntityManager().getTransaction().begin();
<PersistenceObject> objName = new <PersistenceObject>();
//properties of the objName to persist
ManageConnection.getEntityManager().persist(<objName>);
Manageconnection.getEntityManager().getTransaction().commit();
}
Manageconnection.closeEntityManager();
}
Now my problem is I get Transaction is already active Exception whenever I passes the values to my Servlet also the same code works perfect when there is no Servlet thing, I mean using main method in a Test class it is running like charm, but it throws exception when runs in Servlet.
Please help me..............
;(
Thanks in advance,
Ankur
All of your EntityManagerFactory and EntityManagerFactory is used static. It is the class level and for all instance of ManageConnection. At first, if an instance of ManageConnection is created, it will be share other instance of ManageConnection. My suggestion is just try without using static.
I assume you don't want to use EJBs, but instead want to use POJOs.
(Note there's a simple solution where Session Beans carry out JPA operations and Servlets call EJBs - less code, less ugly, does what you want.)
Each servlet session should have its own entity manager instance. Remove every case of "static" from the class ManageConnection. Then in your servlet, when you create the HttpSession, additionally create an instance of ManageConnection and store it as an attribute in the session.
public class MyServlet extends HttpServlet {
private ManageConnections getManageConnections(HttpSession sess) {
ManageConnection manageConnection =
(ManageConnection)sess.getAttribute("userManageConnection");
if (manageConnection == null) {
ManageConnection manageConnection = new ManageConnection();
sess.setAttribute("userManageConnection", manageConnection);
}
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.processRequest(req, resp);
}
public void processRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
HttpSession sess = req.getSession(true);
ManageConnections manageConnections = this.getManageConnections(sess);
// remaining JPA operations
}
}
Get the EntityManager:
// inside processRequest() above
EntityManager em = manageConnection.getEntityManager();
Start Tx, do entity operations, End Tx
// inside processRequest() above
em.getTransaction().begin();
<PersistenceObject> objName = new <PersistenceObject>();
//properties of the objName to persist
em.persist(<objName>);
em.getTransaction().commit();
Close the EntityManager before the user finishes their session. This is important, because without it some implementations will need to be restarted very often - especially during development when you're rebuilding and redeploying often (I'm looking at you, EclipseLink on Glassfish, deployed using netbeans modules).
make servlet: extends HttpSessionListener
// add the following methods, so we get a callback to sessionDestroyed when the
// session is closed via user logout (terminateSession) or session timeout:
public void init(ServletConfig config) throws ServletException {
config.getServletContext().addListenter(this.class.getName());
}
public void sessionCreated(HttpSessionEvent se) {
}
public void sessionDestroyed(HttpSessionEvent se) {
ManageConnections manageConnections = this.getManageConnections();
manageConnections.getEntityManager().close();
manageConnections.getEntityManagerFactor().close();
}
As I said - a bit ugly, because we are using a very stateful Application Managed Entity Manager in a stateless Servlet. Much cleaner to use a Transaction Scoped Entity Manager in a Stateless Session Bean or Extended Scope (or Application Managed) Entity Manager in a Stateful Session Bean... quite a JPA mouthful, but easier than it sounds.
:-)
I created two classes like this:
//This class has the EntityManagerFactory instance that is going to be shared between the classes
public class ManageConnection {
protected static EntityManagerFactory emf = null;
private static String persitenceName="locationtracker";
//Anonymous Block that is going to be called (beofre) on every call for constructor of this class
//whether through inheritance or normal instantiation
{
if(emf==null || !emf.isOpen())
emf = Persistence.createEntityManagerFactory(persitenceName);
}
public static EntityManagerFactory getEntityManagerFactory(){
return ManageConnection.emf;
}
}
//This class actually handles the trasactional management
public class ManageTransaction extends ManageConnection{
/**
*
*/
public ManageTransaction() {
super();
this.entityManager = emf.createEntityManager();
this.transaction = this.entityManager.getTransaction();
}
/**
* #param entityManager
* #param transaction
*/
public ManageTransaction(EntityManager entityManager,EntityTransaction transaction) {
super();
this.entityManager = entityManager;
this.transaction = transaction;
}
private EntityManager entityManager;
private EntityTransaction transaction;
/**
* #return the entityManager
*/
public EntityManager getEntityManager() {
return entityManager;
}
/**
* #param entityManager the entityManager to set
*/
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
/**
* #return the transaction
*/
public EntityTransaction getTransaction() {
return transaction;
}
/**
* #param transaction the transaction to set
*/
public void setTransaction(EntityTransaction transaction) {
this.transaction = transaction;
}
public void closeEntityManager(){
if(entityManager!=null && entityManager.isOpen()){
entityManager.close();
}
}
public void close(){
this.closeEntityManager();
}
public void flush(){
entityManager.flush();
}
public void begin(){
this.transaction.begin();
}
public void commit(){
this.flush();
this.transaction.commit();
}
public void persist(Object objToPersist){
this.entityManager.persist(objToPersist);
}
}//end of ManageTransaction class
Now if I want to use this, I use like this:
.
.
.
.
.
.
ManageTransaction mt = new ManageTransaction();
Scenario 1
mt.getEntityManager().find(blah,blah);//works perfectly
Scenario 2
mt.begin();
<PersistenceObject> objName = new <PersistenceObject>();
mt.persist(objName);
mt.close();
Scenario 3
String jpaquery = "blah blah";
TypedQuery<ClassType> tq = mt.getEntityManager().createQuery(jpaquery,<Class>.class);
List<ClassType> all = tq.getResultList();
In this way every time creating new Transaction is not required I just create a single transaction and use that transaction every where in my class and at the end closes it.
That way my problem of sharing EntityManager is solved and thus never throws the Exception at any case.
:)
I am working on a java web application that calls database backend through hibernate.I use servlets,jsp and tomcat for test/deployment.Most books on java-ee suggested using Dao classes for database calls.As per examples given in books(Hibernate Recipes by Gary Mak),I created a generic base class and a specific subclass as below.
class BaseDao{
private Class persistentClass;
public BaseDao(Class persistentClass) {
super();
this.persistentClass = persistentClass;
}
public Object findById(Long id) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Object object = null;
try {
object = (Object) session.get(persistentClass, id);
return object;
}
finally {
session.close();
}
}
#Override
public void saveOrUpdate(Object obj) {
SessionFactory factory = HibernateUtil.getSessionFactory();
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
session.saveOrUpdate(obj);
tx.commit();
}catch(HibernateException e){
if (tx != null) {
tx.rollback();
}
throw e;
}finally {
session.close();
}
}
}
class SaleOrderDao extends BaseDao{
public SaleOrderDao() {
super(SaleOrder.class);
}
#Override
public SaleOrder findSaleOrderById(Long saleOrderId){
SaleOrder so = (SaleOrder)findById(saleOrderId);
return so;
}
#Override
public void saveOrUpdateSaleOrder(SaleOrder so){
saveOrUpdate( so);
}
}
While going through the posts in this forum ,I came across Ryan Stewart's advice that beginning and ending transactions in a dao method is not recommended..Sadly, my project does not use any web framework that supports transaction management..and I am limited to using jsp,servlets and a servlet container..
Is there some way I can rewrite my dao implementations sothat transactions can be managed properly..I couldn't find anything in this regard from those books I read..
Hope somebody helps me with suggestions
sincerely,
Jim
Normally transactions should not be handled in the DAO. They should be handled by the service layer. One service method may include multiple DAO calls that are all in the same transaction.
Spring (as well as other DI frameworks) allows you to do that by simply annotating your service methods with #Transactional. Without spring you can still do that manually in the service layer
Ok, I read bunch of articles/examples how to write Entity Manager Factory in singleton.
One of them easiest for me to understand a bit:
http://javanotepad.blogspot.com/2007/05/jpa-entitymanagerfactory-in-web.html
I learned that EntityManagerFactory (EMF) should only be created once preferably in application scope.
And also make sure to close the EMF once it's used (?)
So I wrote EMF helper class for business methods to use:
public class EmProvider {
private static final String DB_PU = "KogaAlphaPU";
public static final boolean DEBUG = true;
private static final EmProvider singleton = new EmProvider();
private EntityManagerFactory emf;
private EmProvider() {}
public static EmProvider getInstance() {
return singleton;
}
public EntityManagerFactory getEntityManagerFactory() {
if(emf == null) {
emf = Persistence.createEntityManagerFactory(DB_PU);
}
if(DEBUG) {
System.out.println("factory created on: " + new Date());
}
return emf;
}
public void closeEmf() {
if(emf.isOpen() || emf != null) {
emf.close();
}
emf = null;
if(DEBUG) {
System.out.println("EMF closed at: " + new Date());
}
}
}//end class
And my method using EmProvider:
public String foo() {
EntityManager em = null;
List<Object[]> out = null;
try {
em = EmProvider.getInstance().getEntityManagerFactory().createEntityManager();
Query query = em.createNativeQuery(JPQL_JOIN); //just some random query
out = query.getResultList();
}
catch(Exception e) {
//handle error....
}
finally {
if(em != null) {
em.close(); //make sure to close EntityManager
}
//should I not close the EMF itself here?????
EmProvider.getInstance().closeEmf();
}
I made sure to close EntityManager (em) within method level as suggested. But when should EntityManagerFactory be closed then? And why EMF has to be singleton so bad??? I read about concurrency issues but as I am not experienced multi-thread-grammer, I can't really be clear on this idea.
EntityManagerFactory instances are
heavyweight objects. Each factory
might maintain a metadata cache,
object state cache, EntityManager
pool, connection pool, and more. If
your application no longer needs an
EntityManagerFactory, you should
close it to free these resources.
When an EntityManagerFactory closes,
all EntityManagers from that factory,
and by extension all entities managed
by those EntityManagers, become
invalid.
It is much better to keep a factory
open for a long period of time than
to repeatedly create and close new
factories. Thus, most applications
will never close the factory, or only
close it when the application is
exiting.
Only applications that require
multiple factories with different
configurations have an obvious reason
to create and close multiple
EntityManagerFactory instances.
Only one EntityManagerFactory is
permitted to be created for each
deployed persistence unit
configuration. Any number of
EntityManager instances may be
created from a given factory.
More than one entity manager factory
instance may be available
simultaneously in the JVM. Methods of the EntityManagerFactory
interface are threadsafe.
Scenario:
I have #Singleton UserFactory (#Stateless could be) , its method createSession() generating #Stateful UserSession bean by manual lookup.
If I am injecting by DI #EJB - i will get same instance during calling fromFactory() method(as it should be)
What I want - is to get new instance of UserSession without preforming lookup.
Q1: how could I call new instance of #Stateful session bean?
Code:
#Singleton
#Startup
#LocalBean
public class UserFactory {
#EJB
private UserSession session;
public UserFactory() {
}
#Schedule(second = "*/1", minute = "*", hour = "*")
public void creatingInstances(){
try {
InitialContext ctx = new InitialContext();
UserSession session2 = (UserSession) ctx.lookup("java:global/inferno/lic/UserSession");
System.out.println("in singleton UUID " +session2.getSessionUUID());
} catch (NamingException e) {
e.printStackTrace();
}
}
#Schedule(second = "*/1", minute = "*", hour = "*")
public void fromFactory(){
System.out.println("in singleton UUID " +session.getSessionUUID());
}
public UserSession creatSession(){
UserSession session2 = null;
try {
InitialContext ctx = new InitialContext();
session2 = (UserSession) ctx.lookup("java:global/inferno/lic/UserSession");
System.out.println("in singleton UUID " +session2.getSessionUUID());
} catch (NamingException e) {
e.printStackTrace();
}
return session2;
}
}
As I understand, calling of
session.getClass().newInstance();
is not a best idea
Q2 : is it true?
#
Update
Goals
In reality the goal is to create some SessionsFactory that that would managed user`s sessions (this is web services users)
The Session #Statefull bean :
#Stateful
//Destroying outomaticly after 30 minuts inactive
#StatefulTimeout(180000)
#LocalBean
public class UserSession {
//represent creation time, used by scheduler for destroying session
private GregorianCalendar creationDate;
private UUID sessionUUID;
private String userId;
private String state;
//TODO change to xml
private String histrory;
public UserSession() {
}
#PostConstruct
private void initSession(){
//getting construction date
creationDate = (GregorianCalendar) Calendar.getInstance();
//generationg session id
sessionUUID = UUID.randomUUID();
}
#PreDestroy
private void releaseResource(){
creationDate =null;
sessionUUID = null;
userId =null;
}
#Remove
public void destroySession(){
}
public UUID getSessionUUID() {
return sessionUUID;
}
public GregorianCalendar getCreationDate() {
return creationDate;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getHistrory() {
return histrory;
}
public void addHistroryEntry(String entry) {
//TODO add history entry
}
}
In factory methods I want just create new instance of #Statefull UserSession and to manage number of created sessions for each user, and call destroySession() after some period (30 minutes)
I need to track the history of user`s sessions requests , and persists there history later..
So I think #Statefull bean should suet my needs. But it looks like the lookup by JNDI name is the only chance to be shore that new ejb will be created. I am searching for possibility
to inject new instance of ejb without lookups, and maybe possibility to get collection of currently created instances of my #Statefull UserSession instead of keeping thrm in some map/collection.
Q3: so.. only JNDI will help me to create new instance of ejb ?
Q4: Is it possible to get collection of some ejb`s instances from container?
I am using glassfish v3, ejb 3.1.
Q1: how could I call new instance of #Stateful session bean?
You must not inject a Stateful Session Bean into a stateless object such as Stateless
Session Bean or Servlet that may be shared by multiple concurrent clients, you should use JNDI instead. Period.
To be honest, I'm not sure to understand what you are doing and I don't see important steps such as removal of your Stateful Session Beans. You are likely going to run out of memory or cause a lot of disk IO as the container that will try to passivate/activate instances to save memory.
Q2 : is it true?
You can call new but don't expect to get something else than a simple Java class i.e. don't expect to get a managed object i.e. don't expect to get an EJB. I don't think that this is what you want.
Sorry if this doesn't help much but as I said, I don't really understand what you're trying to achieve. You should maybe start to explain your goal first, I don't have the feeling that you are on the right path.