#PostConstruct and "No Hibernate Session bound to thread" exception - java

I have to do some database stuff in my repository' #PostConstruct:
#Repository
public class SomeRepositoryHibernate implements SomeRepository {
private SessionFactory sessionFactory;
#Autowired
public SomeRepositoryHibernate(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
...
#PostConstruct
public void doSomestuffWithDb() {
...
}
}
but it fails with:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and
configuration does not allow creation of non-transactional one here
is there any easy solution for that?
Thanks!

You don't have a running transaction in #PostConstruct
you can't use #Transactional there (except for mode="aspectj"), so spring can't start the transaction
a transaction is required for hibernate to mutate data (insert/update/delete)
So, you would have to create your session from the session factory (via .openSession()) there and start a transaction manually.

assuming you are using hibernate combining with spring and you have configured your sessionFactory and transaction manager correctly in your spring config file.
Then the root cause is that when your doSomestuffWithDb() method is invoked the transaction prepare work has not been finished by spring. The #postconstruct can only ensure the method is called after the bean is created, it can not ensure the container is ready for everything- here, I mean the transaction related stuff- at the moment.
There is a detailed discussion in spring forum.
http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct
Also, the author submitted his solution to jira at
https://jira.springsource.org/browse/SPR-5966?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel#issue-tabs

Related

Perform native SQL Query during Spring startup

I'm using Spring and Hibernate with an automatically generated database (for that I have set "hibernate.hbm2ddl.auto" to "update" in the JPA configuration properties).
I also have a class annotated #Configuration with a #PostConstruct method that is called on application startup after the database has been created or updated. This is where I setup the database with some default data if it's empty (first launch).
I would like to execute some custom native SQL queries at this moment. These queries won't return anything, they're just configuration stuff (like creating additional indexes or extensions).
Currently I'm stuck on creating a SessionFactory in order to create a new Hibernate Session. I've tried auto wiring it, but it doesn't work :
#Autowired
SessionFactory sessionFactory;
Gives me: Field sessionFactory in ... required a bean of type 'org.hibernate.SessionFactory' that could not be found.
I understand that I probably need to configure it elsewhere, but I don't know where. Several answers on SO use an xml configuration file, but I'm not using any configuration file so I can't do it that way.
Is there a way Spring can create the SessionFactory with the appropriate configuration ?
You don't even need to access SessionFactory. Please just put your scripts into a file src/main/resources/scripts/myscript.sql. You can then do the following with Spring:
#Component
public class Startup {
#Autowired
private DataSource dataSource;
#PostConstruct
public void runNativeSql() {
ClassPathResource resource = new ClassPathResource("scripts/myscript.sql");
try(Connection connection = dataSource.getConnection()) {
ScriptUtils.executeSqlScript(connection, resource);
} catch (SQLException | ScriptException e) {
//LOG
}
}
}
You can autowire the JPA EntityManager as:
#PersistenceContext
EntityManager entityManager;
If you really need a Hibernate Session and are using using JPA 2.1, the Session can be obtained from the EntityManager as:
entityManager.unwrap(Session.class);

Spring transactions, EntityManager lifecycle

I am developing a project with spring framework.
I have following architecture: all database code is in dao classes, all application logic is in service classes, http requests are processed using spring mvc rest controllers.
#Repository
public class UserDao {
#PersistenceContext
private EntityManager em;
public void editUser(User user) {
...
}
}
#Service
public class UserService {
#Autowired
private UserDao userDao;
#Transactional
public void editUser(User user) {
...
}
}
#RestController
#RequestMapping(value = "/UserCtrl", produces = "application/json;charset=UTF-8")
public class UserCtrl {
private static final Logger logger = LogManager.getLogger(AppConfig.LOGGER_NAME);
#Autowired
private ApplicationContext appContext;
#RequestMapping(value = "/editUser")
public ActionResult editUser(#ModelAttribute User user) {
ActionResult rslt = new ActionResult();
try {
UserService userService = appContext.getBean(UserService.class);
userService.editUser(user);
rslt.setSuccess(true);
} catch (Exception ex) {
logger.error("editUser", ex);
rslt.setSuccess(false);
}
return rslt;
}
}
This code works correctly.
One thing I cannot understand is how aop proxy of UserService bean starts transaction, when EntityManager is injected only in UserDao class. Can somebody explain me how this works and how EntityManager lifecycle is managed by spring framework ?
Any help appreciated.
The TransactionManager is responsible for managing the transaction boundaries
in Spring Framework.
When you annotate the business method with #Transactional you are instrumenting the method with an aspect.
Before executing the method, this aspect interact with TransactionManager which decides if it is necessary to create a new Transaction or use a preexisting one. In the case of create a new Transaction, a new Entity Manager is created from EntityManagerFactory and is associated to the current thread alonside with the Transaction.
The EntityManager is responsible to iterate with the database. When you inject it with #PersistenceContext, Spring injects an proxy to the EntityManager.
Whenever an operation is executed in the EntityManager proxy it looks the EntityManager associated with the thread.
Based on the snippet of code you provide you are using spring with some implementation of JPA you are using J2EE container for your web application and bases on my guess I think this is good article about how things works.
Basic concepts :
EntityManager - A class that manages the persistent state(or lifecycle) of an entity.
Persistence Unit - is a named configuration of entity classes.
Persistence Context - is a managed set of entity instances. The entities classes are part of the Persistence Unit configurations.
Managed Entities - an entity instance is managed if it is part of a persistence context and that Entity Manager can act upon it.
Based on this article you use Container Managed EntityManager by using #PersistenceContext
When a container of the application(be it a Java EE container or any other custom container like Spring) manages the lifecycle of the Entity Manager, the Entity Manager is said to be Container Managed. The most common way of acquiring a Container Managed EntityManager is to use #PersistenceContext annotation on an EntityManager attribute.
And the injection is like this :
A Transaction Scoped Entity Manager is returned whenever a reference created by #PersistenceContext is resolved.
and
Every time an operation is invoked on an Entity Manager, the container proxy(the container creates a proxy around the entity manager while instantiating it ) checks for any existing Persistence Context on the JTA Transaction. If it finds one, the Entity Manager will use this Persistence Context. If it doesnt find one, then it will create a new Persistence Context and associates it with the transaction.
So the lifecycle of of entity manager is managed by your container and
we work with an instance of EntityManager, the only role of EntityManager is to determine the lifetime of the Persistence Context. It plays no role in dictating how a Persistence Context should behave. To reiterate, Persistence Context is a managed set of Entity instances. Whenever a transaction begins, a Persistence Context instance gets associated with it. And when a Transaction ends(commits for example), the Persistence Context is flushed and get disassociated with the transaction.
In the nutshell container instantiate your EntityManager by the EntityManagerFactory you provide and manage it's lifecycle but inject the proxy of EntityManager for you. The TransactionManager is responsible for creating, commiting and ... tranactions based on annotations you provide ,whenever it begins the transaction the PersistancecContext associated with it and when the tranasction ends it commites the state of PersistenceContext. The EntityManager works with PersistenceContext and if it's not provided the EntityManager creates one. The EntityManager is threadsafe as long as it holds no state and the state (PersistenceContext) is attached to current tranasction.
Hope this helps.

Why is my StatelessSession asking for a container transaction?

I have a runnable task as follows
#TransactionManagement(TransactionManagementType.BEAN)
#TransactionAttribute(TransactionAttributeType.NEVER)
public class Task implements Runnable {
private SessionFactory sessionFactory;
public Task(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public void run() {
StatelessSession session = sessionFactory.openStatelessSession();
session.beginTransaction();
// ... the rest is irelevant because beginTransaction launches an exception
SessionFactory is supplied by a bean but when I try to begin the transaction, even tough I marked the class as TransactionAttributeType.NEVER, hibernate launches the exception
org.hibernate.TransactionException: Could not register synchronization for container transaction
I tried this but I only got another problem
org.hibernate.TransactionException: Could not find UserTransaction in JNDI [java:comp/UserTransaction]
Stateless session do not require transactions, remove the transaction statements ant try. You can read up more here
A stateless session does not implement a first-level cache nor
interact with any second-level cache, nor does it implement
transactional write-behind or automatic dirty checking, nor do
operations cascade to associated instances.

Spring - "late binding" autowired beans

Let's say I have the following dependencies:
#Configuration
public class MyCfg {
// ...
#Bean
public Session session() {
return sessionFactory().getCurrentSession();
}
}
#Repository
#Transactional
public class MyRepo {
#Autowired
private Session session;
}
sessionFactory() is set up properly. If I inject SessionFactory instead of Session, it works just fine. However, if try and inject Session, it dies with an exception on container bootstrap because there is no session bound to thread.
Since the repository is #Transactional, I know that at run time there will be a session. How can I make it work, so that it injects AOP-initialized Session at run time, but does not try and resolve it when the repo is instantiated?
I would take a look at this bit of Spring documentation regarding bean scopes. Near the bottom they show how to use the #Scope annotation, which you will want to apply to your session() method in MyCfg. It sounds like you would want to use the 'request' value, which will create a new instance of this bean for each HTTP request coming in.
I will also suggest taking a look at the <aop:scoped-proxy/> element for configuration. It is mentioned a couple times in the documentation, and may be useful for what you are trying to do.
This approach will get you into a lot of trouble. Instead of injecting a Session, which you now automatically scopes as a singleton, you should inject the SessionFactory instead. Instances of Session acquired within a #Transactional annotated method will adhere to those transaction rules, eg:
#Transactional(readonly=true)
public List<Person> getPersons() {
Session session = sessionFactory.getCurrentSession();
//find those darn people.
}
#Autowired
private SessionFactory sessionFactory;

Test Hibernate + Spring from public static void main

I'm Spring and Hibernate newbie.
I've created the entity User and DAO - UserHibernateDao.
I want to test how the hibernate working in simple java-class with public static void main:
public class Starter {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("/org/jtalks/jcommune/model/entity/applicationContext-dao.xml");
Dao<User> uhd = (Dao) context.getBean("userDao");
User user = new User();
user.setNickName("UserName");
uhd.saveOrUpdate(user);
}
}
but I get the error
INFO: Using DataSource [org.springframework.jdbc.datasource.DriverManagerDataSource#17b4703] of Hibernate SessionFactory for HibernateTransactionManager
Exception in thread "main" org.springframework.orm.hibernate3.HibernateSystemException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here; nested exception is org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:679)
I understand I need to create something like session and transaction but I don't know how exactly I should do this.
my config
User.java
UserHibernateDao.java
Full Project
Thanks
Add the #Transactional annotation to your DAO's method.
That will initiate the transactional context.
import org.springframework.transaction.annotation.Transactional;
#Transactional
public User getUser(int id) {
..
}
I'd suggest you read this reference on Spring and Transaction Management as it will help you understand how to set this all up.

Categories

Resources