Creating sessionFactory in Hql-Initialization - java

I have create a dbadapter for delaing with hibernate.Actually my class looks like this..
public class DBAdapter {
private static SessionFactory factory;
private static final ThreadLocal<Session> threadSession = new ThreadLocal();
public static Session OpenConnection() {
if (factory == null) {
factory = new Configuration().configure(
"com/et/hibernatexml/hibernate.cfg.xml")
.buildSessionFactory();
}
Session s = (Session) threadSession.get();
if (s == null)
{
s =factory.openSession();
threadSession.set(s);
}
return s;
}
public List selectQuery(String QueryString)
{ try
{
Session session=OpenConnection();
resultlist = query.list();
}
finally()
{
closeSession();
}
}
public static void closeSession()
{
Session session = (Session) threadSession.get();
threadSession.set(null);
if (session != null && session.isOpen()) {
session.flush();
session.close();
}
}
For getting data from server ,i will do like this..
DBAdapter ob=new DBAdapter();
ob.setParameter("orgId", orgId);
List list=ob.selectQuery(queryvalue);
My doubt is any issue by dealing like this.Especially because SessionFactory is static variable??

You do not want more than one threads to create a session factory. It should be a singleton and is by design thread safe. The easiest way to do this with the code you provided is to use the synchronized keyword on the openConnection() method. However, there is no reason to synchronize the part of the code where you create a session and put it on the ThreadLocal instance as well. A rough solution would be like the following
public class DBAdapter {
private static SessionFactory factory;
private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
private static synchronized SessionFactory getSessionFactory() {
if(factory == null) {
factory = new Configuration().configure("com/et/hibernatexml/hibernate.cfg.xml").buildSessionFactory();
}
return factory;
}
public static Session getSession() {
Session s = (Session) threadSession.get();
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
return s;
}
}

Related

Hibernate Junit H2 In memory database test case changing fields in the development db

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;

Java hibernate declared connection effective

This is the command to display information data sheet, I see the declaration it is repeated
CODE 1
public class DBTable {
public List<MdGmail> showGmail() {
Configuration conf = new Configuration().configure("hibernate.cfg.xml");
SessionFactory sf = conf.buildSessionFactory();
currentSession = sf.getCurrentSession();
currentSession.beginTransaction();
return currentSession.createCriteria(MdGmail.class).list();
}
public List<MdBlogger> showBlogger() {
Configuration conf = new Configuration().configure("hibernate.cfg.xml");
SessionFactory sf = conf.buildSessionFactory();
currentSession = sf.getCurrentSession();
currentSession.beginTransaction();
return currentSession.createCriteria(MdBlogger.class).list();
}
}
In my class DBTable,I create a list function to display data table in a database as table gmail,order...
With the first code 1 need to rewrite the declaration for each function, so what I want is to create a connection function for all with code 2
But with the way this declaration it will not update the value was changed in the database
CODE 2
public class DBTable {
private static final Configuration conf = new Configuration().configure("hibernate.cfg.xml");
private static final SessionFactory sf = conf.buildSessionFactory();
private static Session currentSession;
public DBTable() {
currentSession = sf.getCurrentSession();
currentSession.beginTransaction();
}
private static DBTable instance = null;
public static DBTable getInstance() {
if (instance == null) {
instance = new DBTable();
}
return instance;
}
public List<MdGmail> showTableGmail() {
return currentSession.createCriteria(MdGmail.class).list();
}
public List<MdGmail> showTableOrder() {
return currentSession.createCriteria(MdGmail.class).list();
}
}
And if use new additional data function, the connection will be closed and command data showing that my table would stop working.Please help me
public boolean saveOrUpdateGmail(MdGmail table) {
try {
currentSession.saveOrUpdate(table);
currentSession.getTransaction().commit();
return true;
} catch (Exception e) {
currentSession.getTransaction().rollback();
e.printStackTrace();
return false;
}
}
The simplest strategy of using Hibernate is open a session (or get current one), begin a transaction, do request, commit, and close a session for every operation (showTableGmail, saveOrUpdateGmail). So you need to delete all code from DBTable() constructor and do something like this.

Hibernate SessionFactory and could not obtain transaction-synchronized session for current thread

I know this question has been asked before however none of the solutions have worked for me.
I am trying to hit a controller to populate an index. The issue arises when I try and search the database for updates.
Here is are the classes I am dealing with:
Configuration:
#Configuration
#EnableTransactionManagement
public class WebApplication implements WebApplicationContextInitializer, ApplicationContextAware {
#Bean(name="dataSource")
public DataSource getDataSource() throws IOException {
InitialContext initialContext = new Context();
return (DataSource) initialContext.lookup("java:comp/env/jdbc/myDataSource");
}
#Bean(name="sessionFactory")
public SessionFactory getSessionFactory() throws IOException {
LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(getDataSource());
sessionBuilder.scanPackages(PropertyUtil.getInstance().getPropertySplitTrimmed("hibernate", "packagesToScan"));
sessionBuilder.addProperties(PropertyUtil.getInstance().getProperties("hibernate"));
return sessionBuilder.buildSessionFactory();
}
#Bean(name="transactionManager")
public HibernateTransactionManager transactionManager() throws IOException {
return new HibernateTransactionManager(getSessionFactory());
}
}
Controller:
#RestController
#Transactional
#RequestMapping("/persons")
public class IndexController {
#Autowired
PersonsDao personsDoa;
private ExecutorService executorService = Executors.newFixedThreadPool(100);
#RequestMapping(value="/index")
public void populateIndex(#DefaultValue("") #RequestParam String name){
...
...
List<Future<Persons>> holder = new ArrayList<>();
for(Persons p : people){
String name = p.name();
Future<Person> f = this.executorService.submit(new Callable<Person>(){
#Override
public Person call() throws Exception {
return personsDao.findByName(name); // <-- Throws error here
}
});
holder.add(f); // process the array later once all threads are finished
}
...
...
}
}
UPDATE: I've updated my Controller according to some suggestions, however I am still receiving the same error
Controller:
#RestController
#Transactional
#RequestMapping("/persons")
public class IndexController {
#Autowired
PersonsDao personsDoa;
private ExecutorService executorService = Executors.newFixedThreadPool(100);
#RequestMapping(value="/index")
public void populateIndex(#DefaultValue("") #RequestParam String name){
...
...
List<Future<Persons>> holder = new ArrayList<>();
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(sessionFactory.getCurrentSession())); //<-- THROWS ERROR HERE
for(Persons p : people){
String name = p.name();
Future<Person> f = this.executorService.submit(new Callable<Person>(){
SessionHolder holder = (SessionHolder)TransactionSynchronizationManager.getResources(sessionFactory);
Session session = holder.getSession();
#Override
public Person call() throws Exception {
Transaction t = session.getTransaction();
t.begin();
Persons p = personsDao.findByName(name);
t.commit();
session.flush();
return p;
}
});
holder.add(f); // process the array later once all threads are finished
}
...
...
}
}
Usualy the request thread use only one shared Session, this session is binded at the start of the request, and unbinded at the end of the request, but given you want to use it in another thread, we must :
1_ prevent the session from being closed from the Request Thread.
2_ bind this session to the new thread, to offer the TransactionManager to works with same Session.
First the current Session must not be closed, so if you are using the OpenInViewFilter, you need to add a method before calling the new Thread.
OpenEntityManagerInViewFilter.getCurrent().keepEmfOpen(request);
Then inside the Thread you need to attach the current session.
public void attachThread() {// this must bind the session to this thread.
OpenEntityManagerInViewFilter.getCurrent().registerEmfs(request, session);
}
private boolean registerEmf(String key, ServletRequest request, EntityManagerFactory emf){
if (emf == null)
return true;
if (TransactionSynchronizationManager.hasResource(emf))
return true;
else {
boolean isFirstRequest = true;
WebAsyncManager asyncManager = null;
if (request!=null){
asyncManager = WebAsyncUtils.getAsyncManager(request);
isFirstRequest = !(request instanceof HttpServletRequest) || !isAsyncDispatch((HttpServletRequest) request);
}
if (emf.isOpen())
if (isFirstRequest || !applyEntityManagerBindingInterceptor(asyncManager, key)) {
logger.debug("Opening JPA EntityManager in OpenEntityManagerInViewFilter");
try {
EntityManager em = createEntityManager( emf );
EntityManagerHolder emHolder = new EntityManagerHolder( em );
TransactionSynchronizationManager.bindResource( emf, emHolder );
if (asyncManager!=null)
asyncManager.registerCallableInterceptor( key, new EntityManagerBindingCallableInterceptor( emf, emHolder ) );
return false;
}
catch (PersistenceException ex) {
throw new DataAccessResourceFailureException("Could not create JPA EntityManager", ex);
}
}
}
return true;
}
in case of OpenSessionInViewFilter :
private void openHibernateSessionInView(){
Session session=SessionFactoryUtils.getSession(sessionFactory,true);
SessionHolder holder=new SessionHolder(session);
if (!TransactionSynchronizationManager.hasResource(sessionFactory)) {
TransactionSynchronizationManager.bindResource(sessionFactory,holder);
}
}
private void closeHibernateSessionInView(){
if (TransactionSynchronizationManager.hasResource(sessionFactory)) {
SessionHolder sessionHolder=(SessionHolder)TransactionSynchronizationManager.unbindResource(sessionFactory);
if (sessionHolder.getTransaction() != null && !sessionHolder.getTransaction().wasRolledBack() && !sessionHolder.getTransaction().wasCommitted()) {
sessionHolder.getTransaction().commit();
}
SessionFactoryUtils.closeSession(sessionHolder.getSession());
}
}

