Change the database in a Spring web app - java

I have created a web app with Spring on the basis of Maven archetype for spring web app by kolorobot on GitHub
this archetype. Since I have not been developing with spring for several months, I need some help. This web app is using a HSQL db. I want to change the db, but i am not sure where to do it. Maybe somebody with more experience can help? This is the content of my persitence.properties file:
dataSource.driverClassName=org.hsqldb.jdbcDriver
dataSource.url=jdbc:hsqldb:mem:test
dataSource.username=sa
dataSource.password=
hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.hbm2ddl.auto=create
In my web app there are already several config classes, that come along with the parent archetype.
This is my JPAConfig:
package org.stimpy.config;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;
import org.stimpy.Application;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackageClasses = Application.class)
class JpaConfig implements TransactionManagementConfigurer {
#Value("${dataSource.driverClassName}")
private String driver;
#Value("${dataSource.url}")
private String url;
#Value("${dataSource.username}")
private String username;
#Value("${dataSource.password}")
private String password;
#Value("${hibernate.dialect}")
private String dialect;
#Value("${hibernate.hbm2ddl.auto}")
private String hbm2ddlAuto;
#Bean
public DataSource configureDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean configureEntityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(configureDataSource());
entityManagerFactoryBean.setPackagesToScan("org.stimpy");
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties jpaProperties = new Properties();
jpaProperties.put(org.hibernate.cfg.Environment.DIALECT, dialect);
jpaProperties.put(org.hibernate.cfg.Environment.HBM2DDL_AUTO, hbm2ddlAuto);
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
#Bean
public PlatformTransactionManager annotationDrivenTransactionManager() {
return new JpaTransactionManager();
}
}
I know Spring is very configurable, but at the minute I am lost.
Update:
When I change the persitence properties to:
dataSource.driverClassName=org.h2.Driver
dataSource.url=jdbc:h2:mem:test
dataSource.username=sa
dataSource.password=
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.hbm2ddl.auto=create
the maven package command fails. And several tests are failing. In the error output it said:
Table ACCOUNT was not found. Do I have to create the tables manually or does Spring do the job?

I solved the problem. I changed the properties to:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql://localhost:3306/mywebbapp
dataSource.username=root
dataSource.password=
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.hbm2ddl.auto=create
hibernate.connection.url=jdbc:mysql://localhost:3306/mywebbapp
And then created a table named 'mywebabapp' in my local mysql database.
Now i am going to setup multiple environments (test, prod, dev). To let the tests run against the embedded H2-db like user Bobby Zohdy suggeseted.

Let's assume that you want to change the database to H2, then you only need the following changes (assuming of course you have added the H2 dependencies to the project):
dataSource.driverClassName=org.h2.Driver
dataSource.url=jdbc:h2:mem:test
hibernate.dialect=org.hibernate.dialect.H2Dialect

if you are going to use the in-memory database why not use spring embedded database like :
<jdbc:embedded-database id="dataSource">
<jdbc:script location="classpath:schema.sql"/>
<jdbc:script location="classpath:test-data.sql"/>
</jdbc:embedded-database>
or
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
EmbeddedDatabase db = builder.type(H2).script("schema.sql").script("test-data.sql").build();
// do stuff against the db (EmbeddedDatabase extends javax.sql.DataSource)
db.shutdown()
and if you have multiple environments, you can use spring profile http://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

Related

Intellij Idea doesn't work the way it was working with thymeleaf / java

I've reinstalled intellij idea and noticed some changes while working with Java / Spring MVC / thymeleaf. The exact thing that now I can't actually see if return "htmlFile"; in #Controller method exists. It was underlinning it at first, now it does not. The second thing is when I put something in Model with model.addAttribute("book", book) and trying to use "book" in html with thymeleaf it shows like "book" doesn't exists but when I run program I can see that "book" exist and I can even get it's name or whatever.
Do I need some kind of plugin installed or what?
The actual solution:
Go to: File / Project Structure / Facets.
Select Spring, click on plus and Add your Application context class.
My Application context class example:
package ua.yuriy.spring.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.thymeleaf.spring6.SpringTemplateEngine;
import org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring6.view.ThymeleafViewResolver;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#ComponentScan("your.main.thread")
#PropertySource("classpath:hibernate.properties")
#EnableJpaRepositories("your.main.thread.repositories")
#EnableWebMvc
#EnableTransactionManagement
public class SpringConfig implements WebMvcConfigurer {
private final ApplicationContext applicationContext;
private final Environment env;
#Autowired
public SpringConfig(ApplicationContext applicationContext, Environment env) {
this.applicationContext = applicationContext;
this.env = env;
}
#Bean
public SpringResourceTemplateResolver templateResolver() {
SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver();
templateResolver.setApplicationContext(applicationContext);
templateResolver.setPrefix("/WEB-INF/templates/"); // You might want to change templates to views
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
#Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setEnableSpringELCompiler(true);
return templateEngine;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine());
resolver.setCharacterEncoding("UTF-8");
registry.viewResolver(resolver);
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("hibernate.driver_class"));
dataSource.setUrl(env.getRequiredProperty("hibernate.connection.url"));
dataSource.setUsername(env.getRequiredProperty("hibernate.connection.username"));
dataSource.setPassword(env.getRequiredProperty("hibernate.connection.password"));
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", env.getRequiredProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", env.getRequiredProperty("hibernate.show_sql"));
return properties;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan("ua.yuriy.spring.models");
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(hibernateProperties());
return em;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
}

