Hibernate issue with `SessionFactory` - java

I am having a JSP, Servlet (Pure JSP, Servlet) application where it uses Hibernate. Below is a Hibernate implementation class for a one table.
DesignationImpl.java
package dao;
import model.sub.DesigAllBean;
import java.util.List;
import model.main.Designation;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
/**
*
* #author Yohan
*/
public class DesignationImpl implements DesignationInterface
{
#Override
public Session openCurrentSession() {
Session currentSession = getSessionFactory().openSession();
return currentSession;
}
#Override
public Transaction openTransaction(Session session) {
Transaction beginTransaction = session.beginTransaction();
return beginTransaction;
}
private static SessionFactory getSessionFactory() {
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties());
SessionFactory sessionFactory = configuration.buildSessionFactory(builder.build());
return sessionFactory;
}
#Override
public void save(Designation d, Session session)
{
session.save(d);
}
#Override
public void update(Designation d, Session session)
{
session.update(d);
}
}
Below is the service class which calls to the above class.
DesignationService .java
package service;
import dao.Common;
import model.sub.*;
import dao.DesignationImpl;
import dao.DesignationInterface;
import java.util.ArrayList;
import java.util.List;
import model.main.Designation;
import org.hibernate.Session;
import org.hibernate.Transaction;
/**
*
* #author Yohan
*/
public class DesignationService
{
private DesignationInterface designationInterface;
public DesignationService()
{
designationInterface = new DesignationImpl();
}
public Session getSession()
{
Session session = designationInterface.openCurrentSession();
return session;
}
public Transaction getTransaction(Session session)
{
return designationInterface.openTransaction(session);
}
public String save(Designation d)
{
Session session = designationInterface.openCurrentSession();
Transaction transaction = null;
String result="";
try
{
transaction = designationInterface.openTransaction(session);
designationInterface.save(d,session);
transaction.commit();
result = Common.SAVE_SUCCESS;
}
catch(Exception e)
{
e.printStackTrace();
if(transaction!=null)
{
transaction.rollback();
}
result = Common.SAVE_ROLLBACK;
}
finally
{
session.close();
}
return result;
}
public String update(Designation d)
{
Session session = designationInterface.openCurrentSession();
Transaction transaction = null;
String result="";
try
{
transaction = designationInterface.openTransaction(session);
designationInterface.update(d,session);
transaction.commit();
result = Common.SAVE_SUCCESS;
}
catch(Exception e)
{
e.printStackTrace();
if(transaction!=null)
{
transaction.rollback();
}
result = Common.SAVE_ROLLBACK;
}
finally
{
session.close();
}
return result;
}
}
And the servlets call them like below.
DesignationService desigSrvc=new DesignationService();
Designation designation=desigSrvc.findByForiegnKey(idEmployee);
Employee empl=new Employee();
empl.setIdEmployee(idEmployee);
if(designation.getDateCreated()==null)
{
designation.setDateCreated(Common.getCurrentDateSQL());
}
designation.setEmployee(empl);
designation.setDesignation(txtDesignation);
designation.setLocation(location);
designation.setSalary(salary);
designation.setDatePromoted(datePromoted);
designation.setLastUpdated(Common.getCurrentDateSQL());
desigSrvc.save(designation);
As you can see, there is a bad thing happening there, that is, the servlets are creating new SessionFactory instances every time it executes.I am having Driver#Connect issues and I guess this might be the reason for it.
I read stackoverflow posts and some seems to be suggesting the use of only one SessionFactory for the entire application. If it is suitable, then how can I do it? Maybe make a singleton class like below and use it in my implementation classes?
public class SessionFactoryBuilder
{
private static SessionFactoryBuilder instance;
private static SessionFactory sessionFactory;
private SessionFactoryBuilder()
{
}
private static void buildConfig()
{
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(builder.build());
}
public static SessionFactoryBuilder getInstance()
{
if(instance == null)
{
instance = new SessionFactoryBuilder();
buildConfig();
}
return instance;
}
public SessionFactory getSessionFactory()
{
return sessionFactory;
}
}
But then what about threads? Servlets are multi threaded isn't it?

