Access SessionFactory from Spring Boot Application - spring

I am trying to get access to the Hibernate session factory but am getting the following error at the line mentioned.
No CurrentSessionContext configured!
code
#Service
#Transactional
public class GenericSearchImpl implements GenericSearch {
#Autowired
private EntityManagerFactory entityManagerFactory;
#Override
#SuppressWarnings("unchecked")
public <T> List<T> search(final Class<T> type, final String[] criteriaList, final int page, final int perPage) {
Session session = getSession();
...
}
public Session getSession() {
final HibernateEntityManagerFactory emFactory = (HibernateEntityManagerFactory) entityManagerFactory;
final SessionFactory sessionFactory = emFactory.getSessionFactory();
return sessionFactory.getCurrentSession(); //ERROR No CurrentSessionContext configured!
//This worked but I understand it to be BAD as spring should be managing open sessions.
// try {
// return sessionFactory.getCurrentSession();
// } catch (Exception e) {
// return sessionFactory.openSession();
// }
}
...
}
Any idea why?

In property file,
spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
in configuration class
#Bean
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
Then you can autowire
#Autowired
private SessionFactory sessionFactory;
We do this as Spring boot doesn't auto configure hibernate sessinoFactory.
Update: As of Spring 4.3.12 and Hibernate 5.2, above Hibernate API solution is depreciated in favor of generic JPA API solution EntityManagerFactory.
Session session = entityManager.unwrap(Session.class);
Here is some detailed example doc with examples on EntityManagerFactory.

You can access SessionFactory with entityManagerFactory unwrap method instead of HibernateJpaSessionFactoryBean
SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
HibernateJpaSessionFactoryBean is deprecated in Spring Boot 1.5.8

Related

Spring Boot + Neo4j get GraphDatabaseService bean?

Using the new-style (Spring Data Neo4j 4.1.2.RELEASE) Neo4jConfiguration can I get a reference to the underlying embedded GraphDatabaseService to pass to the web ui?
New style config:
#Configuration
#EnableNeo4jRepositories(basePackages = "fu.bar")
#EnableTransactionManagement
public class Neo4j extends Neo4jConfiguration {
#Bean
#Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON, proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
#Bean
public org.neo4j.ogm.config.Configuration getConfiguration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config.driverConfiguration()
.setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver")
.setURI("file:///var/tmp/graph.db");
return config;
}
#Bean
public SessionFactory getSessionFactory() {
SessionFactory sessionFactory = new SessionFactory(getConfiguration(), "fu.bar");
return sessionFactory;
}
I'm not seeing anything in the Javadoc that helps but I suspect Boot has an instance someplace.
Thanks.
If you're using the embedded driver, the GraphDatabaseService can be obtained as follows:
EmbeddedDriver embeddedDriver = (EmbeddedDriver) Components.driver();
GraphDatabaseService databaseService = embeddedDriver.getGraphDatabaseService();
With HTTP, direct access to the database can be achieved with:
String uri = Components.driver().getConfiguration().getURI() +
"/db/data/index/node/" + indexName;
HttpPost httpPost = new HttpPost(uri);
These examples come from the section on indexes of the Spring Data Neo4j reference guide.

Spring 4 with JPA (Hibernate implementation): Transaction not working (no transaction in progress)