EntityManager.close() Not Closing The Connections to Database Tomcat

Here is my JPA Utill Class....
private static Logger logger=Logger.getLogger(JPAUtil.class);
private static EntityManager entityManager = null;
private static final ThreadLocal<EntityManager> threadLocal;
private static EntityManagerFactory emf = null;
static
{
try {
emf = Persistence.createEntityManagerFactory("XYZ");
threadLocal = new ThreadLocal<EntityManager>();
} catch (Throwable ex) {
logger.info("JPAUtil Exception",ex);
throw new ExceptionInInitializerError(ex);
}
}
public static EntityManager getEntityManager() {
try {
entityManager = threadLocal.get();
if (entityManager == null || !entityManager.isOpen()) {
JPAUtil.entityManager = emf.createEntityManager();
threadLocal.set(entityManager);
}else if(!emf.isOpen())
{
entityManager = threadLocal.get();
emf = Persistence.createEntityManagerFactory("XYZ");
JPAUtil.entityManager = emf.createEntityManager();
threadLocal.set(entityManager);
}
} catch (Throwable ex) {
logger.info("JPAUtil Exception",ex);
throw new ExceptionInInitializerError(ex);
}
return JPAUtil.entityManager;
}
public static void closeEntityManager() {
EntityManager entityManager = threadLocal.get();
if (entityManager != null) {
entityManager.close();
threadLocal.set(null);
}
}
public static void closeEntityManagerFactory() {
emf.close();
}
public static void commit() {
if (!entityManager.getTransaction().isActive()){
entityManager.getTransaction().begin();
}
entityManager.getTransaction().commit();
}
public static void rollback() {
if (!entityManager.getTransaction().isActive()){
entityManager.getTransaction().begin();
}
entityManager.getTransaction().rollback();
}
And After each and every transactions i am closing entitymanager....with
finally block...and later i came to Know that even in select query we need to
begin transaction and commit it...so i did try that in my application Home
page Just executing 2 select query and in the server mysql is Occupying the memory the most....with the eclipse MAT i Anallise the Memory Leak....
As per my understanding since i am using tomcat i cant do connection pooling..and we will be moving to jboss...but till the i would like to patch this....any help would be appreciated :) :)

HibernateSessionFactory class doesn't change data from database

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.

Categories