As I commented I have the HibernateUtil.java class as Singleton. This class can provide you sessionfactory using HibernateUtil.getSessionFactory() and you should remove the related code from your DesignationImpl class
public class HibernateUtil {
private static StandardServiceRegistry serviceRegistry;
private static SessionFactory INSTANCE = null;
public static SessionFactory getSessionFactory() {
if(INSTANCE=null){
createSessionFactory():
}
return sessionFactory;
}
private synchronized static void createSessionFactory(){
if(INSTANCE!=null){return;}
Configuration configuration = new Configuration();
configuration.configure();
SeviceRegistry=newStandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
}
}
Find the above code, and please suggest / comment to confirm the correctness of code.I think threading will be taken care of using this..I adding a dual check to avoid multiple sessionfactory creation ad its a heavy resource.

I corrected Viraj Nalawade's code which had a few errors:
class HibernateUtil {
private static SessionFactory INSTANCE = null;
public static SessionFactory getSessionFactory() {
if (INSTANCE == null) {
createSessionFactory();
}
return INSTANCE;
}
private synchronized static void createSessionFactory() {
if (INSTANCE != null) {
return;
}
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = configuration.getStandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
INSTANCE = configuration.buildSessionFactory(serviceRegistry);
}
}

Related

Getting exception java.lang.IllegalStateException: EntityManagerFactory is closed while trying to save secound istance