Spring Boot Multi Data sources : How to configure multi spring.jpa properties in java class

application.yml
spring:
security:
user:
name: test
password: admin
datasource:
platform: postgres
jdbc-url: jdbc:postgresql://localhost:5432/ktnb
username: xxxx
password: xxxx
driverClassName: org.postgresql.Driver
sqlserver-datasource:
jdbc-url: jdbc:sqlserver://192.168.0.10;databaseName=backup1
username: xxx
password: xxx
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
PrimaryDBConfig.java
package com.ktnb.keahlian.config;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactory",
transactionManagerRef = "transactionManager",
basePackages = { "com.ktnb.keahlian.repository" }
)
public class PrimaryDBConfig {
#Primary
#Bean(name = "dataSource")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean
entityManagerFactory(
EntityManagerFactoryBuilder builder,
#Qualifier("dataSource") DataSource dataSource
) {
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("spring.jpa.database", "postgresql");
properties.put("spring.jpa.show-sql", "true");
properties.put("spring.jpa.hibernate.ddl-auto", "create");
properties.put("spring.jpa.properties.hibernate.default_schema", "keahlian");
properties.put("spring.jpa.org.hibernate.envers.default_schema", "keahlian_envers");
properties.put("spring.jpa.org.hibernate.envers.audit_strategy", "org.hibernate.envers.strategy.ValidityAuditStrategy");
return builder
.dataSource(dataSource)
.packages("com.ktnb.keahlian.entity")
.persistenceUnit("primaryDB")
.properties(properties)
.build();
}
#Primary
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager(
#Qualifier("entityManagerFactory") EntityManagerFactory
entityManagerFactory
) {
return new JpaTransactionManager(entityManagerFactory);
}
}
But it cannot found right table/schema and not able show sql into console.
Primary datasource for development DB.
Secondary datasource for Production DB.
[INFO ] 2020-08-21 09:38:30.116 [http-nio-8080-exec-1] SessionListenerImpl - ==== Session is created ====
[INFO ] 2020-08-21 09:38:30.116 [http-nio-8080-exec-1] SessionListenerImpl - Total active session are 1
[WARN ] 2020-08-21 09:38:32.480 [http-nio-8080-exec-6] SqlExceptionHelper - SQL Error: 0, SQLState: 42P01
[ERROR] 2020-08-21 09:38:32.480 [http-nio-8080-exec-6] SqlExceptionHelper - ERROR: relation "pengguna" does not exist
Position: 467
Can you try this ?
application.properties
primary.url={primary-database-url}
primary.username={primary-database-username}
primary.password={primary-database-password}
primary.driver-class-name=com.mysql.jdbc.Driver
primary.test-on-borrow=true
primary.validation-query=SELECT 1
secondary.url={secondary-database-url}
secondary.username={secondary-database-username}
secondary.password={secondary-database-password}
secondary.driver-class-name=com.mysql.jdbc.Driver
secondary.test-on-borrow=true
secondary.validation-query=SELECT 1
secondary.validation-interval=25200000
Create the configuration beans
#Bean(name = "primaryDataSource")
#ConfigurationProperties("primary")
#Primary
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "secondaryDataSource")
#ConfigurationProperties("secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
Next, create the JdbcTemplate beans that we are going to use for accessing the data sources in our data access layer.
#Bean(name = "primaryJdbcTemplate")
public JdbcTemplate primaryJdbcTemplate(#Qualifier("primary") DataSource primaryDs) {
return new JdbcTemplate(writeDs);
}
#Bean(name = “secondaryJdbcTemplate")
public JdbcTemplate secondaryJdbcTemplate(#Qualifier("secondary") DataSource secondaryDs) {
return new JdbcTemplate(secondaryDs);
}
Try accessing properties like this:
#Resource(name = "primaryJdbcTemplate")
private JdbcTemplate primaryJdbcTemplate;
#Resource(name = "secondaryJdbcTemplate")
private JdbcTemplate secondaryJdbcTemplate;
primaryJdbcTemplate.query(“any-query-to-apply-on-primary-data-source”);

Spring : How to configure tomcat Datasource Programatically in Groovy DAO

