Open viniciusxyz opened 1 year ago
You might be missing implementation("io.micronaut.data:micronaut-data-spring-jdbc")
. It's always better to have an added test to reproduce.
Did you try to measure performance with Micronaut Data repositories vs the template?
@dstepanov Until the last release I used only the micronaut-spring-annotation processor together with the spring-jdbc, micronaut-spring and micronaut-jdbc-hikari dependencies, adding the suggested dependency I start to see the exception:
Message: No current connection present. Consider declaring @Connectable or @Transactional on the surrounding method
Path Taken: new Migration(DataSource dataSource)
io.micronaut.context.exceptions.BeanInstantiationException: Bean definition [my.transaction.app.db.Migration] could not be loaded: Error instantiating bean of type [my.transaction.app.db.Migration]
Message: No current connection present. Consider declaring @Connectable or @Transactional on the surrounding method
Path Taken: new Migration(DataSource dataSource)
How to use spring-jdbc was discussed in issue #555
Regarding the performance tests, we did not manage to add the micronaut-data-repositories, we have a guideline of not "tying" the application to any framework, so we have a set of interfaces to be able to switch between Spring and Micronaut in a very simple way, but unfortunately, as previously the development was focused on spring and a large part of the code was focused on the database, we decided to go with something that worked in both frameworks, which in this case was spring-jdbc, when possible I will evaluate the micronaut-data-repositories and validate the possibility of creating a built-in compatibility layer between it and spring-jdbc for my team to use, but for now spring-jdbc support remains essential for us.
Please try annotating your custom repos @Connectable
.
@dstepanov With the dependencies present this annotation is not available, until version 3.x I never needed to add this annotation either
In the application that I left as an example, there is a project in micronaut 3 with everything working correctly and in another branch the project with micronaut 4 with the problems described
We extracted the Spring integration into our TX dependency. Please try adding micronaut-data-connection
dependency.
@dstepanov Added, unfortunately I have the same problem :/
I will check, please update the project
@dstepanov Both branches are up to date, they do not have the suggested changes as I preferred to keep micronaut 3 the way it works and micronaut 4 in the format that is delivered by the openrewrite update
I did an analysis, a little limited by my level of knowledge, but I hope it helps:
Validating the behavior of Micronaut 3 we have the following:
Watch the debug result item
Validating the behavior of Micronaut 4 we have the following:
Watch the debug result item
Here is the snippet I used to create the PlatformTransactionManager bean
@Factory
public class JdbcTemplateFactory {
private final DataSource dataSource;
@Bean
public PlatformTransactionManager provide(){
return new DataSourceTransactionManager(dataSource);
}
}
@dstepanov @graemerocher Is there anything else I can do to try to help resolve the issue? It seems to me that in version 3 the PlatformTranctionManager bean was created automatically and now it is not.
I will check next week
The solution is add this class:
import io.micronaut.context.annotation.EachBean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.context.annotation.Requires;
import io.micronaut.context.event.BeanCreatedEvent;
import io.micronaut.context.event.BeanCreatedEventListener;
import io.micronaut.context.event.BeanPreDestroyEventListener;
import jakarta.inject.Singleton;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import javax.sql.DataSource;
@Factory
@Requires(classes = DataSourceTransactionManager.class)
public class DataSourceTransactionManagerFactory {
/**
* For each {@link DataSource} add a {@link DataSourceTransactionManager} bean.
*
* @param dataSource The data source
* @return The bean to add
*/
@EachBean(DataSource.class)
DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(dataSource);
dataSourceTransactionManager.afterPropertiesSet();
return dataSourceTransactionManager;
}
/**
* For each data source, wrap in a {@link TransactionAwareDataSourceProxy}.
* @return The listener that will wrap each data source
*/
@Singleton
TransactionAwareDataSourceListener transactionAwareDataSourceListener() {
return new TransactionAwareDataSourceListener();
}
@Singleton
final BeanPreDestroyEventListener<DataSource> transactionAwareDataSourceListenerUnwrapper() {
return event -> {
DataSource ds = event.getBean();
if (ds instanceof TransactionAwareDataSourceProxy transactionAwareDataSourceProxy) {
return transactionAwareDataSourceProxy.getTargetDataSource();
}
return ds;
};
}
/**
* A {@link BeanCreatedEventListener} that wraps each data source in a transaction aware proxy.
*/
private static class TransactionAwareDataSourceListener implements BeanCreatedEventListener<DataSource> {
@Override
public DataSource onCreated(BeanCreatedEvent<DataSource> event) {
DataSource dataSource = event.getBean();
if (dataSource instanceof TransactionAwareDataSourceProxy) {
return dataSource;
} else {
return new TransactionAwareDataSourceProxy(dataSource);
}
}
}
}
@dstepanov Adding the class informed in the project everything works perfectly fine, I had imagined that an EachBean that configured this type of thing had been removed by mistake or something from 4.5.1 to 5.0.0, but when I searched the tag I did not find any that seems to be right and looking back now actually this class didn't exist in 4.5.1 so I'm not exactly sure how this worked before, can I add this to micronaut-spring and open a PR or is it already something you're working on?
It used to be in micronaut-sql, but I'm not sure if we want to add it back.
@dstepanov I think it's important to at least have some configuration to indicate whether this should be active or not, even if it is disabled by default, when I migrated from spring to micronaut, spring-jdbc worked equally in micronaut and spring was something that certainly reduced our time of migration in a few months and for those who are in the same situation as mine and had done the migration that way, but there are no tests that point out defects in the behavior of the transactions can lead to problems for production with the update to micronaut 4
For my particular project the proposed solution solves the problem, but it would be a shame not to see this working by default in the framework
Expected Behavior
Hopes that when performing the update with openrewrite the application will continue to work correctly including integration with spring jdbcTemplate
Actual Behaviour
When performing an update and calling an endpoint that invokes a service marked with @transaction, the following exception is thrown: "No transaction manager configured"
For comparison purposes the project has a branch h2-micronaut4 and another h2-micronaut3 where using the branch with micronaut 3 the project works correctly.
We chose to use spring's jdbc-template in conjunction with our micronaut applications because it makes migration and switching between frameworks easier and also because it offers better performance in our tests than other options and in the company where I work, performance on database operations is something very critical, for comparison is the graph below:
The title at the top of the chart says "Account Search"
Steps To Reproduce
mvn mn:run
If there is anything I can do to bring more detailed data and help understand the source of the problem please let me know.
Environment Information
Example Application
https://github.com/viniciusxyz/micronaut-transaction-failed/tree/h2-micronaut4
Version
4.0.1