相当于MyBatis Guice中的MyBatis XML多环境 [英] Equivalent of MyBatis XML multiple environments in MyBatis Guice

查看:163
本文介绍了相当于MyBatis Guice中的MyBatis XML多环境的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个需要根据上下文使用不同数据库的服务(一个简单的字符串标签)。每个数据库都具有完全相同的模式。数据库列表是动态的。

I'm writing a service that needs to use a different database depending on context (a simple string label). Each database has exactly the same schema. The list of databases is dynamic.

浏览关于多个数据源的MyBatis-Guice文档,该示例是预先知道数据源列表的位置,每个数据源都有不同的映射器。同样,发现此处SO 的问题也有相同的要求。

Looking through MyBatis-Guice documentation on multiple data sources, the example is where the list of datasources are known upfront, and each datasource has a different mapper. Similarly, a question found here on SO assumes the same requirements.

如上所述,我的要求更加动态和流畅。我们的想法是将所有当前已知的数据库(及其连接信息)放在配置中,并在服务启动时进行解析。然后,根据任何传入请求的上下文,代码应该为正确的数据库提取SqlSessionFactory。使用该SqlSessionFactory的所有下游代码完全相同 - 即不依赖于请求上下文。这意味着无论使用什么数据库都会使用相同的映射器。

As stated, my requirements are much more dynamic and fluid. The idea is to have all the currently known databases (with their connection information) in a config and have that parsed at service startup. Then, dependent upon the context of any incoming requests, the code should pull the SqlSessionFactory for the correct database. All downstream code that uses that SqlSessionFactory is exactly the same - i.e. not dependent on request context. Which means the same mappers are used no matter what database is required.

我的MyBatis和Guice知识无疑是新的和有限的。但是,我无法谷歌任何显示MyBatis-Guice等同于 MyBatis的XML配置支持多种环境方法。

My MyBatis and Guice knowledge is admittedly very new and limited. However, I've not been able to google anything that shows the MyBatis-Guice equivalent to the multiple environment approach supported by the XML configuration of MyBatis.

推荐答案

我设法提出了一个有效的解决方案对我来说,我想我会在这里分享。已经做出了使用Guice的决定,所以那里没有蠕动空间。

I managed to come up with a solution that works for me, so thought I'd share it here. The decision to use Guice had already been made, so there was no wriggle room there.

首先,我写了一个MyBatis Guice模块来注册一个数据源。它是 PrivateModule ,以便为一个数据源注册的所有MyBatis类不会与其他数据源的其他注册冲突。它使用内部MyBatisModule实现,因为Java不支持多重继承。意思是我们不能做公共类MyMyBatisModule扩展了PrivateModule,MyBatisModule {...}

First, I wrote a MyBatis Guice module for registering a single datasource. It is a PrivateModule so that all the MyBatis classes that get registered for one datasource do not conflict with other registrations for other datasources. It makes use of an internal MyBatisModule implementation because Java doesn't support multiple inheritance. Meaning we can't do public class MyMyBatisModule extends PrivateModule, MyBatisModule {...}.

public class MyMyBatisModule extends PrivateModule {

    private final String     datasourceLabel;
    private final Properies  datasourceProperties;
    private       List< Key<?> > exposedKeys = new ArrayList< Key<?> >();

    public MyMyBatisModule( String datasourceLabel, Properties datasourceProperties ) {

        this.datasourceLabel = datasourceLabel;
        this.datasourceProperties = datasourceProperties;
    }

    @Override
    protected void configure() {

        install( new InternalMyMyBatisModule( ) );

        for( Key<?> key: keys ) {
            expose( key );
        }
    }

    private class InternalMyMyBatisModule extends MyBatisModule {

        @Override
        protected void initialize( ) {

            environmentId( datasourceLabel );
            Names.bindProperties( binder(), properties );

            install( JdbcHelper.MySQL ); // See JDBC Helper commentary below

            bindDataSourceProviderType( C3p0DataSourceProvider.class ); // Choose whichever one you want
            bindTransactionFactoryType( JdbcTransactionFactory.class );

            // Register your mapper classes here.  These mapper classes will have their
            // keys exposed from the PrivateModule
            //
            // i.e.
            // 
            // keys.add( registerMapper( FredMapper.class );
            // kets.add( registerMapper( GingerMapper.class );
        }

