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=DEBUGYou must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 46 | |
| 41 | |
| 38 | |
| 36 | |
| 30 | |
| 28 | |
| 27 | |
| 24 | |
| 24 | |
| 23 |