mybatis / guice

Google Guice integration for MyBatis 3
http://mybatis.github.io/guice
Apache License 2.0
174 stars 118 forks source link

Support for multiple DataSources or Environment #709

Open robotdan opened 4 months ago

robotdan commented 4 months ago

Description

Mybatis supports multiple environments which should allow you to bind a mapper to more than one DataSource. This would allow me to decide at runtime which connection pool I want to use based upon the request.

From what I can tell, MyBatis Spring does support this concept. The MyBatis Guice module assumes a single DataSource or single Environment.

What I'd like to be able to do is bind one to many DataSource instances, by way of DataSourceProvider , EnvironmentProvider, or something else.

Example usage at runtime:

private final UserMapper primaryUserMapper;

private final UserMapper secondaryUserMapper;

@Inject
public ExampleService(@Named("Primary") UserMapper primaryUserMapper, 
                      @Named("Secondary") UserMapper secondaryUserMapper) {
  this.primaryUserMapper = primaryUserMapper;
  this.secondaryUserMapper = secondaryUserMapper;
}

I have find a few SO articles that claim to have pulled it off using a PrivateModule, but I have yet to get them to work for my use case.

Here is one of the examples:

Have you considered adding this support, or would you be open to accepting a PR to add this support? If you would be open to accepting a PR, do you have any opinion or suggestion on what would need to change to the current module?

I am still working to get more of a complete solution working if I can pull it off, I would be open to either trying to retro fit it to the existing module.

I a partial solution by just injecting the SQLSessionManager and opening a new connection based upon a specific DataSource but this is not idea as I have to manage all of the transaction handling myself and I can no longer just simply inject a mapper into a service.

Related documentation

christianpoitras commented 3 months ago

It is possible to use multiple DataSources using PrivateModules but it does not look easy. I checked some old conversations about this and there are multiple gotchas along the way. The most difficult one being to support transactions.

If you want to support transactions across multiple DataSource instances, you will need an external transaction manager since MyBatis-Guice does not have much support for this. The only support is for XA transactions that was programmed by a user of MyBatis-Guice.

If you accept to have a separate transaction per DataSource, then you can just use PrivateModules. The main issue here is to expose the mappers/services properly.

There is no documentation about multiple DataSource mostly because I was not confident enough I could write a documentation that would be complete. Especially since I never used MyBatis-Guice with more than one DataSource instance.

You can write a PR if you find a better way to support multiple DataSources. The main problem of MyBatis-Guice is that there is no more people driving the project unlike MyBatis-Spring.

robotdan commented 3 months ago

Thanks @christianpoitras appreciate the response.

I did get it all working with PrivateModule - it wasn't super easy.

Binding everything private wasn't so difficult, but wrapping my head around how Guice Private Modules and getting the visibility correct for services, etc., was a learning curve.

I also had to implement my own interceptor for @Transactional since the interceptor bound in MyBatisModule is now private and it won't have any visibility to the services bound in the parent. Also, in my case, I also wanted @Transactional to work on various datasources, so I had to make mine aware of multiple instances of SqlSessionManager.

Perhaps if anyone else chimes in on this thread to show interest, I could put together a boiler plate reference or put up a PR for some minor updates to the library that would have allowed me to accomplish my goals a bit easier.