quarkiverse / quarkus-mybatis

Quarkus MyBatis Extension
Apache License 2.0
91 stars 33 forks source link

Multitenancy support #253

Open franck102 opened 1 year ago

franck102 commented 1 year ago

Hi,

Is there any recommended pattern for implementing multitenancy support using a schema-per-tenant approach using this extension?

The SQLSessionFactory.openSession method would be the perfect place to configure the connection for a tenant, however it looks like the build steps have hardcoded the use of org.apache.ibatis.session.SqlSessionFactoryBuilder which in turn will always resort to org.apache.ibatis.session.defaults.DefaultSqlSessionFactory.

Is there any way to provide a custom session or factory to the extension?

franck102 commented 1 year ago

I see that this build step is "overrideable" in the extension:

@BuildStep
    @Overridable
    SqlSessionFactoryBuilderBuildItem createSqlSessionFactoryBuilder() {
        return new SqlSessionFactoryBuilderBuildItem(new SqlSessionFactoryBuilder());
    }

... however I cannot find documentation or examples on how I could override an extension's build step, either in my app or in an "extension's extension"... any pointers?

Thanks!

zhfeng commented 1 year ago

Well, This @Overridable method can be used in another extension. You can find one in mybatis-plus, see https://github.com/quarkiverse/quarkus-mybatis/blob/master/mybatis-plus/deployment/src/main/java/io/quarkiverse/mybatis/plus/deployment/MyBatisPlusProcessor.java#L57

franck102 commented 1 year ago

Makes sense, are there any documentation or examples explaining how you can write an "extension's extension"? I did read Building my first extension and the Writing your own extension If not I will use the examples in the guide, a few questions to help me get started:

Thanks!

zhfeng commented 1 year ago

Yeah, please refer to the quarkus guides. We all start from there .

I assume that my MyBatisMultitenant extension will be mostly empty and needs only declare the BuildStep I want to override

Yeah, and you need to add quarkus-mybatis as a dependency in pom.xml as well.

Can I / should I somehow declare the relationship between the extensions - Multitenant will require MyBatis?

Sure, see above comment.

I assume all it takes to override a build step is to provide the annotated method that returns the same type (SqlSessionFactoryBuilderBuildItem here)?

Yeah, you are right. Please check SqlSessionFactoryBuilderBuildItem and you should set your new implementation of SqlSessionFactoryBuilder.

Do I somehow need to specify an ordering between the 2 extensions to make sure that the multitenant BuildStep replaces the MyBatis bean (and not the opposite)?

No, I don't think so.

And if you like, I'm happy to add it as a part of quarkus-mybatis extension such like quakrkus-mybatis-plus. WDYT?

franck102 commented 1 year ago

I think it would make a lot of sense having an extension for just multitenancy, the approach is very well described for oidc and for hibernate, but I couldn’t find anything related to MyBatis. I am not using mybatis-plus and I don’t plan to, so a separate extension would probably be more flexible. I will experiment and get back to you if I manage to get something working

zhfeng commented 1 year ago

Sorry for the confusion and I just proposal to have quarkus-mybatis-multitenancy as a separate module and host in https://github.com/quarkiverse/quarkus-mybatis. Then we can take care of the maintain and release works with other extensions. Also it should be easy to be availiable on https://code.quarkus.io/?extension-search=origin:other%20mybatis

franck102 commented 1 year ago

That would make sense... however I looked into this today and I can't figure oI tried ut a proper design.

I can use extensions to create my custom SqlSessionFactory, but I don't know how to obtain the current RoutingContext from inside openSession (short of using thread locals which doesn't seem great). I tried creating a custom interceptor binding in the extension, with openSession annotated so it could be intercepted, but it seems I can't use the interceptor binding from my app (I am getting an "Interceptor has no bindings" trying to build).

I feel there is to much I don't know about Quarkus & CDI to design something solid, so hopefully someone more capable can look into this.

zhfeng commented 1 year ago

You may refer to Quarkus CDI guide and also

Feel free to share your thoughts and codes, I think we can find some experts from Quarkus community to help to figure it out. Aslo it would be a great opportunity to learn more details about Quarkus Extension development.

Good luck!

eggyknap commented 1 year ago

I'd love to see something like this, too. In my case, I'd like to adjust what user credentials are used to connect to the database, based on authentication details provided to quarkus. I'm new to mybatis, but I think outside of quarkus that would be supported by a custom DataSourceFactory. I tried making a mybatis XML configuration that referred to a simple datasourcefactory implementation, to no avail.

zhfeng commented 1 year ago

@eggyknap Are you interesting to work on it?

eggyknap commented 1 year ago

That's a reasonable question. I'll need to think about it. I'll mention it here if I feel I can contribute. I feel much like @franck102 : there's a lot about quarkus and CDI I don't know.