Spring Boot Data JPA: Hibernate Session issue - spring

I'm developing a Spring Boot based web application. I heavily rely on #ComponentScan and #EnableAutoConfiguration and no explicit XML configuration in place.
I have the following problem. I have a JPA-Annotated Entity class called UserSettings:
#Entity public class UserSettings {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#OneToMany(cascade = CascadeType.ALL)
private Set<Preference> preferences; // 'Preference' is another #Entity class
public UserSettings() {
this.preferences = new HashSet<Preference>();
}
// some more primitive properties, Getters, Setters...
}
I followed this tutorial and created a repository interface that extends JpaRepository<UserSettings,Long>.
Furthermore, I have a UserManager bean:
#Component public class SettingsManager {
#Autowired
UserSettingsRepository settingsRepository;
#PostConstruct
protected void init() {
// 'findGlobalSettings' is a simple custom HQL query
UserSettings globalSettings = this.settingsRepository.findGlobalSettings();
if (globalSettings == null) {
globalSettings = new UserSettings();
this.settingsRepository.saveAndFlush(globalSettings);
}
}
Later in the code, I load the UserSettings object created here, again with the findGlobalSetttings query.
The problem is: Every time I try to access the #OneToMany attribute of the settings object, I get the following exception:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role org.example.UserSettings.preferences, could not initialize proxy - no Session
I understand that each HTTP Session has its own Hibernate Session, as described in the accepted answer of this question, but that does not apply in my case (currently I'm testing this within the same HTTP Session), which is why I have no idea where this exception comes from.
What am I doing wrong and how can I achieve circumvent the error?

If you want to be able to access mapped entities outside the transaction (which you seem to be doing), you need to flag it as an "eager" join. i.e.
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)

This question has been answered beautifully by #Steve. However, if you still want to maintain your lazy loading implementation, you may want to try this
import javax.servlet.Filter;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate4.support.OpenSessionInViewFilter;
#Configuration
#ComponentScan
public class AppConfig {
#Bean
public FilterRegistrationBean filterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(openSessionInView());
registration.addUrlPatterns("/*");
return registration;
}
#Bean
public Filter openSessionInView() {
return new OpenSessionInViewFilter();
}
}
What this configuration does is, it registers a Filter on requests to path "/*" which keeps your Hibernate Session open in your view.
This is an anti-pattern and must be used with care.
NOTE: As of Spring Boot 1.3.5.RELEASE, when you use the default configuration with Spring Data JPA auto-configuration, you shouldn't encounter this problem

I faced similar issue in spring boot application, after googling I'm able to fix this issue by adding the following code to my application.
#Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource) {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource);
entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
Properties jpaProperties = new Properties();
jpaProperties.put("hibernate.enable_lazy_load_no_trans", true);
entityManagerFactoryBean.setJpaProperties(jpaProperties);
return entityManagerFactoryBean;
}
Referred here.

Related

Reading same cache from different microservices