I have my tomcat datasource configured in XML as below:
<bean id="docDataSource"
class="org.apache.tomcat.jdbc.pool.DataSource"
destroy-method="close"
p:driverClassName="${doc.database.driver}"
p:url="${doc.database.url}"
p:username="${doc.database.user}"
p:password="${doc.database.password}"
p:validationQuery="select 1"
p:testOnBorrow="true"
p:minIdle="2"
p:maxIdle="4"
p:maxActive="6"
p:defaultTransactionIsolation="1">
</bean>
And my customDAO(groovy class) uses the above datasource as below
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.stereotype.Component
import groovy.sql.Sql
import org.apache.log4j.Level
import javax.sql.DataSource
import java.util.Map
import java.util.Map.Entry
import java.util.ResourceBundle
#Component
public class customDao implements GroovyInterceptable {
#Autowired
private Services services
#Autowired
#Qualifier("docDataSource")
private DataSource dataSource
// implementation
}
I wanna switch my tomcat dataSource to a class file instead of XML. Can someone help me how to do this?
Here's the piece of code you can follow (with PostgreSQL, but it should more or less work the same):
import org.postgresql.ds.PGPoolingDataSource
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import javax.sql.DataSource
#Configuration
class PostgreSQLDatasourceConfiguration {
#Bean(name = 'dataSource')
DataSource ds(#Value('${DATABASE_URL}') String databaseFullUrl) {
assert databaseFullUrl, 'Database URL is required to start the application'
URI uri = new URI(databaseFullUrl)
def (_, dbUsername, dbPassword) = (uri.getUserInfo() =~ /(.*):(.*)/)[0]
(DataSource) new PGPoolingDataSource().tap {
url = "jdbc:postgresql://$uri.host:${uri.port}$uri.path"
password = dbPassword
user = dbUsername
}
}
}

How to run a legacy code inside a managed spring transaction?

Hi I have a legacy code which gets its jdbc connections through
DataSource.getConnection()
The DataSource is bounded to Jndi namespace.,
Suppose that I have a function which gets its connections like that:
foo(){
...
Connection con = DataSource.getConnection()
...
}
And I want to run this foo method into a well defined spring transaction. How would I do that ?
I have used TransactionAwareDataSourceProxy and It worked quite well before I move onto something like JPA
At first I could synronize foo's transaction with my spring transaction with this configuration.
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations"><list><value>classpath:/db.properties</value></list></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dbcpDataSource"/>
</bean>
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>oracle.jdbc.driver.OracleDriver</value></property>
<property name="url"><value>jdbc:oracle:thin:#${jdbc.url}:1521:${jdbc.db}</value></property>
<property name="username"><value>${jdbc.username}</value></property>
<property name="password"><value>${jdbc.password}</value></property>
<!-- <property name="defaultAutoCommit"><value>true</value></property> -->
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
After that I move onto JPA using LocalContainerEntityManagerFactoryBean and JpaTransactionManager.
package setup;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
#Configuration
#EnableJpaRepositories
public class SpringContextConfiguration {
#Bean
public TestsSetup testSetup(){
return new TestsSetup();
}
#Bean
public TransactionAwareDataSourceProxy dataSource(){
TransactionAwareDataSourceProxy tp = new TransactionAwareDataSourceProxy();
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUrl("jdbc:oracle:thin:#a.a.a.a:port:some");
ds.setUsername("user");
ds.setPassword("paswd");
ds.setDefaultAutoCommit(true);
tp.setTargetDataSource(ds);
return tp;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setDataSource(dataSource);
lef.setJpaVendorAdapter(jpaVendorAdapter);
lef.setPackagesToScan("setup");
return lef;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
hibernateJpaVendorAdapter.setShowSql(true);
hibernateJpaVendorAdapter.setGenerateDdl(false);
hibernateJpaVendorAdapter.setDatabase(Database.ORACLE);
return hibernateJpaVendorAdapter;
}
#Bean
public PlatformTransactionManager transactionManager() {
return new JpaTransactionManager();
}
}
Now my legacy code blocks do not synchronize with my managed transactions. How can I overcome this problem. Any tools or comments is greatly appreciated.
EDIT
Inject the DataSource and EntityManagerFactory into the JpaTransactionManager bean. See class-level comment # http://docs.spring.io/spring/docs/3.2.5.RELEASE/javadoc-api/org/springframework/orm/jpa/JpaTransactionManager.html for more info.
The above configuration is actually correct and the underlying legacy functions is being called inside the created spring transaction. What I miss is that on the upper layer I needed to flush the underlying session to the datastore. When I did that the legacy transaction begins to aware of the changed data and everything works perfect and also the transactions can be rolled back.
I flush my session to the datastore with this :
#Autowired
PlatformTransactionManager pt;
TransactionDefinition td = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_MANDATORY);
pt.getTransaction(td).flush();