Ok, this looks to be a repeated question, however, I have been searching for this over 2 days and no success. Below are the configuration details:
Annotated App Config class
#Configuration
#ComponentScan(basePackages = "com.test")
#EnableTransactionManagement(mode=AdviceMode.PROXY, proxyTargetClass=true)
public class AnnotatedAppConfig {
private static final Logger _logger = Logger
.getLogger(AnnotatedAppConfig.class);
#Bean
public DataSource dataSource() {
// C3P0 datasource configuration
final ComboPooledDataSource dataSource = new ComboPooledDataSource();
try {
dataSource.setDriverClass(ReaderUtil.getInstance()
.getProperty(IConst.DB_DRIVER));
} catch (PropertyVetoException e) {
_logger.error("Error setting driver class ", e);
}
dataSource.setUser(ReaderUtil.getInstance().getProperty(
IConst.DB_USER));
dataSource.setPassword(ReaderUtil.getInstance().getProperty(
IConst.DB_PASSWORD));
dataSource.setJdbcUrl(ReaderUtil.getInstance().getProperty(
IConst.DB_URL));
_logger.info("Datasource created successfully");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceUnitName("testunit");
entityManagerFactoryBean.setJpaVendorAdapter(createJPAVendorAdapter());
_logger.info("EntityManagerFactory created successfully");
return entityManagerFactoryBean;
}
#Bean
public PlatformTransactionManager txManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory()
.getObject());
transactionManager.setDataSource(dataSource());
_logger.info("Transaction Manager created successfully");
return transactionManager;
}
private HibernateJpaVendorAdapter createJPAVendorAdapter() {
final HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setShowSql(true);
jpaVendorAdapter.setGenerateDdl(false);
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setDatabasePlatform(ReaderUtil.getInstance()
.getProperty(IConst.HIBERNATE_DB_DIALECT));
return jpaVendorAdapter;
}
}
Annotated Service Class
#Service
#Transactional(value="txManager")
public class TestServiceImpl extends BaseServiceImpl implements ITestService {
#Autowired
private ITestDAO testDAO;
#Override
#Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=false, value="txManager")
public Long register(final String username, final String password,
final String name, final String address, final Integer deptId) {
return testDAO.register(username, password, name, address, deptId);
}
}
When ever I try to invoke the register method, then the below error is thrown (in DEBUG mode):
TransactionAspectSupport.completeTransactionAfterThrowing(534) | Completing transaction for [com.test.service.TestServiceImpl.register] after exception: javax.persistence.TransactionRequiredException: no transaction is in progress
07 Jul 2015 18:59:36,488 230371 [http-bio-9080-exec-5]:DEBUG - RuleBasedTransactionAttribute.rollbackOn(131) | Applying rules to determine whether transaction should rollback on javax.persistence.TransactionRequiredException: no transaction is in progress
I have tried all that I could find on the net, however, no luck.
Any experts, please help me know what is missing in the configuration.
PLEASE NOTE: Autowiring is working fine, read transactions (SELECT queries) are working fine.
I read somewhere that #Service & #Transactional annotations do not work if applied together on the same class (which is happening in my case, TestServiceImpl has both the annotations). Is this the case? What would be the workaround in such a situation?

Creating a single SessionFactory per application, without using static methods