        private <T> Key<T> registerMapper( Class<T> mapperClass ) {
            Key<T> key = Key.get( mapperClass, Names.named( datasourceLabel ) );
            bind( key ).to( mapperClass );
            addMapperClass( mapperClass );
            return key;
        }
    }
}

JdbcHeler.MySQL :我使用 JdbcHelper.MySQL 作为将属性映射到连接字符串的快捷方式,并使用 com .mysql.jdbc.Driver 作为JDBC驱动程序。声明为:

JdbcHeler.MySQL: I've used JdbcHelper.MySQL as a shortcut to map properties to the connection string, and use com.mysql.jdbc.Driver as the JDBC driver. It's declared as:

MySQL("jdbc:mysql://${JDBC.host|localhost}:${JDBC.port|3306}/${JDBC.schema}", "com.mysql.jdbc.Driver"),

现在是时候到了注册所有数据源。 MyBatisModules 为我们处理此问题。它需要一个datasourceLabel到jdbc属性的映射。

Now it's time to register all your datasources. MyBatisModules handles this for us. It requires a map of datasourceLabel to jdbc properties.

public class MyBatisModules extends AbstractModule {

    private Map< String, Properties > connectionsProperties;

    public MyBatisModules( Map< String, Properties > = new HashMap< String, Properties > connectionsProperties ) {
        this.connectionsProperties = connectionsProperties; // consider deep copy if appropriate
    }

    @Override
    protected void configure( ) {

        for( Entry< String, Properties > datasourceConnectionProperties : this.connectionsProperties.entrySet() ) {
            install( new MyMyBatisModule( datasourceConnectionProperties.getKey(), datasourceConnectionProperties.getValue() ) );
        }

        bind( MapperRetriever.class ); // See MapperRetriever later

        // bind your DAO classes here.  By wrapping MyBatis Mapper use in DAO implementations, theoretically we
        // can fairly easily change from MyBatis to any other database library just by changing the DAO implementation.
        // The rest of our codebase would remain the same.
        //
        // i.e.
        //
        // bind( FredDao.class ).to( FredDaoMyBatis.class );
        // bind( GingerDao.class).to( GingerDaoMyBatis.class );
    }
}

现在我们只需要一些方法来获得正确的Mapper class(它本身与正确的数据源相关联)。为此,我们实际上需要在Guice Injector上调用一个方法。我真的不喜欢传递它的想法,所以我把它包装在 MapperRetriever 中。您需要为每个 Mapper 实现检索方法。

Now we just need some way of getting the right Mapper class (which itself is associated with the right datasource). To do this, we actually need to call a method on the Guice Injector. I don't really like the idea of passing that around, so I wrapped it in MapperRetriever. You need to implement a retrieval method for each of your Mappers.

public class MapperRetriever {

    private final Injector injector;

    @Inject
    public MapperRetriver( Injector injector ) {
        this.injector = injector;
    }

    // The follwing two methods use the example Mappers referenced in the MyMyBatisModule implementation above

    public FredMapper getFredMapper( String datasourceLabel ) {
        return this.injector.getInstance( Key.get( FredMapper.class, Names.named( datasourceLabel ) ) );
    }

    public GingerMapper getGingerMapper( String datasourceLabel ) {
        return this.injector.getInstance( Key.get( GingerMapper.class, Names.named( datasourceLabel ) ) );
    }
}

以及DAO实施示例...

And an example DAO implementation ...

public interface FredDao {
    Fred selectFred( String datasourceLable, String fredId );
}    

public class FredDaoMyBatis implements FredDao {

    private MapperRetriever mapperRetriever;

    @Inject
    public FredDaoMyBatis( MapperRetriever mapperRetriever ) {
        this.mapperRetriever = mapperRetriever;
    }

    @Override
    public Fred selectFred( String datasourceLabel, String fredId ) {
        FredMapper fredMapper = this.mapperRetriever.getFredMapper( datasourceLabel );
        return fredMapper.getFred( fredId );
    }
}

这篇关于相当于MyBatis Guice中的MyBatis XML多环境的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