Skip to content

Commit 0e40d90

Browse files
GH-2888 - Respect multiple Neo4jTransactionManagers.
There might be different transaction managers in place for different Neo4jTemplates. The change is also applied to the ReactiveNeo4jTemplate. Co-authored-by: Michael Simons <[email protected]>
1 parent c02dd5a commit 0e40d90

File tree

4 files changed

+71
-16
lines changed

4 files changed

+71
-16
lines changed

src/main/java/org/springframework/data/neo4j/core/Neo4jTemplate.java

+32-7
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,17 @@ public Neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingCo
158158
this(neo4jClient, neo4jMappingContext, EntityCallbacks.create());
159159
}
160160

161+
public Neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, PlatformTransactionManager transactionManager) {
162+
this(neo4jClient, neo4jMappingContext, EntityCallbacks.create(), transactionManager);
163+
}
164+
161165
public Neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
162166
EntityCallbacks entityCallbacks) {
167+
this(neo4jClient, neo4jMappingContext, entityCallbacks, null);
168+
}
169+
170+
public Neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
171+
EntityCallbacks entityCallbacks, @Nullable PlatformTransactionManager platformTransactionManager) {
163172

164173
Assert.notNull(neo4jClient, "The Neo4jClient is required");
165174
Assert.notNull(neo4jMappingContext, "The Neo4jMappingContext is required");
@@ -170,6 +179,7 @@ public Neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingCo
170179
this.eventSupport = EventSupport.useExistingCallbacks(neo4jMappingContext, entityCallbacks);
171180
this.renderer = Renderer.getDefaultRenderer();
172181
this.elementIdOrIdFunction = SpringDataCypherDsl.elementIdOrIdFunction.apply(null);
182+
setTransactionManager(platformTransactionManager);
173183
}
174184

175185
ProjectionFactory getProjectionFactory() {
@@ -1102,20 +1112,35 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
11021112
this.elementIdOrIdFunction = SpringDataCypherDsl.elementIdOrIdFunction.apply(cypherDslConfiguration.getDialect());
11031113
this.cypherGenerator.setElementIdOrIdFunction(elementIdOrIdFunction);
11041114

1105-
PlatformTransactionManager transactionManager = beanFactory.getBeanProvider(PlatformTransactionManager.class).getIfUnique(() -> beanFactory.getBean(Neo4jTransactionManager.class));
1106-
this.transactionTemplate = new TransactionTemplate(transactionManager);
1107-
this.transactionTemplateReadOnly = new TransactionTemplate(transactionManager, readOnlyTransactionDefinition);
1115+
if (this.transactionTemplate != null && this.transactionTemplateReadOnly != null) {
1116+
return;
1117+
}
1118+
PlatformTransactionManager transactionManager = null;
1119+
var it = beanFactory.getBeanProvider(PlatformTransactionManager.class).stream().iterator();
1120+
while (it.hasNext()) {
1121+
PlatformTransactionManager transactionManagerCandidate = it.next();
1122+
if (transactionManagerCandidate instanceof Neo4jTransactionManager neo4jTransactionManager) {
1123+
if (transactionManager != null) {
1124+
throw new IllegalStateException("Multiple Neo4jTransactionManagers are defined in this context. " +
1125+
"If this in intended, please pass the transaction manager to use with this Neo4jTemplate in the constructor");
1126+
}
1127+
transactionManager = neo4jTransactionManager;
1128+
}
1129+
}
1130+
setTransactionManager(transactionManager);
11081131
}
11091132

11101133
// only used for the CDI configuration
11111134
public void setCypherRenderer(Renderer rendererFromCdiConfiguration) {
11121135
this.renderer = rendererFromCdiConfiguration;
11131136
}
11141137

1115-
// only used for the CDI configuration
1116-
public void setTransactionManager(PlatformTransactionManager platformTransactionManager) {
1117-
this.transactionTemplate = new TransactionTemplate(platformTransactionManager);
1118-
this.transactionTemplateReadOnly = new TransactionTemplate(platformTransactionManager, readOnlyTransactionDefinition);
1138+
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
1139+
if (transactionManager == null) {
1140+
return;
1141+
}
1142+
this.transactionTemplate = new TransactionTemplate(transactionManager);
1143+
this.transactionTemplateReadOnly = new TransactionTemplate(transactionManager, readOnlyTransactionDefinition);
11191144
}
11201145

11211146
@Override

src/main/java/org/springframework/data/neo4j/core/ReactiveNeo4jTemplate.java

+31-3
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,14 @@ public boolean isReadOnly() {
150150
private ProjectionFactory projectionFactory;
151151

152152
private Renderer renderer;
153+
153154
private Function<Named, FunctionInvocation> elementIdOrIdFunction;
154155

155156
public ReactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext) {
157+
this(neo4jClient, neo4jMappingContext, null);
158+
}
159+
160+
public ReactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, @Nullable ReactiveTransactionManager transactionManager) {
156161

157162
Assert.notNull(neo4jClient, "The Neo4jClient is required");
158163
Assert.notNull(neo4jMappingContext, "The Neo4jMappingContext is required");
@@ -163,6 +168,7 @@ public ReactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContex
163168
this.eventSupport = ReactiveEventSupport.useExistingCallbacks(neo4jMappingContext, ReactiveEntityCallbacks.create());
164169
this.renderer = Renderer.getDefaultRenderer();
165170
this.elementIdOrIdFunction = SpringDataCypherDsl.elementIdOrIdFunction.apply(null);
171+
setTransactionManager(transactionManager);
166172
}
167173

