Skip to content

Commit 88e6c30

Browse files
GH-1578 - Improve Docs about Spring Data REST needing an open-session-in-view interceptor.
This closes #1578.
1 parent 816588a commit 88e6c30

File tree

2 files changed

+108
-0
lines changed

2 files changed

+108
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ target/
1515
*.db
1616
.DS_Store
1717
.classpath
18+
.flattened-pom.xml

src/main/asciidoc/faq.adoc

+107
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ OGM can be seen on the same level as a JPA implementation like Hibernate in the
1010

1111
How do I set up my Spring Configuration with Spring WebMVC projects?::
1212
If you are using a Spring WebMVC application, the following configuration is all that's required:
13+
+
1314
[source,java]
1415
----
1516
@Configuration
@@ -32,8 +33,114 @@ public class MyWebAppConfiguration extends WebMvcConfigurerAdapter {
3233
}
3334
----
3435

36+
Do I need to setup an `OpenSessionInViewFilter`?::
37+
It depends but in most cases the answer is _no_.
38+
+
39+
First let's recap what a so called `OpenSessionInViewFilter` does:
40+
As soon as a web request arrives at your application it will make sure, a write transaction is opened and every interaction
41+
with the Neo4j database will happen in that transaction.
42+
+
43+
While this removes the need to think about transactional boundaries, it comes at a price:
44+
As the filter cannot know upfront whether you will only execute read queries or will execute writes.
45+
Therefore it will open a write transaction. In a cluster environment that will prevent load distribution among the read replicas,
46+
as they would not be able to answer writes.
47+
+
48+
The general recommendation is to wrap a chain of calls to the Neo4j-OGM session or any repository inside a dedicated service like this:
49+
+
50+
[source,java]
51+
----
52+
@Service
53+
public class MyService {
54+
// If you need the session, it should be injected like that
55+
// The infrastructure will make sure it is always one that fits your transaction.
56+
// private final Session session;
57+
58+
private final MyRepository myRepository;
59+
60+
public MyService(MyRepository myRepository) {
61+
this.myRepository = myRepository;
62+
}
63+
64+
@Transactional // <.>
65+
public void doSomething() {
66+
MyObject thing = userRepository.findByName("whatever");
67+
thing.setProperty("newValue");
68+
userRepository.save(thing);
69+
}
70+
}
71+
----
72+
<.> Call this method from your web controller instead of relying on the OSIV interceptor.
73+
Thus you have a clean transactional boundary at the service level.
74+
+
75+
If you still want to have the interceptor, you can enable it on a Spring Boot application with `spring.data.neo4j.open-in-view=true` or in a plain Spring application with a configuration like that:
76+
+
77+
[source,java]
78+
----
79+
import org.springframework.context.annotation.Bean;
80+
import org.springframework.context.annotation.Configuration;
81+
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
82+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
83+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
84+
85+
@Configuration
86+
public class MyWebAppConfiguration {
87+
88+
@Bean
89+
public OpenSessionInViewInterceptor openSessionInViewInterceptor() {
90+
return new OpenSessionInViewInterceptor();
91+
}
92+
93+
@Bean
94+
WebMvcConfigurer osivMvcConfigurer(
95+
OpenSessionInViewInterceptor openSessionInViewInterceptor
96+
) {
97+
return new WebMvcConfigurer() {
98+
@Override
99+
public void addInterceptors(InterceptorRegistry registry) {
100+
registry.addWebRequestInterceptor(openSessionInViewInterceptor);
101+
}
102+
};
103+
}
104+
}
105+
----
106+
+
107+
IMPORTANT: There is one special case in which you do *need* an open-session-in-view interceptor and that is when
108+
you use Spring Data Neo4j with https://spring.io/projects/spring-data-rest[Spring Data Rest]. In that case
109+
however you don't have control over the transactional boundaries. The `PUT` request for example will be executed
110+
with at least two repository interactions originating at the request handler.
111+
+
112+
Also, the configuration above or the Spring Boot property will not be enough to enable open-session-in-view.
113+
Instead you want to use a configuration as shown in <<faq.osiv-for-data-rest>>.
114+
+
115+
[[faq.osiv-for-data-rest]]
116+
.Enable open-session-in-view for Spring Data Rest
117+
[source,java]
118+
----
119+
import org.springframework.context.annotation.Bean;
120+
import org.springframework.context.annotation.Configuration;
121+
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
122+
import org.springframework.web.servlet.handler.MappedInterceptor;
123+
124+
@Configuration
125+
public class MyWebAppConfigurationForSpringDataRest {
126+
127+
@Bean // <.>
128+
public OpenSessionInViewInterceptor openSessionInViewInterceptor() {
129+
return new OpenSessionInViewInterceptor();
130+
}
131+
132+
@Bean // <.>
133+
public MappedInterceptor mappedOSIVInterceptor(OpenSessionInViewInterceptor openSessionInViewInterceptor) {
134+
return new MappedInterceptor(new String[] { "/**" }, openSessionInViewInterceptor);
135+
}
136+
}
137+
----
138+
<.> You don't need this bean if you already have the open-session-in-view interceptor, either through the Spring Boot property or manual configuration.
139+
<.> This `MappedInterceptor` is required to enable open-session-in-view for Spring Data Rest.
140+
35141
How do I set up my Spring Configuration with a Java Servlet 3.x+ Container project?::
36142
If you are using a Java Servlet 3.x+ Container, you can configure a Servlet filter with Spring's `AbstractAnnotationConfigDispatcherServletInitializer` like this:
143+
+
37144
[source,java]
38145
----
39146
public class MyAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

0 commit comments

Comments
 (0)