有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java MyBatis使用单个映射器提供多个数据源

我正在开发一个系统,该系统使用guice绑定和注入MyBatis映射器,用于从不同的数据库中删除条目。事实上,所有数据库都位于不同的主机中,但具有相同的结构。因为有很多,而且主机的数量和位置经常变化,所以我想安装一个MyBatis模块,其中包含使用同一映射器动态加载的不同数据源

我一直在四处寻找,但不知道如何解决映射器的模糊性。我还查看了MyBatis beans CDI插件,它使添加具有多个数据源的命名映射器变得更容易,但仍然无法使其工作,因为我没有可以命名的固定数据源列表

我是否错过了实现这一目标的简单方法


共 (3) 个答案

  1. # 1 楼答案

    您需要私下绑定MyBatisModule,并使用唯一的绑定属性公开映射。下面有一个例子。我已经证实它也有效:)

    DaoModule:此模块设置为将单个映射器绑定到具有特定数据源的密钥。请注意,这个类扩展了一个“PrivateModue”,并将密钥公开给父模块。您将使用此键注入映射

    public class DaoModule<T> extends PrivateModule {
    
        private static final String ENVIRONMENT_ID = "development";
    
        private final Key<T> key;
        private final Class<T> mapper;
        private final Provider<DataSource> dataSourceProvider;
    
        public DaoModule(Key<T> key, Class<T> mapper, Provider<DataSource> dataSourceProvider) {
            this.key = key;
            this.mapper = mapper;
            this.dataSourceProvider = dataSourceProvider;
        }
    
        @Override
        protected void configure() {
            install(new InnerMyBatisModule());
            expose(key);
        }
    
        private class InnerMyBatisModule extends MyBatisModule {
            @Override
            protected void initialize() {
                bind(key).to(mapper);
                addMapperClass(mapper);
    
                environmentId(ENVIRONMENT_ID);
                bindDataSourceProvider(dataSourceProvider);
                bindTransactionFactoryType(JdbcTransactionFactory.class);
            }
        }
    }
    

    MyModule:此模块通过两个不同的键和不同的数据源安装两个具有相同映射器类型的DAO模块

    public class MyModule extends AbstractModule {
    
        @Override
        protected void configure() {
            Key<MapperDao> key1 = Key.get(MapperDao.class, Names.named("Mapper1"));
            Provider<DataSource> datasource1 = null;
    
            Key<MapperDao> key2 = Key.get(MapperDao.class, Names.named("Mapper2"));
            Provider<DataSource> datasource2 = null;
    
            install(new DaoModule<MapperDao>(key1, MapperDao.class, datasource1));
            install(new DaoModule<MapperDao>(key2, MapperDao.class, datasource2));
        }
    }
    

    Main:Main获取两个类型相同但数据源不同的映射器

    public class Main {
        public static void main(String... args) {
            Injector i = Guice.createInjector(new MyModule());
    
            MapperDao mapper1 = i.getInstance(Key.get(MapperDao.class, Names.named("Mapper1")));
            MapperDao mapper2 = i.getInstance(Key.get(MapperDao.class, Names.named("Mapper2")));
        }
    }
    

    示例注入类:这展示了如何使用字段注入来注入映射器

    public class MyExampleClass {
    
       @Inject
       @Named("Mapper1")
       MapperDao mapper1;
    
       @Inject
       @Named("Mapper2")
       MapperDao mapper2;
    
    }
    
  2. # 3 楼答案

    这个答案的范围与问题的范围略有不同。对于任何拥有固定数量数据源并需要共享映射器的人,也有一种解决方案,它不使用公认答案中描述的@Named

    你可以简单地使用

    interface SomeMapperForDbA extends SomeMapper {}
    

    并在相应的PrivateModule中添加+exposeSomeMapperForDbA

    这里的接口名充当逻辑数据源鉴别器,而所有映射查询仍然保持在SomeMapper中的一个位置。与命名注入相比,这种方法有优点和缺点,但它是有效的,可能会为一些人节省时间

    显然,您需要注入SomeMapperForDbA来使用DbA数据源。这就是说,它只能在构造函数中完成,而实际代码中使用的类成员类型只能是SomeMapper,以避免混淆

    或者,如果数据库有公共部分和不同部分等,您可以向SomeMapperForDbA添加一些特定于DbA的选择。在本例中,我建议使用更好的名称,以反映这种逻辑

    也就是说,在需要时不要害怕扩展映射器接口