How to get Spring Data Neo4j and Spring Data JPA to work together?

I have an application that does some batch jobs using MySQL and, via REST, Neo4j server version.
I can't figure out how to make them to work together correctly: I can get to make work both of them, but not at the same time. The posts I've found around are not specific to the server version of Neo4j, and maybe that's where the problem is, since everything else seems ok to me.
My configuration:
JpaConfig
#Configuration
#EnableTransactionManagement(order=Ordered.HIGHEST_PRECEDENCE)
#PropertySource("META-INF/database.properties")
#ImportResource("classpath*:META-INF/repository.xml")
public class JpaConfig {
#Autowired
Environment env;
#Bean(destroyMethod = "close")
public DataSource dataSource() {
DataSource dataSource = new DataSource();
dataSource.setDriverClassName(env.getProperty("database.driverClassName"));
dataSource.setUrl(env.getProperty("database.url"));
dataSource.setUsername(env.getProperty("database.username"));
dataSource.setPassword(env.getProperty("database.password"));
dataSource.setTestOnBorrow(true);
dataSource.setTestOnReturn(true);
dataSource.setTestWhileIdle(true);
dataSource.setTimeBetweenEvictionRunsMillis(1800000);
dataSource.setNumTestsPerEvictionRun(3);
dataSource.setMinEvictableIdleTimeMillis(1800000);
dataSource.setValidationQuery("SELECT 1");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
entityManagerFactory.setDataSource(dataSource());
entityManagerFactory.setPackagesToScan("it.smartblue.mcba.domain");
entityManagerFactory.setJpaDialect(new HibernateJpaDialect());
Map<String, String> jpaProperties = new HashMap<>();
jpaProperties.put("hibernate.connection.charSet", "UTF-8");
jpaProperties.put("hibernate.ejb.naming_strategy", "org.hibernate.cfg.EJB3NamingStrategy");
jpaProperties.put("hibernate.bytecode.provider", "javassist");
jpaProperties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5InnoDBDialect");
entityManagerFactory.setJpaPropertyMap(jpaProperties);
entityManagerFactory.setPersistenceProvider(new HibernatePersistence());
return entityManagerFactory;
}
#Bean
public PlatformTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
}
Neo4j.xml
<!-- neo4j configuration -->
<neo4j:config graphDatabaseService="graphDatabaseService" entityManagerFactory="entityManagerFactory"/>
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
<constructor-arg index="0" value="http://192.168.11.186:7474/db/data" />
</bean>
<neo4j:repositories base-package="it.smartblue.mcba.neo4j.repository" />
With this configuration Mysql works perfectly, but Neo4j doesn't save any property to the nodes it creates.
If I remove the attribute entityManagerFactory="entityManagerFactory" Neo4j works, but I can't write to MySQL.
My services methods are annotated with #Transactional or #Neo4jTransactional, not both at the same time.
Inside the class org.springframework.data.neo4j.rest.SpringRestGraphDatabase for the graphDatabaseService bean I've found:
#Override
public Transaction beginTx() {
// return super.beginTx();
return new NullTransaction();
}
#Override
public TransactionManager getTxManager() {
return new NullTransactionManager();
}
Maybe it's a work in progress? Or maybe I miss something...
I'm using Spring 3.1.2, Hibernate 4.1.4. Here is part of my pom.xml.
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.2.0.RC1</version>
</dependency>
<!-- Neo4j dependencies -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j</artifactId>
<version>2.1.0.RC4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-rest</artifactId>
<version>2.1.0.RC4</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-neo4j-cross-store</artifactId>
<version>2.1.0.RC4</version>
</dependency>
Finally I made it.
Instead of having two different transactionManagers, now I have only one ChainedTransactionManager.
I removed the transactionManager bean from JpaConfig and the neo4j.xml file, and added the following Neo4jConfig
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.JtaTransactionManagerFactoryBean;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.rest.SpringRestGraphDatabase;
import org.springframework.data.neo4j.transaction.ChainedTransactionManager;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
#EnableNeo4jRepositories(basePackages = { "it.smartblue.mcba.neo4j.repository" })
#Configuration
public class Neo4jConfig extends Neo4jConfiguration {
#Autowired
LocalContainerEntityManagerFactoryBean entityManagerFactory;
#Bean
public SpringRestGraphDatabase graphDatabaseService() {
return new SpringRestGraphDatabase("http://192.168.11.186:7474/db/data");
}
#Override
#Bean(name = "transactionManager")
public PlatformTransactionManager neo4jTransactionManager() throws Exception {
return new ChainedTransactionManager(new JpaTransactionManager(entityManagerFactory.getObject()),
new JtaTransactionManagerFactoryBean(graphDatabaseService()).getObject());
}
}
Now I have to use on my methods only the #Transactional annotation

Categories

Resources