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.
Related
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);
I am developing a Java application using Spring + Hibernate. i want this application to run on more then one Database on same time.
For Example if user tries to search for some data, Application has to search for that data in all the configured data-sources at a same time.
I am looking for a solution which will create different threads for each data-source and when user perform any operation all the threads needs to perform that operation
Edit 1
Let me explain my problem in detail below is my DAO class
#Repository("engineDAO")
public class EngineDAOImpl implements EngineDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void persistEngine(Engine engine, String[] DataSourceNames) {
sessionFactory.getCurrentSession().persist(engine);
}
}
Now from service class i will call persistEngine method of EngineDAO class with argument as String[] DataSourceNames so this operation needs to be performed on all the Data-sources provided as argument. What all changes i have to make for this?
Thanks in advance
You can have multiple SessionFactory or EntityManagerFactory objects, each associated with different DataSource. If you want to manage transaction across different datasources I would recommend to use JTA Transaction Manager. If your application is not running in Java EE environment, you can use some 3rd party JTA transaction manager, for example Atomikos Transaction Manager
There are some threads at Stackoverflow that discuss about this problem. Try this
Edit 1:
If you neet to select datasources by name, than your DAO can implement BeanFactoryAware and you will obtain BeanFactory object, which you can use for accessing SessionFactory beans by name.
Your code should look like something like that
#Repository("engineDAO")
public class EngineDAOImpl implements EngineDAO, BeanFactoryAware {
private org.springframework.beans.factory.BeanFactory beanFactory;
#Override
public void persistEngine(final Engine engine, final String[] sessionFactoryNames) {
for (final String sessionFactoryName : sessionFactoryNames) {
final SessionFactory sessionFactory = beanFactory.getBean(sessionFactoryName, SessionFactory.class);
sessionFactory.getCurrentSession().persist(engine);
}
}
#Override
public void setBeanFactory(final BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
In the following code, a Null pointer exception is raised when I try to call beginTransaction method. I thought that JBoss would init my transaction... apparently not :\
What am I missing ?
JBoss 5.1.0.GA
JPA 1
JDK 6
import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.transaction.UserTransaction;
public abstract class AbstractDAO {
#PersistenceUnit(unitName = "miniDS")
protected static EntityManagerFactory emf;
#Resource
protected UserTransaction t;
public AbstractDAO() {
}
protected void beginTransaction() throws Throwable {
t.begin();
}
protected void commitTransaction() throws Throwable {
t.commit();
}
protected void rollbackTransaction() throws Throwable {
t.rollback();
}
}
Your AbstractDAO does not seem to be managed. Injection only works in container managed objects. This is not specific to injection of UserTransaction, but injection in general. As result emf is null as well. Java EE specification lists following classes to be able to use injection:
Servlet: servlets, servlet filters, event listeners
JSP: tag handlers, tag library event listeners
JSF: scoped managed beans
JAX-WS: service endpoints, handlers
EJB: beans, interceptors
Managed Beans: managed beans
CDI: CDI-style managed beans, decorators
Java EE Platform: main class (static), login callback handler
Possible workaround are to move injection of resources to managed class or use JNDI lookup.
Your concrete class ConcreteDAO which extends AbstractDAO, should be an ejb, as said by Mikko Maunu and should manage itself transaction (beans that manage transaction themselves BMT), in other words:
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class ConcreteDAO extends AbstractDAO {
...
}
And it be better if you inject EntityManager in your AbstractDAO, and configure JBOSS datasource to manage transaction (local-tx-datasource or xa-datasource).
you can look at JBOSS DS config at:
https://community.jboss.org/wiki/ConfigDataSources
if you want to manage transaction yourself through EntityManager, with entityManagerFactory
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
you can't use UserTransaction and the JBoss DS should be no-tx-datasource
If you inject your persistence unit, try to get the transaction through the EntityManager.
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
For more information, have a look here: https://github.com/wicketstuff/core/wiki/How-to-use-#PersistenceUnit-annotation
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;
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