MyBatis - 连接到同一服务调用中的多个数据库

时间:2016-11-10 06:06:58

标签: java guice mybatis

我需要连接到多个数据库,以便在将数据返回给用户之前查询和合并数据。有没有办法使用MyBatis和cdi?我查看了使用DatabaseIdProvider并拥有multiple environment configurations,但看起来它们不适合这种情况。使用多个环境配置,我可以创建不同的sql会话工厂,但是在这种情况下,映射器的cdi将如何工作?我想尽可能多地使用cdi。 MyBatis Guice会对此有所帮助吗?我查看了一个similar问题但我无法确定Guice是否会在这种情况下提供帮助,我需要在同一服务调用中查询多个数据库。

2 个答案:

答案 0 :(得分:1)

您需要定义2个SqlSessionFactories。单独的环境可能适合您的需求,但也可以使用完全独立的配置和对象/类层次结构。无论如何,您可以根据需要在映射器或映射扫描器的配置中传递每个。

有关配置映射器的各种方法,请参阅documentation。请注意,如果需要,所有这些都允许您指定SqlSessionFactory。如果每个配置使用相同的映射器,您可能无法使用扫描器方法,因为我认为这将使用来自不同SqlSessionFactories的映射器的相同名称。在这种情况下,您将不得不为不同的配置使用不同的名称手动配置映射器。

然后在您的服务中,您可以执行以下操作:

public class FooServiceImpl implements FooService {
  @Autowired
  @Qualifier("fooMapperDB1")
  private FooMapper fooMapper1;

  @Autowired
  @Qualifier("fooMapperDB2")
  private FooMapper fooMapper2;

  public List<Foo> doService(String id) {
    List<Foo> toReturn = new ArrayList<>();
    toReturn.add(fooMapper1.getFoo());
    toReturn.add(fooMapper2.getFoo());
    return toReturn;
  }
}

请注意,此处需要注意事务。您可能希望该服务是事务性的,然后将分布式XA数据源用于两个数据库连接。

答案 1 :(得分:0)

环境配置定义数据源和事务管理器。 然后连接到多个数据库至少需要 SqlSessionFactory

Reader reader = Resources.getResourceAsReader(classpathConfigFilename);
new SqlSessionFactoryBuilder().build(reader, environment, properties);

为每个环境调用一个

如果目的是整合数据,我猜两个数据模型略有不同(那么查询,映射器,typeHandler等等),那么最好从不同的mybatis-config文件创建SqlSessionFactory并使用它们的默认环境:

new SqlSessionFactoryBuilder().build(reader, properties);

如何解决这个问题呢? 如果您编辑问题以提供有关上下文,示例以及您尝试过的内容的更多信息,则可能会给出更准确的答案。

Guice:当然可以使用,但不是此成就所必需的。

编辑:

使用Mybatis-CDI

以下是如何生成SqlSession工厂(它们必须是 @Named ):

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;
import javax.inject.Named;

public class SqlSessionFactoryWrapper {

    private static final String  BI_CONFIG  = "mybatis-config.xml";

    private SqlSessionFactory getFactory(final String config, final String env) throws IOException {
        final Reader reader = Resources.getResourceAsReader(config);
        final Properties properties = new Properties();
        properties.load(Resources.getResourceAsReader("some.properties"));

        return new SqlSessionFactoryBuilder().build(reader, env, properties);
    }

    @Produces
    @ApplicationScoped
    @Named("A")
    public SqlSessionFactory getFactoryA() throws IOException {
        return this.getBiFactory(CONFIG, "A");
    }

    @Produces
    @ApplicationScoped
    @Named("B")
    public SqlSessionFactory getFactoryB() throws IOException {
        return this.getFactory(CONFIG, "B");
    }
}

如何注射:

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named;


    @Inject
    @Named("A")
    protected SqlSession          sessionA;

    @Inject
    @Named("B")
    protected SqlSession          sessionB;

直接注入 mapper 以获取环境 B SqlSession

import org.mybatis.cdi.Mapper;

    @Inject
    @Named("B")
    @Mapper
    protected MyMapper mapper;

这在我在jBoss中运行的应用程序中有效,但这里没有特定于jBoss的内容。

阅读documentation for transaction management,这很清楚。 我建议使用

@Transactional(executorType = ExecutorType.REUSE)

特别是批量操作只准备一次语句。

EDIT2:

片段中的

mybatis.cdi注释对我当时使用的版本1.0.0.beta3有效。在进一步的测试版中,它们略有进化,然后很少需要适应最终版本(仅仅一个月)。