Am using spring-data-redis(2.1.5.RELEASE) and jedis(2.10.2) client to connect to my azure redis instance from different services running as spring-boot application.
Two services has the same caching methods and pointed to the same cache by implementing the following configuration. The problem am facing is when one service trying to read a cached value created by another service, de-seralization exception occurs.
Exception:
org.springframework.data.redis.serializer.SerializationException: Cannot deserialize; nested exception is org.springframework.core.serializer.support.SerializationFailedException: Failed to deserialize payload. Is the byte array a result of corresponding serialization for DefaultDeserializer?; nested exception is org.springframework.core.NestedIOException: Failed to deserialize object type; nested exception is java.lang.ClassNotFoundException
Note: Am using redis only to cache the data read from my database.
Redis Cache Configuration of microservice 1
public RedisCacheWriter redisCacheWriter(RedisConnectionFactory connectionFactory) {
return RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
}
#Bean
public RedisCacheManager cacheManager() {
Map<String, RedisCacheConfiguration> cacheNamesConfigurationMap = new HashMap<>();
cacheNamesConfigurationMap.put("employers", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(90000)));
cacheNamesConfigurationMap.put("employees", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(90000)));
RedisCacheManager manager = new RedisCacheManager(redisCacheWriter(), RedisCacheConfiguration.defaultCacheConfig(), cacheNamesConfigurationMap);
manager.setTransactionAware(true);
manager.afterPropertiesSet();
return manager;
}
Redis Cache Configuration of microservice 2
public RedisCacheWriter redisCacheWriter(RedisConnectionFactory connectionFactory) {
return RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
}
#Bean
public RedisCacheManager cacheManager() {
Map<String, RedisCacheConfiguration> cacheNamesConfigurationMap = new HashMap<>();
cacheNamesConfigurationMap.put("employees", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(90000)));
RedisCacheManager manager = new RedisCacheManager(redisCacheWriter(), RedisCacheConfiguration.defaultCacheConfig(), cacheNamesConfigurationMap);
manager.setTransactionAware(true);
manager.afterPropertiesSet();
return manager;
}
Caching methods in both services
#Cacheable(value = "employees", key = "#employeesId")
public Employee getEmployee(String employeesId) {
//methods
}
Employee class in both services
public class Employee implements Serializable {
private String id;
private String name;
}
Either make sure the returned (de(serialized)) object is in exact same package or prevent registering the class in the data. This happens because the class name with full package qualified name are set into the data (JSON in my case). Here are the configuration I used to
Do not get restricted using same class name of a dto !
Use typed de-(serialization) and not generic types for converting from/to JSON
Remove the class mark put in the data
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext.SerializationPair;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
#Configuration
#RequiredArgsConstructor
public class RedisConfig {
#Bean
RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
return builder -> {
Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
configurationMap.put("whatever-cache-name",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(3600))
.serializeValuesWith(
SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(Employee.class))
)
);
builder.withInitialCacheConfigurations(configurationMap);
};
}
}
To only
Remove the class mark put in the data
Just use instead a different serializer
#AutoWired
ObjectMapper objectMapper;
#Bean
RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
return builder -> {
Map<String, RedisCacheConfiguration> configurationMap = new HashMap<>();
configurationMap.put("whatever-cache-name",
RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(3600))
.serializeValuesWith(
SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper))
)
);
builder.withInitialCacheConfigurations(configurationMap);
};
}
Note that by default the GenericJackson2JsonRedisSerializer creates new ObjectMapper if you don't provide one in the constructor and the default implementation will add the full qualified class name in the data and that's why I used the one provided by Spring as it was properly configured enough in that case.
I would suggest you make sure the Employee classes are identical and then add a serialVersionUID field to the classes. Clear the Redis cache and try again.
This is from the Javadocs in the java.io.Serializable interface:
If a serializable class does not explicitly declare a serialVersionUID, then
the serialization runtime will calculate a default serialVersionUID value
for that class based on various aspects of the class, as described in the
Java(TM) Object Serialization Specification. However, it is strongly
recommended that all serializable classes explicitly declare
serialVersionUID values, since the default serialVersionUID computation is
highly sensitive to class details that may vary depending on compiler
implementations, and can thus result in unexpected
InvalidClassExceptions during deserialization. Therefore, to
guarantee a consistent serialVersionUID value across different java compiler
implementations, a serializable class must declare an explicit
serialVersionUID value. It is also strongly advised that explicit
serialVersionUID declarations use the private modifier where
possible, since such declarations apply only to the immediately declaring
class--serialVersionUID fields are not useful as inherited members.

Set Spring Session Redis on production only

Is it possible to set the Spring session data redis module on production profile only?
I have tried using #Profile but the AbstractHttpSessionApplicationInitializer was initialized before setting the profile/environment and thus will give me an NoSuchBean Exception
NoSuchBeanDefinitionException: No bean named 'springSessionRepositoryFilter' available
And when I try to inject the profile using #Values it returns null value.
#Value("${spring.profiles.active:local}")
private String activeProfile; // result is null
I have solved the problem using this article.
The production session config will be like this.
#Configuration
#ConditionalOnProperty(name = "spring.profiles.active", havingValue = "production")
#EnableRedisHttpSession
#ConfigurationProperties(prefix = "redis.db")
public class ProductionSessionConfig {
#Setter
private String server;
#Setter
private Integer port;
#Bean
public JedisConnectionFactory connectionFactory() {
//creates your own connection
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(server, port);
return new JedisConnectionFactory(config);
}
}
And if you are not going to use the spring-session-data-redis in other environment. You can just proceed. Just keep in mind the #ConditionalOnProperty value.
And do not forget to exclude the Auto Configuration of Session.
#SpringBootApplication(exclude = {SessionAutoConfiguration.class})

Unable to use two Neo4j Instances with Spring boot/Spring data neo4j

