com.sap.cds.CdsDataStoreConnector
we need first to:javax.sql.Datasource
. For the sake of simplicity we will use the external configuration properties (primary.datasource.*
).@Primary
@Bean
@ConfigurationProperties(prefix = "primary.datasource")
public DataSource ds() {
return DataSourceBuilder.create().build();
}
PlatformTransactionManager
bean using Spring DataSourceTransactionManager
which supports NESTED propagation out-of-the-box. This allows to execute queries within a nested transaction if a current transaction exists.@Primary
@Bean
public PlatformTransactionManager transactionManager(DataSource ds) {
return new DataSourceTransactionManager(ds);
}
CdsDataStoreConnector
bean, using a wrapped (managed) connection of a javax.sql.Datasource
, thus allowing to avoid physical close of the transactional connecton.@Primary
@Bean
public CdsDataStoreConnector cdsDataStoreConnector(DataSource ds, CdsTransactionManager transactionManager)
throws IOException {
final Supplier managedConnection = () -> wrapConnection(ds, DataSourceUtils.getConnection(ds));
return CdsDataStoreConnector.createJdbcConnector(getCdsModel(), transactionManager).connection(managedConnection).build();
}
com.sap.cds.transaction.TransactionManager
, used by Cds4j to check, whether there exists an active transaction or the whole transaction should be rolled back.@Configuration
public class CdsTransactionManager implements TransactionManager {
@Override
public boolean isActive() {
return TransactionSynchronizationManager.isActualTransactionActive();
}
@Override
public void setRollbackOnly() {
TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
}
}
CdsDataStoreConnector
.@Primary
the named beans are to be registered and referenced by name in the application.entity Book {
key id : Integer;
title : String;
}
entity Author {
key id : Integer;
name : String;
}
@Component
public class BookService {
private final CdsDataStore dataStore;
...
public BookService(CdsDataStoreConnector primaryConnector) {
this.dataStore = primaryConnector.connect();
...
}
@Transactional
public void saveBooks(List<Map> books) {
CqnInsert insert = Insert.into("Book").entries(books);
dataStore.execute(insert);
}
@Transactional
public Result readAllBooks() {
CqnSelect select = Select.from("Book");
return dataStore.execute(select);
}
...
}
@Component
public class AuthorService {
private final CdsDataStore dataStore;
public AuthorService(@Qualifier("secondary") CdsDataStoreConnector secondaryConnector) {
dataStore = secondaryConnector.connect();
}
@Transactional(transactionManager = "secondaryTx")
public void saveAuthors(List<Map<String, Object>> authors) {
CqnInsert insert = Insert.into("Author").entries(authors);
dataStore.execute(insert);
}
...
}
@Transactional
annotation, which defines the transactional boundaries.@Qualifier("secondary")
and @Transactional(transactionManager = "secondaryTx")
for the secondary data source. This is the way to distinguish between the data sources currently operated on.@RunWith(SpringRunner.class)
@SpringBootTest
public class IntegrationTest {
@Autowired
private BookService bookService;
@Autowired
private AuthorService authorService;
...
@Test
public void testWriteReadDataFrom2DataSources() {
bookService.saveBooks(booksData);
authorService.saveAuthors(authorsData);
Result allBooks = bookService.readAllBooks();
Result allAuthors = authorService.readAllAuthors();
assertThat(allBooks.toJson()).isEqualTo(expectedBooksJson);
assertThat(allAuthors.toJson()).isEqualTo(expectedAuthorsJson);
}
...
}
application.properties
.logging.level.ROOT=INFO
logging.level.org.springframework.jdbc=DEBUG
logging.level.com.sap.cds.impl=DEBUG
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
37 | |
25 | |
17 | |
13 | |
7 | |
7 | |
7 | |
6 | |
6 | |
6 |