In the SDN 4.1 reference, the configuration includes extending Neo4jConfiguration and setting up a Session object explicitly as a #Bean. In 4.2, the guidance is to not extend Neo4jConfiguration and follow the config below. Note that explicitly setting up a standalone Session object is absent:
#Bean
public org.neo4j.ogm.config.Configuration configuration() {
org.neo4j.ogm.config.Configuration config = new org.neo4j.ogm.config.Configuration();
config
.driverConfiguration()
.setDriverClassName("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver")
.setURI(dbLocation);
return config;
#Bean
public SessionFactory sessionFactory() {
SessionFactory sessionFactory = new SessionFactory(configuration(), "org.my.package" );
sessionFactory.register(new MyPreSaveListener());
return sessionFactory;
}
I've seen this config used while #Autowiring the Session object itself (not the factory) in repository classes. Does this mean that there will then be only one Session instance across the application? If so, doesn't that go against the idea that a Session lifespan should be limited to an application's "unit of work?"
Note that my repositories are custom and do not extend the neo4j repos, as I am currently migrating away from using the Neo4jTemplate object.
No, there is not one session per application. So long as your Session is called from within a #Transactional annotation or TransactionTemplate it will call a proxy Session (which is generated by the Spring Data Neo4j framework during startup). This will effectively create a session for the lifetime of the transaction (where it is demarcated) and once out of scope, allow it to be garbage collected.
Related
HI We are migrating hibernate 3 to 5.4.25 >Please help me to get CMT transactionfactory replacement in hibernate 5 as it is deprecated and i am getting no transaction is in progress if i use session.flush() in my DAO class GET methos. Kindly help
An excerpt from link
Its not just org.hibernate.transaction.CMTTransactionFactory that was
removed; all of the TransactionFactory classes were removed. Actually I
think we should add them as resolvable names:
org.hibernate.transaction.CMTTransactionFactory
->
org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl
org.hibernate.transaction.JTATransactionFactory
-> org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl
org.hibernate.transaction.JDBCTransactionFactory ->
org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl
Actually, I have recently done a similar migration where I have completely changed the transaction-related blocks to Spring's imperative transaction infrastructure.
I have used PlatformTransactionManager which is the default implementations of this strategy interface are org.springframework.transaction.jta.JtaTransactionManager and org.springframework.jdbc.datasource.DataSourceTransactionManager, which can serve as an implementation guide for other transaction strategies.
#EnableTransactionManagement
#Configuration
public class DbConfig{
#Autowired
private DataSource dataSource;
#Bean
#Primary
public PlatformTransactionManager annotationDrivenTransactionManager(LocalSessionFactoryBean lsfb) {
return new HibernateTransactionManager(lsfb.getObject());
}
#Bean
#Primary
public LocalSessionFactoryBean getSessionFactory()
{
LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();
lsfb.setDataSource(this.dataSource);
Properties properties = new Properties();
properties.put("hibernate.dialect", <hibernateDialect>);
properties.put("hibernate.connection.isolation",2); // READ_COMMITTED
properties.put("hibernate.show_sql", hibernateShowSql); //To show sql or not
//...configurable hibernate properties to add
lsfb.setHibernateProperties(properties);
lsfb.setPackagesToScan("com.demo.entity.model"");
return lsfb;
}
}
JavaDoc about the PlatformTransactionManager(link)
PlatformTransactionManager implementation for a single Hibernate
SessionFactory. Binds a Hibernate Session from the specified factory
to the thread, potentially allowing for one thread-bound Session per
factory. SessionFactory.getCurrentSession() is required for Hibernate
access code that needs to support this transaction handling mechanism,
with the SessionFactory being configured with SpringSessionContext.
Supports custom isolation levels, and timeouts that get applied as
Hibernate transaction timeouts.
This transaction manager is appropriate for applications that use a
single Hibernate SessionFactory for transactional data access, but it
also supports direct DataSource access within a transaction (i.e.
plain JDBC code working with the same DataSource). This allows for
mixing services which access Hibernate and services which use plain
JDBC (without being aware of Hibernate)! Application code needs to
stick to the same simple Connection lookup pattern as with
DataSourceTransactionManager (i.e.
DataSourceUtils.getConnection(javax.sql.DataSource) or going through a
TransactionAwareDataSourceProxy).
I have 2 DAO - the first works with #Bean DataSource + JDBC. Configuration is the following:
#Bean("dataSource")
#Singleton
public DataSource getDataSource() {
BasicDataSource basicDataSource = new BasicDataSource();
basicDataSource.setDriverClassName("...");
basicDataSource.setUrl("...");
basicDataSource.setUsername(...);
basicDataSource.setPassword(...);
...
return basicDataSource;
}
The second works with entityManager. application.properties configuration is the following:
spring.datasource.url=...
spring.datasource.username=...
spring.datasource.password=...
...
When I starts my Spring Boot Application and spring initializes my beans, I use the second DAO to get some information from database.
I am using second DAO -> entityManager in this case.
I expects that entityManager uses configuration from application.properties.
Indeed, entityManager uses configration from bean DataSource.
How does It work?
p.s. database properties in application.properties look like used.
Actually I think that I should use one ConnectionPool for my application.
I can configure DataSource as #Bean and provide entityManager and jdbcTemplate with It.
Should I choose another solution? Or Is this idea quite suitable?
It's because of the importance. #Configuration has higher precedence than application.properties. First spring-boot searches for #Bean definition, if it's not found, then it checks application.properties. Generally those definitions are equivalent.
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);
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