I have a helper class called HibernateUtil, which creates a SessionFactory and returns a session. The class works fine, except it creates problems with mocking because Mockito can't use static methods.
The simple solution would seem to create an instance of the class, except I need to make sure there is only one SessionFactory in the application. How do I do that without using static methods?
public class HibernateUtil {
private static final Log logger = LogFactory.getLog(SessionFactory.class);
private static final SessionFactory sessionFactory = createSessionFactory();
private static SessionFactory createSessionFactory() {
logger.info("createSessionFactory called");
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
return configuration.buildSessionFactory(builder.build());
}
private static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().getCurrentSession();
if (!session.isOpen()) {
session = HibernateUtil.getSessionFactory().openSession();
}
} catch (Exception e) {
e.printStackTrace();
}
return session;
}
}
Edit: Thanks for the replies! I think I'll call it a night and tackle this again tomorrow morning.
The alternative is to use dependency injection, but by the looks of your code you're not doing that.
You could use Spring or another IoC container to do the IoC... or diy-di
Another alternative (although a bit hacky) is to have the same "static" interface, but delegate to another object which can be replaced in the tests. By default the backing implementation uses Hibernate and in your tests you can replace that implementation with a mocked instance.
If you don't want to use the spring hibernate support, you can change your class to:
package com.captain.oh.captain
#Component // singletonbean
public class HibernateUtil {
private static final Log logger = LogFactory.getLog(SessionFactory.class);
private SessionFactory sessionFactory;
#PostConstruct
private void createSessionFactory() {
logger.info("createSessionFactory called");
Configuration configuration = new Configuration().configure();
StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
sessionFactory = configuration.buildSessionFactory(builder.build());
}
private SessionFactory getSessionFactory() {
return sessionFactory;
}
public Session getSession() {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().getCurrentSession();
if (!session.isOpen()) {
session = HibernateUtil.getSessionFactory().openSession();
}
} catch (Exception e) {
e.printStackTrace();
}
return session;
}
}
And autowire it in another components (#Autowired HibernateUtil). Don't forget to add the package (com.captain.oh.captain) to your scan packages (in application-context.xml or in your #Configuration class)
Also note that your getSession method is not Thread-safe
Instead of using the HibernateUtil directly in your code, you can hide it behind an interface:
public interface HibernateSessionProvider() {
Session getSession();
}
with a default implementation:
public class DefaultHibernateSessionProvider() implements HibernateSessionProvider {
#Override
public Session getSession() {
return HibernateUtil.getSession();
}
}
Then you can mock the HibernateSessionProvider during testing. This approach works with or without Sprting's dependency injection.

#Transactional on Spring shutdown to properly shutdown Hsqldb

The heart of this question is: Is it possible to execute a Transaction from a method triggered by a Spring shutdown hook?
At the moment I have a HyperSqlDbServer class that implements SmartLifeCycle as found in this question:
In a spring bean is it possible to have a shutdown method which can use transactions?
I have a method in that class that is marked transactional that gets invoked as part of the stop method:
#Transactional
public void executeShutdown() {
hsqlDBShutdownService.executeShutdownQuery();
hsqlDBShutdownService.closeEntityManager();
}
The service used in that method is a bit of a hack that I had to do because I could not autowire in the EntityManager to this class:
#Service
public class HsqlDBShutdownService {
#PersistenceContext
private EntityManager entityManager;
#Autowired
private HyperSqlDbServer hyperSqlDbServer;
#Transactional
public void executeShutdownQuery() {
entityManager.createNativeQuery("SHUTDOWN").executeUpdate();
}
#Transactional
public void closeEntityManager() {
entityManager.close();
}
#PostConstruct
public void setHsqlDBShutdownService() {
hyperSqlDbServer.setShutdownService(this);
}
}
You may notice that all I'm really trying to accomplish is invoking the query "SHUTDOWN" before stopping the server. Without this, the hsqldb lock file sticks around on server restart, and the server throws an exception.
The code above produces the following exception:
javax.persistence.TransactionRequiredException: Executing an update/delete query
at org.hibernate.ejb.AbstractQueryImpl.executeUpdate(AbstractQueryImpl.java:96)
...
So my original question stands, but if anyone has a thought on how I could execute this query another way I'll try that as well.
FYI, I've also tried the #PreDestroy annotation, but get the same TransactionRequiredException.
Edit: For completeness, I am using the JpaTransactionManager and the #Transactional annotations work throughout my project, except on shutdown...
Edit 2: Datasource and transaction manager configuration:
#Configuration
#EnableTransactionManagement
#PropertySource("classpath:persistence.properties")
public class PersistenceConfig implements TransactionManagementConfigurer {
private static final String PASSWORD_PROPERTY = "dataSource.password";
private static final String USERNAME_PROPERTY = "dataSource.username";
private static final String URL_PROPERTY = "dataSource.url";
private static final String DRIVER_CLASS_NAME_PROPERTY = "dataSource.driverClassName";
#Autowired
private Environment env;
#Bean
#DependsOn("hsqlDb")
public DataSource configureDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty(DRIVER_CLASS_NAME_PROPERTY));
dataSource.setUrl(env.getProperty(URL_PROPERTY));
dataSource.setUsername(env.getProperty(USERNAME_PROPERTY));
dataSource.setPassword(env.getProperty(PASSWORD_PROPERTY));
return dataSource;
}
#Bean
#DependsOn("hsqlDb")
public LocalContainerEntityManagerFactoryBean configureEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(configureDataSource());
entityManagerFactoryBean.setPackagesToScan("com.mycompany.model.db");
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties jpaProperties = new Properties();
jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, env.getProperty(org.hibernate.cfg.Environment.DIALECT));
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, env.getProperty(org.hibernate.cfg.Environment.HBM2DDL_AUTO));
jpaProperties.put(org.hibernate.cfg.Environment.SHOW_SQL, env.getProperty(org.hibernate.cfg.Environment.SHOW_SQL));
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR, env.getProperty(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES_SQL_EXTRACTOR));
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES, env.getProperty(org.hibernate.cfg.Environment.HBM2DDL_IMPORT_FILES));
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Override
#Bean()
#DependsOn("hsqlDb")
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new JpaTransactionManager();
}
}
I found a workaround for shutting down the HsqlDB database, but it involves avoiding the use of Spring's EntityManager and #Transactional as they apparently do not work during server shutdown. My modified HsqlDBShutdownService is below. The key change is that instead of using the EntityManager to invoke the query, I create a new jdbc connection manually, and invoke the query that way. This avoids the requirement for #Transactional:
#Service
public class HsqlDBShutdownService {
#Autowired
private ApplicationContext applicationContext;
#PersistenceContext
private EntityManager entityManager;
#Autowired
private HyperSqlDbServer hyperSqlDbServer;
public void executeShutdownQuery() {
Connection conn = null;
try {
JdbcTemplate jdbcTemplate = new JdbcTemplate(this.applicationContext.getBean(DataSource.class));
conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
conn.setAutoCommit(true);
jdbcTemplate.execute("SHUTDOWN");
} catch(Exception ex) {
ex.printStackTrace();
} finally {
try {
if(conn != null)
conn.close();
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
#Transactional
public void closeEntityManager() {
entityManager.close();
}
#PostConstruct
public void setHsqlDBShutdownService() {
hyperSqlDbServer.setShutdownService(this);
}
}
The server can now restart successfully without leaving Hsqldb lock files around.

Spring 3.0 and Hibernate 3.5 integration with contextual session

I know hibernate well, and fairly Spring core, I am able to use hibernate template and hibernate dao support class to integrate both but as from hibernate 3.1 we have contextual sessions i.e. we need not to use hibernate template and hibernate dao support but when i am trying to integrate with this concept and inject the sessionFactory in my dao class everything goes write but i am trying to insert data hibernate shows the insert query but the data is not saved to database please help me what can i do.
Here is my code
#Transactional
public class UserDAO {
SessionFactory sessionFactory;
public void save(User transientInstance) {
try {
sessionFactory.openSession().save(transientInstance);
} catch (RuntimeException re) {
throw re;
}
}
public static UserDAO getFromApplicationContext(ApplicationContext ctx) {
return (UserDAO) ctx.getBean("UserDAO");
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
This is my beans.xml
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
<bean id="UserDAO" class="dao.UserDAO">
<property name="sessionFactory"><ref bean="sessionFactory" /></property>
</bean>
This is my main code
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
User user=new User("firstName", "lastName", "address", "phoneNo", "mobileNo", "email", "password", false, null);
SessionFactory factory=(SessionFactory)context.getBean("sessionFactory");
Session session=factory.openSession();
Transaction tx=session.beginTransaction();
UserDAO ud=(UserDAO)context.getBean("UserDAO");
ud.save(user);
tx.commit();
session.close();
There are several problems with your code,
The DAO is already transactional, managed by Spring. You are starting another transaction in main.
You are opening session twice. Once in main and another time in dao.
When you are using contextual session, it is best practice to call sessionFactory.getCurrentSession()
Now if you have configured transaction manager with Spring properly, the following code will work, I just added some comments, see if it's helpful to you :)
#Transactional
public class UserDAO {
SessionFactory sessionFactory;
public void save(User transientInstance) {
//Removed try-catch. It was just catching RuntimeException only to re throw it
sessionFactory.openSession().save(transientInstance);
}
//I would get rid of this method.
public static UserDAO getFromApplicationContext(ApplicationContext ctx) {
return (UserDAO) ctx.getBean("UserDAO");
}
//I would get rid of this method or make it private
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Main code
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
//I would use builder instead of constructor here
User user=new User("firstName", "lastName", "address", "phoneNo", "mobileNo", "email", "password", false, null);
UserDAO ud=(UserDAO)context.getBean("UserDAO");
ud.save(user);

Resources