168174
ProjectionFactory getProjectionFactory() {
@@ -1182,10 +1188,32 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
11821188
this.renderer = Renderer.getRenderer(cypherDslConfiguration);
11831189
this.elementIdOrIdFunction = SpringDataCypherDsl.elementIdOrIdFunction.apply(cypherDslConfiguration.getDialect());
11841190
this.cypherGenerator.setElementIdOrIdFunction(elementIdOrIdFunction);
1185-
ReactiveTransactionManager reactiveTransactionManager = beanFactory.getBeanProvider(ReactiveTransactionManager.class)
1186-
.getIfUnique(() -> beanFactory.getBean(ReactiveNeo4jTransactionManager.class));
1187-
this.transactionalOperatorReadOnly = TransactionalOperator.create(reactiveTransactionManager, readOnlyTransactionDefinition);
1191+
1192+
if (this.transactionalOperator != null && this.transactionalOperatorReadOnly != null) {
1193+
return;
1194+
}
1195+
1196+
ReactiveTransactionManager reactiveTransactionManager = null;
1197+
var iter = beanFactory.getBeanProvider(ReactiveTransactionManager.class).stream().iterator();
1198+
while (iter.hasNext()) {
1199+
ReactiveTransactionManager transactionManagerCandidate = iter.next();
1200+
if (transactionManagerCandidate instanceof ReactiveNeo4jTransactionManager reactiveNeo4jTransactionManager) {
1201+
if (reactiveTransactionManager != null) {
1202+
throw new IllegalStateException("Multiple ReactiveNeo4jTransactionManagers are defined in this context. " +
1203+
"If this in intended, please pass the transaction manager to use with this ReactiveNeo4jTemplate in the constructor");
1204+
}
1205+
reactiveTransactionManager = reactiveNeo4jTransactionManager;
1206+
}
1207+
}
1208+
setTransactionManager(reactiveTransactionManager);
1209+
}
1210+
1211+
private void setTransactionManager(@Nullable ReactiveTransactionManager reactiveTransactionManager) {
1212+
if (reactiveTransactionManager == null) {
1213+
return;
1214+
}
11881215
this.transactionalOperator = TransactionalOperator.create(reactiveTransactionManager);
1216+
this.transactionalOperatorReadOnly = TransactionalOperator.create(reactiveTransactionManager, readOnlyTransactionDefinition);
11891217
}
11901218

11911219
@Override

src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain1/Domain1Config.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ public Neo4jClient domain1Client(@Qualifier("domain1Driver") Driver driver) {
6363
@Primary @Bean
6464
public Neo4jOperations domain1Template(
6565
@Qualifier("domain1Client") Neo4jClient domain1Client,
66-
@Qualifier("domain1Context") Neo4jMappingContext domain1Context
66+
@Qualifier("domain1Context") Neo4jMappingContext domain1Context,
67+
@Qualifier("domain1Manager") PlatformTransactionManager domain1TransactionManager
6768
) {
68-
return new Neo4jTemplate(domain1Client, domain1Context);
69+
return new Neo4jTemplate(domain1Client, domain1Context, domain1TransactionManager);
6970
}
7071

7172
@Primary @Bean
@@ -78,7 +79,7 @@ public PlatformTransactionManager domain1Manager(
7879

7980
@Primary @Bean
8081
public DatabaseSelectionProvider domain1Selection() {
81-
return () -> DatabaseSelection.undecided();
82+
return DatabaseSelection::undecided;
8283
}
8384

8485
@Primary @Bean

src/test/java/org/springframework/data/neo4j/integration/multiple_ctx_imperative/domain2/Domain2Config.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ public Neo4jClient domain2Client(@Qualifier("domain2Driver") Driver driver) {
6262
@Bean
6363
public Neo4jOperations domain2Template(
6464
@Qualifier("domain2Client") Neo4jClient domain2Client,
65-
@Qualifier("domain2Context") Neo4jMappingContext domain2Context
65+
@Qualifier("domain2Context") Neo4jMappingContext domain2Context,
66+
@Qualifier("domain2Manager") PlatformTransactionManager domain2TransactionManager
6667
) {
67-
return new Neo4jTemplate(domain2Client, domain2Context);
68+
return new Neo4jTemplate(domain2Client, domain2Context, domain2TransactionManager);
6869
}
6970

7071
@Bean
@@ -77,7 +78,7 @@ public PlatformTransactionManager domain2Manager(
7778

7879
@Bean
7980
public DatabaseSelectionProvider domain2Selection() {
80-
return () -> DatabaseSelection.undecided();
81+
return DatabaseSelection::undecided;
8182
}
8283

8384
@Bean

0 commit comments

Comments
 (0)