Skip to content

Commit bf5912f

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 147a3fd commit bf5912f

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

Lines changed: 32 additions & 7 deletions
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() {
@@ -1095,20 +1105,35 @@ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
10951105
this.elementIdOrIdFunction = SpringDataCypherDsl.elementIdOrIdFunction.apply(cypherDslConfiguration.getDialect());
10961106
this.cypherGenerator.setElementIdOrIdFunction(elementIdOrIdFunction);
10971107

1098-
PlatformTransactionManager transactionManager = beanFactory.getBeanProvider(PlatformTransactionManager.class).getIfUnique(() -> beanFactory.getBean(Neo4jTransactionManager.class));
1099-
this.transactionTemplate = new TransactionTemplate(transactionManager);
1100-
this.transactionTemplateReadOnly = new TransactionTemplate(transactionManager, readOnlyTransactionDefinition);
1108+
if (this.transactionTemplate != null && this.transactionTemplateReadOnly != null) {
1109+
return;
1110+
}
1111+
PlatformTransactionManager transactionManager = null;
1112+
var it = beanFactory.getBeanProvider(PlatformTransactionManager.class).stream().iterator();
1113+
while (it.hasNext()) {
1114+
PlatformTransactionManager transactionManagerCandidate = it.next();
1115+
if (transactionManagerCandidate instanceof Neo4jTransactionManager neo4jTransactionManager) {
1116+
if (transactionManager != null) {
1117+
throw new IllegalStateException("Multiple Neo4jTransactionManagers are defined in this context. " +
1118+
"If this in intended, please pass the transaction manager to use with this Neo4jTemplate in the constructor");
1119+
}
1120+
transactionManager = neo4jTransactionManager;
1121+
}
1122+
}
1123+
setTransactionManager(transactionManager);
11011124
}
11021125

11031126
// only used for the CDI configuration
11041127
public void setCypherRenderer(Renderer rendererFromCdiConfiguration) {
11051128
this.renderer = rendererFromCdiConfiguration;
11061129
}
11071130

1108-
// only used for the CDI configuration
1109-
public void setTransactionManager(PlatformTransactionManager platformTransactionManager) {
1110-
this.transactionTemplate = new TransactionTemplate(platformTransactionManager);
1111-
this.transactionTemplateReadOnly = new TransactionTemplate(platformTransactionManager, readOnlyTransactionDefinition);
1131+
public void setTransactionManager(@Nullable PlatformTransactionManager transactionManager) {
1132+
if (transactionManager == null) {
1133+
return;
1134+
}
1135+
this.transactionTemplate = new TransactionTemplate(transactionManager);
1136+
this.transactionTemplateReadOnly = new TransactionTemplate(transactionManager, readOnlyTransactionDefinition);
11121137
}
11131138

11141139
@Override

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

Lines changed: 31 additions & 3 deletions
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

Lines changed: 4 additions & 3 deletions
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

Lines changed: 4 additions & 3 deletions
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)