I'm using Hibernate withhout #annotations
I tried this code:
public class HibernateUtil {
private static final SessionFactory sessionFactory;
private static StandardServiceRegistryBuilder builder;
static {
try {
Configuration configuration = new Configuration().configure();
configuration.configure("hibernate.cfg.xml");
builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(builder.build());
} catch (HibernateException ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
Client code:
public static void main (String[] args) {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
List<Customer> customers = criteria.list();
for (Customer customer : customers) {
//print values
}
session.getTransaction().commit();
session.close();
}
Also here is important thing I want to know
What if I will create HibernateUtil class object in Client class?
HibernateUtil hibernateUtil = new HibernateUtil();
You can refer stackoverflow link:
What are the advantages and disadvantages of creating an Object in static block in Java?.
If you want SessionFactory to be created when your server or application starts, then static block can be used. else, go for static method approach. You can also use enums to create singleton.
So, you've got two questions there, one about this being the right approach to create a singleton, and the other about what happens if you create a HibernateUtil instance in the client.
First for the HibernateUtil
For the second question, you're fine if each client creates an instance of the HibernateUtil class, as the variable is static. If all goes according to plan, there will only be one Hibernate SessionFactory instance.
As for whether you have a correct Hibernate SessionFactory singleton implementation? That's a harder question to answer. While your code looks good, multiple classloaders can cause all sorts of unpredictable problems with singletons. If separate classloaders create an instance, you may have multiple instances of your singleton, a paradox you want to avoid.
EJB and Spring Singleton help
With the EJB specification, you can mark a session bean as a singleton. If you are using a Java web profile compliant server, I'd do that. If you are using Spring Boot, use the singleton facilities they provide. If it's a standalone application, keep an eye out for peculiar, non-singleton SessionFactory behavior.
Related
I am new to Hibernate and Spring.
I am trying to access data in Mysql using Hibernate Framework. But I feel confused which class to use to retrieve object.
Let me give examples. I found in some online tutorials and websites,
1 . Using HibernateTemplate as an interface to access Data
Using Persistence
EntityManagerFactory entityManagerFactory = Persistence
.createEntityManagerFactory("pl.edu.bogdan.training.db.entity");
EntityManager em = entityManagerFactory.createEntityManager();
Using SessionFactory
package com.journaldev.dao;
import java.util.List;
import org.hibernate.*;
import com.journaldev.model.Person;
public class PersonDAOImpl implements PersonDAO {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Override
public void save(Person p) {
Session session = this.sessionFactory.openSession();
Transaction tx = session.beginTransaction();
session.persist(p);
tx.commit();
session.close();
}}
Could you please guide me in right way. Thanks
They're pretty much equivalent, at this point the only difference is the amount of code you need to write to access data.
Further you may need to fine-tune your queries. For example using Transaction tx = session.beginTransaction(); helps you control, which data manipulation / querying occurs within transaction, so that you don't hold connection to database too long. If you only need to save some entity, you may as well annotate the method of your bean with #Transactional.
I just got through the book "Just Hibernate" from O'Reilly. Some code isn't really explained fully but just given without complete description.
This code for example:
public class BasicMovieManager {
private SessionFactory sessionFactory = null;
// Creating SessionFactory using 4.2 version of Hibernate
private void initSessionFactory(){
Configuration config = new Configuration().configure();
// Build a Registry with our configuration properties
ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(
config.getProperties()).buildServiceRegistry();
// create the session factory
sessionFactory = config.buildSessionFactory(serviceRegistry);
}
...
}
I just wanted to copy the code to my Hibernate-experiments, but the current stable Hibernate-version 5.2 doesn't know the class ServiceRegistryBuilder. What is a service-registry and how do I have to change the code to work with the current Hibernate-version?
The code was used to create a SessionFactory with Hibernate 4.x
The similar code for Hibernate 5.x would be something like:
StandardServiceRegistry standardRegistry =
new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build();
Metadata metaData =
new MetadataSources(standardRegistry).getMetadataBuilder().build();
sessionFactory = metaData.getSessionFactoryBuilder().build();
As you can see, in Hibernate 5 StandardServiceRegistry class is used. If you don't have a hibernate.cfg.xml file just use configure() method with no arguments.
See this article for further details.
I am learning Hibernate now and I need help to understand how Sessions work. I have some methods in a class which I have given below.
I see there is a getCurrentSession() in SessionFactory class. So, it seems that only one Session can be "active" inside a SessionFactory. Is this SessionFactory like
a queue of transactions where the transactions are completed in in order ? If yes, then
is it possible to promote a transaction to a higher or lower priority ?
private static SessionFactory factory;
//Get a hibernate session.
public static Session getSession(){
if(factory == null){
Configuration config = HibernateUtil.getConfiguration();
factory = config.buildSessionFactory();
}
Session hibernateSession = factory.getCurrentSession();
return hibernateSession;
}
public static void commitTransaction(){
HibernateUtil.getSession().getTransaction().commit();
}
public static void rollbackTransaction(){
HibernateUtil.getSession().getTransaction().rollback();
}
And some more methods that use getTransaction().
SessionFactory's job is to hide the session creation strategy. For example, in a web application, you probably want the SessionFactory to return create a Session the first time getCurrentSession() is called on a thread, and then return the same Session from that point forward for the duration of the request. (Since you probably want to load customer data from that session, then maybe modify their account in that same session.) Other times, you may want SessionFactory to create a brand new session every time you call getCurrentSession(). So by hiding this decision behind the SessionFactory API, you simply write code that gets the Session from the factory and operates on it.
The Session is what handles transactions. As you probably expect, transactions are started in a Session, and then either complete or rollback. There is really no way to prioritize them since once they are started, you are committed to either rolling it back or committing it.
Maybe what I´m going to ask it´s a silly question, what I wan to know if it is possible in a Spring MVC configuration has two entityManagerFactory. I will explain why.
I have one LocalContainerEntityManagerFactoryBean where I configure a hibernate.tenant_identifier_resolver which I use to determine the tenant by LDAP using the session of the user, and then use one database Schema or another, then I use "multi_tenant_connection_provider" to create the database connection for that schema.
Now my application has a Scheduler that needs access to all Schemas and get some information from all databases. So in order to do not touch the entityManagerFactory already configure, what I was thinking was to create a new one with my own implementation of "hibernate.tenant_identifier_resolver" to control which schema I want instead LDAP, before create the database connection by "multi_tenant_connection_provider".
the problem looks like Spring do not allow me configure two entityManagerFactory.
Can you give me any advice about how to achieve what I want?
Regards!
Yes, it is possible to use multiple EntityManagers.
In my project I use the annotation configuration, where I have:
#Configuration
#EnableTransactionManagement
public class AppConfig {
#Bean
public SessionFactory smartDataSessionFactory() {
return new LocalSessionFactoryBuilder(smartDataDatasource())
.scanPackages("...)
.addProperties(smartDataHibernateProperties())
.buildSessionFactory();
}
#Bean
public SessionFactory analysisSessionFactory() {
return new LocalSessionFactoryBuilder(analysisDatasource())
.scanPackages("...)
.addProperties(analysisHibernateProperties())
.buildSessionFactory();
}
...
}
When referencing the entityManagers, be sure to use the Qualifier annotation.
Also note that each SessionFactory will use it's own TransactionFactory
#Repository
#Transactional(value = "analysisTransactionManager")
public class ToURemunerationDaoImpl implements ToURemunerationDao {
private SessionFactory analysisSessionFactory;
private SessionFactory smartDataSessionFactory;
#Autowired
#Qualifier("analysisSessionFactory")
public void setAnalysisSessionFactory(SessionFactory sessionFactory) {
this.analysisSessionFactory = sessionFactory;
}
#Autowired
#Qualifier("smartDataSessionFactory")
public void setSmartDataSessionFactory(SessionFactory sessionFactory) {
this.smartDataSessionFactory = sessionFactory;
}
...
}
Finally I found the solution. The issue was becuase I´m using Spring data, and my repositories did not which EntityManagerFactory use. As soon as I specify which one to use during the scan everything works like a charm.
<repositories base-package="com.*.*.repository**" entity-manager-factory-ref="entityManagerFactory"/>
I have been learning to use hibernate for a couple of months.
I am finding it difficult in deciding how to configure hibernate to work on a test database.
I have a hibernate.cfg.xml with db parameters given as elements.
<property name="connection.url">
jdbc:postgresql://localhost/mydb
</property>
<property name="connection.username">me</property>
<property name="connection.password">mypasswd</property>
My web app uses a HibernateUtil class which loads the configuration as below
class HibernateUtil {
private Class<T> persistentClass;
private static SessionFactory sessionFactory;
static {
try {
sessionFactory = new Configuration().configure().buildSessionFactory();
}catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
...
My dao implementation uses the above class to get the Session
public class BaseDaoImpl<T, ID extends Serializable>{
private Session session;
...
public Session getSession() {
if (session == null || !session.isOpen()){
return HibernateUtil.getCurrentSession();
}else{
return session;
}
}
public T findById(ID id){
T entity = (T) getSession().load(getPersistentClass(), id);
return entity;
}
This is OK as long as I work on the mydb configured in cfg.xml file.But for my tests I am using another database which is given in a test.properties file
test.db.url=jdbc:postgresql://localhost/mytestdb
test.db.driver=org.postgresql.Driver
test.db.username=testme
test.db.password=testpass
The only way I can make hibernate work on mytestdb is to manually replace every db related property in cfg.xml.I would very much like to use test_hibernate.cfg.xml with the test db properties,but since the configuration is done in a static block in HibernateUtil ,that won't work.
Is there a better way of configuring hibernate for these two databases?
I am using ant as build tool..
Any suggestions would be most welcome
jim
I would very much like to use test_hibernate.cfg.xml with the test db properties,but since the configuration is done in a static block in HibernateUtil
So then don't create your configuration in a static block.
Instead, create a class which accepts a parameter for the path to the configuration file (a la Spring's LocalSessionFactoryBean) which returns the Configuration/SessionFactory to use. Or if you truly want to stick with HibernateUtil (which is a strategy very much recommended against in any production setting), change it to read a property or system environment variable to read the configuration.