I am learning hibernate. Everything is preaty clear at the beegining, however when I try to run my app and in main I have two operation connected with session I get exception:
java.lang.IllegalStateException: EntityManagerFactory is closed
Below you can find my DBManager class where I habe methods for adding instances to DB:
import org.hibernate.Session;
public class DBManager
{
public void addAutor(String name, String lastName, Book book)
{
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Autor autor = new Autor(name,lastName,book);
session.save(autor);
session.getTransaction().commit();
HibernateUtil.getSessionFactory().close();
}
public Book addBook(int ISBN, String name, String autorName)
{
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Book book = new Book(ISBN,name,autorName);
session.save(book);
session.getTransaction().commit();
HibernateUtil.getSessionFactory().close();
return book;
}
}
Here is my HibernateUtil class for configuration of the session:
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.addAnnotatedClass(Autor.class);
configuration.addAnnotatedClass(Book.class);
configuration.configure();
StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder();
standardServiceRegistryBuilder.applySettings(configuration.getProperties());
ServiceRegistry serviceRegistry = standardServiceRegistryBuilder.build();
return configuration.buildSessionFactory(serviceRegistry);
}
catch(Exception e) {
throw new ExceptionInInitializerError(e);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
And finally the main class:
public class Test
{
public static void main (String args[])
{
DBManager dbManager = new DBManager();
Book book = dbManager.addBook(1,"Hobbit","Tolkien");
dbManager.addAutor("JRR","Tolkien",book);
}
}
As you can see I just put book, and than try to put Autor. What could be the reason for exception from secound method? I suppose that I do sth. wrong with closing and opening of the session, however I cannot figure out what is wrong.
I found the sulution myself:
I have created the one sessionFactory object for whole class DBManager:
private final SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
So in every method I open session, and than close at the end, eg:
public void addAutor(String name, String lastName, Book book)
{
Session session=sessionFactory.openSession();
session.beginTransaction();
Autor autor = new Autor(name,lastName,book);
session.save(autor);
session.getTransaction().commit();
session.close();
}
Maybe someone will face the same problem.

Hibernate upgrade to 5.2 - Session Factory creation and replacing PersistentClass for getting entity class properties

I am currently upgrading my Hibernate version to the latest version 5.2.10. I replaced my code in the HibernateUtil for the SessionFactory creation.
4.3.11.Final (Previous):
public class HibernateUtil {
private HibernateUtil() {}
private static SessionFactory sessionFactory;
private static Configuration configuration;
public static Configuration getConfiguration() {
return configuration;
}
private static SessionFactory buildSessionFactory() {
try {
if(sessionFactory == null) {
configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();
sessionFactory = configuration
.buildSessionFactory(serviceRegistry);
}
return sessionFactory;
}
catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return buildSessionFactory();
}
public static Session getSession() {
Session hibernateSession = getSessionFactory().getCurrentSession();
return hibernateSession;
}
public static void shutdown() {
getSessionFactory().close();
}
}
5.2.10 Final (New):
public class HibernateUtil {
private static StandardServiceRegistry registry;
private static SessionFactory sessionFactory;
public static SessionFactory getSessionFactory() {
return buildSessionFactory();
}
public static SessionFactory buildSessionFactory() {
if (sessionFactory == null) {
try {
registry = new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
MetadataSources sources = new MetadataSources(registry);
Metadata metadata = sources.getMetadataBuilder().build();
sessionFactory = metadata.getSessionFactoryBuilder().build();
} catch (Exception e) {
e.printStackTrace();
shutdown();
}
}
return sessionFactory;
}
public static Session getSession() {
Session hibernateSession = getSessionFactory().getCurrentSession();
return hibernateSession;
}
public static void shutdown() {
if (registry != null) {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
Now I have a method which would fetch me the list of column names by passing the DB table name as a string. I did it like this before in 4.3.11.Final:
public static List<String> getColumnNames(String tableName) {
List<String> columnList=null;
Map<String, ClassMetadata> map = HibernateUtil.getSessionFactory().getAllClassMetadata();
Iterator<Entry<String, ClassMetadata>> itr = map.entrySet().iterator();
while(itr.hasNext()){
ClassMetadata classMetaData = itr.next().getValue();
AbstractEntityPersister aep = (AbstractEntityPersister) classMetaData;
if(aep.getTableName().split("\\.")[1].equalsIgnoreCase(tableName)){
columnList = new ArrayList<String>();
String[] propertyNames = classMetaData.getPropertyNames();
for(String property : propertyNames){
try {
PersistentClass persistentClass = HibernateUtil .getConfiguration().getClassMapping(classMetaData.getEntityName());
String clmName = ((Column) persistentClass.getProperty(property).getColumnIterator().next()).getName();
columnList.add(clmName);
} catch(NoSuchElementException e){
log.error("Element not found idenfied as : "+property);
} catch(Exception e){
log.error(e.getMessage());
}
}
break;
}
}
return columnList;
}
Now after the upgrade it shows the method getAllClassMetadata as deprecated and am facing difficulty to get the PersistentClass object. I saw a similar question here but I couldn't exactly figure out the solution. What part of my current code do I have to change for my getColumnNames() method to work exactly like before. I referred the documentation and it says to use the EntityManagerFactory.getMetamodel() instead but i can't find suitable reference examples of the same. Also will I have to change the SessionFactory creation mechanism for this?
First, we need to create a new MetadataExtractorIntegrator class that implements the Hibernate Integrator:
public class MetadataExtractorIntegrator
implements org.hibernate.integrator.spi.Integrator {
public static final MetadataExtractorIntegrator INSTANCE =
new MetadataExtractorIntegrator();
private Database database;
#Override
public void integrate(
Metadata metadata,
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
database = metadata.getDatabase();
}
#Override
public void disintegrate(
SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
}
public Database getDatabase() {
return database;
}
}
Then, we can just configure Hibernate to use it.
If you're using the Hibernate bootstrap mechanism, then you can add it like this:
final BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder();
bsrb.enableAutoClose();
Integrator integrator = integrator();
if (integrator != null) {
bsrb.applyIntegrator( integrator );
}
final BootstrapServiceRegistry bsr = bsrb.build();
final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(bsr);
If you're bootstrapping with JPA, then you can do it as follows:
protected EntityManagerFactory newEntityManagerFactory() {
PersistenceUnitInfo persistenceUnitInfo = persistenceUnitInfo(
getClass().getSimpleName()
);
Map<String, Object> configuration = new HashMap<>();
configuration.put("hibernate.integrator_provider",
(IntegratorProvider) () -> Collections.singletonList( MetadataExtractorIntegrator.INSTANCE )
);
EntityManagerFactoryBuilderImpl entityManagerFactoryBuilder = new EntityManagerFactoryBuilderImpl(
new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration
);
return entityManagerFactoryBuilder.build();
}
Now, when running the following test:
for(Namespace namespace : MetadataExtractorIntegrator.INSTANCE
.getDatabase()
.getNamespaces()) {
for( Table table : namespace.getTables()) {
LOGGER.info( "Table {} has the following columns: {}",
table,
StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
table.getColumnIterator(),
Spliterator.ORDERED
),
false
)
.collect( Collectors.toList())
);
}
}
Hibernate outputs all the currently mapped tables in the log:
Table org.hibernate.mapping.Table(post) has the following columns: [
org.hibernate.mapping.Column(id),
org.hibernate.mapping.Column(title),
org.hibernate.mapping.Column(version)
]
Table org.hibernate.mapping.Table(post_comment) has the following columns: [
org.hibernate.mapping.Column(id),
org.hibernate.mapping.Column(review),
org.hibernate.mapping.Column(version),
org.hibernate.mapping.Column(post_id)
]
Table org.hibernate.mapping.Table(post_details) has the following columns: [
org.hibernate.mapping.Column(id),
org.hibernate.mapping.Column(created_by),
org.hibernate.mapping.Column(created_on),
org.hibernate.mapping.Column(version)
]
Table org.hibernate.mapping.Table(post_tag) has the following columns: [
org.hibernate.mapping.Column(post_id),
org.hibernate.mapping.Column(tag_id)
]
Table org.hibernate.mapping.Table(tag) has the following columns: [
org.hibernate.mapping.Column(id),
org.hibernate.mapping.Column(name),
org.hibernate.mapping.Column(version)
]
That's it!
Well finally I did it thank's to Vlad's article. I took the integrator code without any change and modified my HibernateUtil and the getColumns() method. So here's my code:
SessionFactory creation:
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
public static SessionFactory getSessionFactory() {
return buildSessionFactory();
}
private static SessionFactory buildSessionFactory() {
final BootstrapServiceRegistry bootstrapServiceRegistry = new BootstrapServiceRegistryBuilder().enableAutoClose()
.applyIntegrator(MetadataExtractorIntegrator.INSTANCE).build();
final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder(bootstrapServiceRegistry).configure().build();
return new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
}
public static Session getSession() {
Session hibernateSession = getSessionFactory().getCurrentSession();
return hibernateSession;
}
public static void shutdown() {
getSessionFactory().close();
}
}
Metadata Extractor(Get Column names):
public static List<String> getColumnNames(String tableName) {
List<String> columnList = new ArrayList<>();
for (Namespace namespace : MetadataExtractorIntegrator.INSTANCE.getDatabase().getNamespaces()) {
for (Table table : namespace.getTables()) {
if (table.getName().equalsIgnoreCase(lookupTableName)) {
Iterator<Column> iterator = table.getColumnIterator();
while (iterator.hasNext()) {
columnList.add(iterator.next().getName());
}
break;
}
}
if (!columnList.isEmpty())
break;
}
return columnList;
}
As of Hibernate - 5.4.30.Final - released March 19th, 2021
The code below works and is not deprecated :
MetamodelImplementor metaModelImpl = (MetamodelImplementor)session.getMetamodel();
Map<String, EntityPersister> entityPersisters = metaModelImpl.entityPersisters();
Collection<EntityPersister> val = entityPersisters.values();
for (EntityPersister ep : val) {
AbstractEntityPersister aep = (AbstractEntityPersister)ep;
System.out.println(aep.getTableName());
System.out.println(Arrays.toString(aep.getIdentifierColumnNames()));
for (String propName : aep.getPropertyNames()) {
System.out.println(propName);
System.out.println(Arrays.toString(aep.getPropertyColumnNames(propName)));
}
}
An easier way to get column name with hibernate 5
final AbstractEntityPersister classMetadata = (AbstractEntityPersister) sessionFactory.getClassMetadata(clazz)
final String[] names = classMetadata.getPropertyColumnNames(property)

my hibernate utill return null session factory

I'm using hibernate annotation in my program, but its getting error.
It returns no session factory that I opened. I used netbeans IDE and when I debug my program, it want to open a session and next step, it is going to InvocationTargetException.java and do not anything else.
it is my folders
enter image description here
it is my hibernate util
public class HibernatUtil {
private static final SessionFactory FACTORY;
static {
FACTORY = new AnnotationConfiguration().configure("/hibernate.cfg.xml").buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return FACTORY;
}
}
it is my class that get session factory, but getting error
public class UserDAO {
private Session session;
public boolean insert(User user){
session=HibernatUtil.getSessionFactory().getCurrentSession();
Transaction transaction=null;
String result;
try{
transaction=session.beginTransaction();
session.save(user);
transaction.commit();
result="your insert was sucssedfull";
}
catch(Exception e ){
result="your transaction was faild";
if (transaction!=null) transaction.rollback();
}
System.out.println(result);
return transaction!=null ;
}
}
and then after next step go too this class
enter image description here
Try using this HibernateUtil instead :
public class HibernateUtil {
public static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
and in your userDao use this :
private final SessionFactory sessionFactory = HibernateUtil.sessionFactory.getCurrentSession();

Hibernate: Best way of using the `SessionFactory`

I am developing a web application with pure JSP, Servlet and Hibernate. Last few days I was having a trouble with the SessionFactory of Hibernate, not knowing the best way of implementing it. In various places developers have claimed that there should be one SessionFactory for the application. So, I created a singleton class like below.
package dao;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
public class SessionFactoryBuilder
{
private static SessionFactoryBuilder instance;
private static SessionFactory sessionFactory;
private SessionFactoryBuilder()
{
buildConfig();
}
private static void buildConfig()
{
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(builder.build());
}
public static SessionFactoryBuilder getInstance()
{
if(instance == null)
{
instance = new SessionFactoryBuilder();
}
return instance;
}
public SessionFactory getSessionFactory()
{
return sessionFactory;
}
}
Below is a class which uses the SessionFactoryBuilder.
public class AgentImpl implements AgentInterface
{
SessionFactoryBuilder sessionFactory = SessionFactoryBuilder.getInstance();
#Override
public Session openCurrentSession() {
Session currentSession = sessionFactory.getSessionFactory().openSession();
return currentSession;
}
#Override
public Transaction openTransaction(Session session) {
Transaction beginTransaction = session.beginTransaction();
return beginTransaction;
}
#Override
public void save(Agent entity, Session session) {
session.save(entity);
}
#Override
public void update(Agent entity, Session session) {
session.update(entity);
}
}
Now my question is, is this is the best way of using the SessionFactory ? This might sound like a silly question but it will not when you think about multi threaded behavior in servlets, Driver#Connect error happening because of incorrect usage of session factory, various ways of implementing the singleton pattern and so on. Please provide me your advice.

Hibernate 4.3.0.Final get session

In the hibernate documentation for version 4.3.0.Final the following code snippet is given to create a SessionFactory:
package org.hibernate.tutorial.util;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure().buildSessionFactory();
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
This seems to be outdated, as the method buildSessionFactory() is deprecated. What is the correct way to create the SessionFactory?
public class TestHB4 {
private static StandardServiceRegistry serviceRegistry;
private static SessionFactory sessionFactory;
public static void main(String[] args) {
Person person = new Person();
person.setFirstName("Namal");
person.setLastName("Dinesh");
Configuration configuration = new Configuration().configure();
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.configure().buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(person);
session.getTransaction().commit();
session.close();
}

Categories

Resources