In our application we have an HibernateSessionFactory class, that is opening and closing connections. Everything is okay, but when we are updating data in the database, it doesn't change in our application. Unfortunately, we see old data from the database. How can I fix this?
public class HibernateSessionFactory {
private static final ThreadLocal threadLocal = new ThreadLocal();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
private static final Logger log = Logger.getLogger(
HibernateSessionFactory.class);
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
log.error("Error Creating SessionFactory", e);
}
}
private HibernateSessionFactory() {}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ?
sessionFactory.openSession() : null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
log.error("Error Creating SessionFactory", e);
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.flush();
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Configuration getConfiguration() {
return configuration;
}
}
.
#SuppressWarnings("unchecked")
public List<Tauthor> getAuthors() throws HibernateException {
log.debug("getting all authors");
Query queryObject = null;
List<Tauthor> authors = null;
Session session = HibernateSessionFactory.getSession();
try {
String queryString = "from Tauthor";
queryObject = session.createQuery(queryString);
authors = queryObject.list();
} catch (HibernateException e) {
log.error("get all authors failed", e);
throw e;
} finally {
HibernateSessionFactory.closeSession();
}
return authors;
}
You haven't shared your code where you write data to the database. Without that, I can think of only a few reasons as to why your data output is old instead of new data:
Your transactions are not being committed.
Hibernate hasn't written to the database at the time of data queried by you.
Hibernate's cache hasn't been updated, which results in query returning old data.
You should verify that data has been written to the Database with a db developer tool and try disabling all hibernate caching to see if the result changes.
Related
I keep waking up the morning to my site being down because of this No operations allowed after connection closed.
here is the getSession method we use :
public static Session getSession() throws HibernateException {
Session session = THREAD_LOCAL.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
THREAD_LOCAL.set(session);
}
return session;
}
Here is the closeSession
public static void closeSession() throws HibernateException {
Session session = (Session) THREAD_LOCAL.get();
THREAD_LOCAL.set(null);
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
here is the configureSessionFactory
private static SessionFactory configureSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (HibernateException e) {
e.printStackTrace();
}
return sessionFactory;
}
Here is one of our Dao function
public Client getClientInformation(int client_id) {
final Session session = HibernateUtil.getSession();
Client client = null;
try {
session.beginTransaction();
Query q = session.createQuery("FROM Client c WHERE c.id = :client_id")
.setInteger("client_id", client_id);
if (q.list().size() > 0) {
client = (Client) q.uniqueResult();
}
if (session.isOpen()) {
session.close();
}
} catch (HibernateException e) {
} finally {
HibernateUtil.closeSession();
}
return client;
}
I have developed a project using Hibernate. I am trying to test it using Junit with H2 in memory db but the test case is creating fields in the db that I am using it for development.
Here is my code :
UserDAO.java
public interface UserDAO {
public void addUser(String username, String password);
public List<String> getUsers();
}
UserDAOImpl.java
public class UserDAOImpl implements UserDAO {
public static final Logger LOG = LoggerFactory.getLogger(UserDAOImpl.class);
private static Session session;
private static void beginSession() {
session = DbUtils.getSessionFactory().openSession();
session.beginTransaction();
}
#Override
public void addUser(String username, String password) {
String encryptedPassword = Utils.encrypt(password);
User user = new User(username, encryptedPassword);
beginSession();
try {
session.save(user);
System.out.println(user.getPassword());
session.getTransaction().commit();
} catch (SQLGrammarException e) {
session.getTransaction().rollback();
LOG.error("Cannot save user", e);
} finally {
session.close();
}
}
#Override
public List<String> getUsers() {
beginSession();
List<String> results = new ArrayList<String>();
String hql = "select username from User";
Query query = null;
try {
query = session.createQuery(hql);
results = query.list();
} catch (HibernateException e) {
LOG.error("Cannot execute query", e);
}
return results;
}
}
Files for test cases
SessionFactoryRule.java
public class SessionFactoryRule implements MethodRule {
private SessionFactory sessionFactory;
private Transaction transaction;
private Session session;
#Override
public Statement apply(final Statement statement, FrameworkMethod method, Object test) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
sessionFactory = createSessionFactory();
createSession();
beginTransaction();
try {
statement.evaluate();
} finally {
shutdown();
}
}
};
}
private void shutdown() {
try {
try {
try {
transaction.rollback();
} catch (Exception ex) {
ex.printStackTrace();
}
session.close();
} catch (Exception ex) {
ex.printStackTrace();
}
sessionFactory.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
private SessionFactory createSessionFactory() {
Configuration configuration = new Configuration().configure();
configuration.addAnnotatedClass(User.class)
.addAnnotatedClass(Message.class);
configuration.setProperty("hibernate.dialect",
"org.hibernate.dialect.H2Dialect");
configuration.setProperty("hibernate.connection.driver_class",
"org.h2.Driver");
configuration.setProperty("hibernate.connection.url", "jdbc:h2:./data/db");
configuration.setProperty("hibernate.hbm2ddl.auto", "create");
SessionFactory sessionFactory = configuration.buildSessionFactory();
return sessionFactory;
}
public Session createSession() {
session = sessionFactory.openSession();
return session;
}
public void commit() {
transaction.commit();
}
public void beginTransaction() {
transaction = session.beginTransaction();
}
public Session getSession() {
return session;
}`
Here is my test case
UserDAOTest.java
public class UserDAOTest {
#Rule
public final SessionFactoryRule sf = new SessionFactoryRule();
#Test
public void testAddUser() {
Session session = sf.getSession();
UserDAOImpl userDAOImpl = new UserDAOImpl();
String username = "stackoverflow";
String password = "testing";
userDAOImpl.addUser(username, password);
}
}
This test case is updating the fields username and password in the db that I am using while development. How can I stop it and use h2 in-memory db for testing.
You have session = DbUtils.getSessionFactory().openSession() in the UserDAOImpl. This is the reason of using a development database. Your SessionFactoryRule is not used at all.
So what you can to do.
The best choice is use to Spring for Hibernate configuration and unit testing.
Other option is to set sessionFactory to the UserDAOImpl using constructor.
Also, using static here is a really very very bad idea
private static Session session;
I have hibernate query, for example get user by id:
public User findById(int id){
SessionFactory sf = HibernateUtil.getSessionFactory();
Session session = sf.openSession();
Transaction tx = null;
User user = null;
try{
tx = session.beginTransaction();
user = (User) session.get(User.class, id);
session.getTransaction().commit();
} catch(HibernateException e){
if(null != tx) tx.rollback();
System.out.println("HibernateException, transaction will be rollbacked");
} catch(Exception e){
e.printStackTrace();
}
finally {
session.close();
}
return user;
}
It's ok for one query, but i need dublicate all of this code to every query.
I need just on single code:
user = (User) session.get(User.class, id);
Is it possible to put other code to another class, method or something else?
Updated
HibernateUtil:
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new AnnotationConfiguration().configure()
.buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
It is a good practice to keep one Hibernate utility class which will have a static method to provide us the hibernate session. Moreover you can reuse the hibernate session by preventing making a new session on each query by using some simple logic.
Previously I was using the following code to configure the sessionFactory, but after upgrading the version of my hibernate from 4.2.1.Final to 4.3.4.Final, I can not retrieve sessionFactory using the following code as ServiceRegistryBuilder() is deprecated.
I used this link to create it but the provided function is not returning any thing therefore it runs into pre-compile error.
private static SessionFactory configureSessionFactory() {
try {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
} catch (HibernateException e) {
System.out.append("** Exception in SessionFactory **");
e.printStackTrace();
}
return sessionFactory;
}
static {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
private HibernateUtil() {
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() throws HibernateException {
Session session = threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession() : null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
sessionFactory = configureSessionFactory();
} catch (Exception e) {
System.err.println("%%%% Error Creating SessionFactory %%%%");
e.printStackTrace();
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
In 4.3, you should use the StandardServiceRegistryBuilder instead.
import org.hibernate.boot.registry.StandardServiceRegistryBuilder
StandardServiceRegistryBuilder was added as a new parent of ServiceRegistryBuilder. The rest of the code should be the same. The only place that I have found this documented "clearly" is in the 4.3 JavaDocs for ServiceRegistryBuilder.
One thing that I did not notice was that they changed the ServiceRegistryBuilder.buildServiceRegistry() method to just StandardServiceRegistryBuilder.build(). Therefore, it will require you to change that part of your building process:
new ServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.buildServiceRegistry();
Becomes:
new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties())
.build();
I tested this one and it works on Hibernate 4.3.6
public class HUtil{
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
public static SessionFactory createSessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder().
applySettings(configuration.getProperties()).build();
sessionFactory = configuration.configure(). buildSessionFactory(serviceRegistry);
return sessionFactory;
}
public static SessionFactory getSessionFactory() {
return createSessionFactory();
} }
Yes, they have deprecated the previous ServiceRegistryBuilder(), here is how you can do it with Hibernate 4.3.4
public void testConnection() throws Exception {
logger.info("Trying to Connect With a DataBase.");
Configuration configuration = new Configuration();
configuration.configure("Your.cfg.xml");
ServiceRegistryBuilder serviceRegistryBuilder = new ServiceRegistryBuilder().applySettings(configuration
.getProperties());
SessionFactory sessionFactory = configuration
.buildSessionFactory(serviceRegistryBuilder.buildServiceRegistry());
Session session = sessionFactory.openSession();
logger.info("Database connection created successfuly.");
}
Source: Create session factory in Hibernate 4
In our web application we have a HibernateSessionFactory class, that is opening and closing connections. Everything is okay, but when we are updating data in the database, it doesn't change in our application. Unfortunately, we see old data from the database. How can I fix it?
public class HibernateSessionFactory {
private static final ThreadLocal threadLocal = new ThreadLocal();
private static org.hibernate.SessionFactory sessionFactory;
private static Configuration configuration = new Configuration();
private static ServiceRegistry serviceRegistry;
private static final Logger log = Logger.getLogger(HibernateSessionFactory.class);
static {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties())
. buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
log.error("Error Creating SessionFactory",e);
}
}
private HibernateSessionFactory() {
}
public static Session getSession() throws HibernateException {
Session session = (Session) threadLocal.get();
if (session == null || !session.isOpen()) {
if (sessionFactory == null) {
rebuildSessionFactory();
}
session = (sessionFactory != null) ? sessionFactory.openSession()
: null;
threadLocal.set(session);
}
return session;
}
public static void rebuildSessionFactory() {
try {
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder(). applySettings(configuration.getProperties())
.buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
} catch (Exception e) {
log.error("Error Creating SessionFactory",e);
}
}
public static void closeSession() throws HibernateException {
Session session = (Session) threadLocal.get();
threadLocal.set(null);
if (session != null) {
session.flush();
session.close();
}
}
public static org.hibernate.SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Configuration getConfiguration() {
return configuration;
}
}
Hibernate is a sofisticated and complex framework for building a layer between your program and the database, providing an object oriented model to help object oriented programs in their job.
In order to do this, and to be more performat of course, it creates a cache which stores somehow some of the data coming from the database, or going to the database.
I think that this problem is NOT concerning the connection to the database but rather how you save and retrive data.
I'll try to explain my self better: when you query database to save data you do the following steps:
open session
open transaction
build object
flush and save object in session
commit transaction
close transaction
close session
eg
public Boolean saveNewCliente(Cliente c) {
Session s = getSession();
Transaction t = null;
try {
t = s.beginTransaction();
s.save(c);
s.flush();
t.commit();
s.close();
return true;
} catch (Exception e) {
if (t!=null) t.rollback();
System.out.println(e.getMessage());
return false;
}
finally{
s.close();
}
}
A common pitfall happens when you query database to fetch data, is to leave the part relating the transaction out of your "query" steps. As well for saving data you have to
open session
open transaction
build query / criteria
execute query over session
close transaction
close session
If you don't follow this steps is possible that you have stale data in your application, but not in your database. A check may be to execute your update/save-query and check manually in the database if the data has changed/created. If your application then loads stale data you know you do the fetch-query in the wrong way(without using transaction).
Here's a snipped of example
public Cliente get(Integer id) {
Session s = getSession();
Transaction tx = s.beginTransaction();
try {
System.out.println("get cliente by id");
Cliente res = new Cliente();
res = (Cliente) s.get(Cliente.class, id);
tx.commit();
return res;
} catch (Exception e) {
tx.rollback();
System.out.println(e.getMessage());
return null;
}finally{
s.close();
}
}
If you want to furthermore investigate you can suspend the usage of cache by hibernate, you can do it in the following way, but remember that if data is cached there is a reason ;)
This can be useful as a quick test in order to proceed in discovering if the error is due to wrong query usage.
You should add this to your hibernate config xml
<!-- to disable cache -->
<property name="hibernate.cache.use_second_level_cache">false</property>
<property name="hibernate.cache.use_query_cache">false</property>