Expected Behavior
Trying to use two Neo4j instances with Spring boot and Spring data Neo4j
Current Behavior
Able to use only one Neo4j instances. Unable to use two repositories.
Steps to Reproduce (for bugs)
1. Run two Neo4j Instances
2. Create Data source configuration for both Neo4j Instances using spring boot.
3. Use Repository to access the Node entity
4. It will throw error
Context
Consider that I am running a library and renting books to other users. If the user is renting the book from me, the same node details will be present in their repository and I will allow them to edit the node entity through my application (like adding keywords, adding highlights about the books etc.)
So in both repository the node details will be same.
Below are the application. properties details for both Neo4j repositories.
My Neo4j Repository Details
spring.data.neo4j.uri=bolt://localhost:7687
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=neo4j
Rental User's Neo4j Repository Details
(Accessing through http which is running in some other machine)
rental.data.neo4j.uri=bolt://...:7687
rental.data.neo4j.username=neo4j
rental.data.neo4j.password=neo4j
Below is the Rental User's Neo4j configuration :
#configuration
#EnableNeo4jRepositories(basePackages = "com.metadata.dao.rentallibrary", sessionFactoryRef = "rentalSessionFactory", transactionManagerRef = "rentalUsertransactionManager")
#EnableTransactionManagement
#EntityScan("com.metadata.dao")
public class rentalUserNeo4jConfiguration {
#Value("${rental.data.neo4j.uri}")
private String url;
#Value("${rental.data.neo4j.username}")
private String userName;
#Value("${rental.data.neo4j.password}")
private String password;
#Bean(name = "rentalSessionFactory")
public SessionFactory rentalUserSessionFactory() {
return new SessionFactory(rentalNeo4jconfiguration(), "com.metadata.dao.rentallibrary.entity");
}
#Bean
public org.neo4j.ogm.config.Configuration rentalNeo4jconfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration.Builder().uri(url)// "
.credentials(userName, password)
.build();
return configuration;
}
#Bean
public Neo4jTransactionManager rentalUsertransactionManager() {
return new Neo4jTransactionManager(rentalUserSessionFactory());
}
}
And below is my library's Neo4j configuration details :
#configuration
#EnableNeo4jRepositories(basePackages = "com.metadata.dao.mylibrary", sessionFactoryRef = "myUserSessionFactory", transactionManagerRef = "myUserTransactionManager")
#EnableTransactionManagement
public class MyUserNeo4jConfiguration {
#Value("${spring.data.neo4j.uri}")
private String url;
#Value("${spring.data.neo4j.username}")
private String userName;
#Value("${spring.data.neo4j.password}")
private String password;
#Bean(name = "myUserSessionFactory")
#Primary
public SessionFactory myUserSessionFactory() {
return new SessionFactory(myUserconfiguration(), "com.metadata.dao.mylibrary.entity");
}
#Bean
public org.neo4j.ogm.config.Configuration myUserconfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration.Builder().uri(url)
.credentials(userName, password)
.build();
return configuration;
}
#Bean
public Neo4jTransactionManager myUserTransactionManager() {
return new Neo4jTransactionManager(myUserSessionFactory());
}
}
I am trying access both repositories using session Factory (via qualifier) it is working fine. But I am trying to access the data, through repositories I am facing the Issue.
**Accessing through SessionFactory :**
#Autowired
#Qualifier(value = "myUserSessionFactory")
SessionFactory myUserSessionFactory;
#Autowired
#Qualifier(value = "rentalUserSessionFactory")
SessionFactory rentalUserSessionFactory;
Below are the error details, I am getting when trying to access the data through :
java.lang.IllegalArgumentException: Class class com.metadata.dao.Book is not a valid entity class. Please check the entity mapping.
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:88) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.session.delegates.SaveDelegate.save(SaveDelegate.java:40) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.session.Neo4jSession.save(Neo4jSession.java:469) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_141]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_141]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_141]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_141]
at org.springframework.data.neo4j.transaction.SharedSessionCreator$SharedSessionInvocationHandler.invoke(SharedSessionCreator.java:131) ~[spring-data-neo4j-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at com.sun.proxy.$Proxy81.save(Unknown Source) ~[na:na]
org.neo4j.ogm.exception.core.TransactionManagerException: Transaction is not current for this thread
at org.neo4j.ogm.session.transaction.DefaultTransactionManager.rollback(DefaultTransactionManager.java:86) ~[neo4j-ogm-core-3.1.0.jar:3.1.0]
at org.neo4j.ogm.transaction.AbstractTransaction.rollback(AbstractTransaction.java:65) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
at org.neo4j.ogm.drivers.bolt.transaction.BoltTransaction.rollback(BoltTransaction.java:61) ~[neo4j-ogm-bolt-driver-3.1.0.jar:3.1.0]
at org.neo4j.ogm.transaction.AbstractTransaction.close(AbstractTransaction.java:144) ~[neo4j-ogm-api-3.1.0.jar:3.1.0]
at org.springframework.data.neo4j.transaction.Neo4jTransactionManager.doCleanupAfterCompletion(Neo4jTransactionManager.java:379) ~[spring-data-neo4j-5.0.8.RELEASE.jar:5.0.8.RELEASE]
Node Entity Name in dao.mylibrary.entity : Book
Node Entity Name in dao.rentallibrary.entity : RentedBook
Please let me know why this issue is occurring while using Neo4j repositories? Can't we use two Neo4j repositories with Spring data neo4j & Spring boot? Or Am I doing something wrong?
My Environment
OGM Version used: 3.1.0
Java Version used: 1.8
Neo4J Version used:3.2.3
Bolt Driver Version used (if applicable): 3.1.0
Operating System and Version: Windows
Please let me know if you need any additional information.
Update This has been addressed in Spring Data Neo4j Lovelace RC1 and we wrote a small howto: https://michael-simons.github.io/neo4j-sdn-ogm-tips/using_multiple_session_factories
Thanks for submitting this as GitHub issue #498.
It seems that the current Spring Data Neo4j version has a bug in propagating the different session factories to the repositories. In short: there is no way to make this work right now (for example like you can do with Spring Data JPA).
If you need (and want) repositories, I cannot help you right now. What work's however is injecting the different session factories:
#Autowired
#Qualifier("myUserSessionFactory")
private SessionFactory myUserSessionFactory;
#Autowired
#Qualifier("rentalUserSessionFactory")
private SessionFactory rentalUserSessionFactory;
and then do something like
Map<String, Object> params = new HashMap<>();
params.put("name", "test");
ThingEntity t = this.myUserSessionFactory.openSession().queryForObject(
ThingEntity.class,
"MATCH (n:`Thing`) WHERE n.name = $name WITH n RETURN n", params);
Regardless of the bug in our code, I recommend the following configuration. For the primary beans ("myUserconfiguration") use one config class
package gh.neo4jogm.gh498;
import gh.neo4jogm.gh498.domain1.ThingEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
#Configuration
#EnableNeo4jRepositories(
basePackages = Domain1Config.BASE_PACKAGE,
sessionFactoryRef = "myUserSessionFactory",
transactionManagerRef = "myUserTransactionManager"
)
#EntityScan(basePackageClasses = ThingEntity.class)
class Domain1Config {
static final String BASE_PACKAGE = "gh.neo4jogm.gh498.domain1";
#Primary
#Bean
#ConfigurationProperties("spring.data.neo4j")
public Neo4jProperties myNeo4jProperties() {
return new Neo4jProperties();
}
#Primary
#Bean
public org.neo4j.ogm.config.Configuration myUserconfiguration() {
return myNeo4jProperties().createConfiguration();
}
#Primary
#Bean
public SessionFactory myUserSessionFactory() {
return new SessionFactory(myUserconfiguration(), BASE_PACKAGE);
}
#Bean
public Neo4jTransactionManager myUserTransactionManager() {
return new Neo4jTransactionManager(myUserSessionFactory());
}
}
The basic idea is to use #ConfigurationProperties to map the default properties to an instance of Neo4jProperties (our properties class) and use it like we do create the action configuration.
The same then for the other session factory:
package gh.neo4jogm.gh498;
import gh.neo4jogm.gh498.domain2.OtherThingEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import static gh.neo4jogm.gh498.Domain2Config.BASE_PACKAGE;
#Configuration
#EnableNeo4jRepositories(
basePackages = BASE_PACKAGE,
sessionFactoryRef = "rentalUserSessionFactory",
transactionManagerRef = "rentalUsertransactionManager"
)
#EntityScan(basePackageClasses = OtherThingEntity.class)
class Domain2Config {
static final String BASE_PACKAGE = "gh.neo4jogm.gh498.domain2";
#Bean
#ConfigurationProperties("rental.data.neo4j")
public Neo4jProperties rentalNeo4jProperties() {
return new Neo4jProperties();
}
#Bean
public org.neo4j.ogm.config.Configuration rentalNeo4jconfiguration() {
return rentalNeo4jProperties().createConfiguration();
}
#Bean
public SessionFactory rentalUserSessionFactory() {
return new SessionFactory(rentalNeo4jconfiguration(), BASE_PACKAGE);
}
#Bean
public Neo4jTransactionManager rentalUsertransactionManager() {
return new Neo4jTransactionManager(rentalUserSessionFactory());
}
}
Here you map all properties prefixed with rental.data.neo4j to another properties instance.

Spring - Data persisted by JdbcTemplate unable to be seen by JpaRepository

I am building a Spring Boot application which requires the need for persistence via JDBC and selecting/reading via JPA/Hibernate. I have implemented both of these types of operations using Spring's JdbcTemplate and Spring Data's JpaRepository.
After I persist using JdbcTemplate I am unable to see the data via JpaRepository even though they share the same datasource. I am able to read the data if I use JdbcTemplate.
NOTE: I am using two data sources. One is configured in another class without the #Primary annotation using its own entity manager factory and transaction manager, which is why I've needed to explicitly define it below using Spring Boot's default bean terminology "transactionManager" and "entityManagerFactory".
The following is my embedded database configuration for the primary beans:
#Configuration
#EnableJpaRepositories(basePackages = {"com.repository"})
public class H2DataSourceConfiguration {
private static final Logger log = LoggerFactory.getLogger(H2DataSourceConfiguration.class);
#Bean(destroyMethod = "shutdown")
#Primary
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.setName("dataSource")
.build();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder, DataSource dataSource) {
return builder
.dataSource(dataSource)
.packages("com.my.domain", "org.springframework.data.jpa.convert.threeten")
.build();
}
#Bean
#Primary
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(entityManagerFactory);
return jpaTransactionManager;
}
}
The persistence happens in a different transaction to the reading of the data, however they share the same service.
Both operations happen within the #Transactional annotation. Both repository beans are specified in the same service and also contain the #Transactional annotation. The service looks as follows:
#Service
#Transactional
public class MyServiceImpl implements MyService {
private static final Logger log = LoggerFactory.getLogger(MyServiceImpl.class);
#Autowired
private MyJpaRepository myJpaRepository;
#Autowired
private MyJdbcRepository myJdbcRepository;
...
}
MyJdbcRepositoryImpl.java:
#Repository
#Transactional(propagation = Propagataion.MANDATORY)
public class MyJdbcRepositoryImpl implements MyJdbcRepository {
#Autowired
private NamedParameterJdbcTemplate jdbcTemplate;
// methods within here all use jdbcTemplate.query(...)
}
MyJpaRepository.java:
#Repository
#Transactional(propagation = Propagataion.MANDATORY)
public interface AcquisitionJpaRepository extends JpaRepository<AcquisitionEntity, Long> {
}
Is it at all possible that the jdbctemplate calls are saving to a different h2 database?
The above configuration is correct!
The problem was that the JdbcTemplate calls had the schema owner as a prefix.
For example:
select * from I_AM_SCHEMA.KILL_ME
However, I had both the #Entity annotation and the #Table annotation on the entity object and only specified the table name!
Example:
#Entity
#Table(name = "KILL_ME")
So, we were writing to one table with JdbcTemplate but reading from a completely different other table via JPA/Hibernate due to us missing the prefix.
The correct fix was to prefix the entity name in the #Entity annotation:
#Entity("I_AM_SCHEMA.KILL_ME")
DONE!

Spring-data-neo4j multiple graphs

I know there's some similar topic out there, but none of them gives a solution. So, if using Spring-data-neo4j, is there any way to connect to multiple graphs? NOT graphs in the same instance with different labels.
Or equivalently, I can ask this question:
How can I configure spring-data-neo4j to have multiple sessions to different Neo4j instances on different ports.
Thanks.
EDIT
Thanks to #Hunger, I think I am one step forward. Now the question is: how to confiture spring-data-neo4j to have multiple 'PereistenceContext' and each of them refers to an individual Neo4j instance.
You can configure different application contexts with different REST-API's declared pointing to different databases.
You should not mix objects or sessions from those different databases though.
So you might need qualifiers for injection.
How about having multiple configurations :
//First configuration
#Configuration
#EnableNeo4jRepositories(basePackages = "org.neo4j.example.repository.dev")
#EnableTransactionManagement
public class MyConfigurationDev extends Neo4jConfiguration {
#Bean
public Neo4jServer neo4jServer() {
return new RemoteServer("http://localhost:7474");
}
#Bean
public SessionFactory getSessionFactory() {
// with domain entity base package(s)
return new SessionFactory("org.neo4j.example.domain.dev");
}
// needed for session in view in web-applications
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
}
and another one
//Second config
#Configuration
#EnableNeo4jRepositories(basePackages = "org.neo4j.example.repository.test")
#EnableTransactionManagement
public class MyConfigurationDev extends Neo4jConfiguration {
#Bean
public Neo4jServer neo4jServer() {
return new RemoteServer("http://localhost:7475");
}
#Bean
public SessionFactory getSessionFactory() {
// with domain entity base package(s)
return new SessionFactory("org.neo4j.example.domain.test");
}
// needed for session in view in web-applications
#Bean
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return super.getSession();
}
}

Resources