MyBatis - 在同一个服务调用中连接到多个数据库
MyBatis - Connect to multiple databases in the same service call
我有一个需求,在将数据返回给用户之前连接到多个数据库以查询和整合数据。有没有办法使用 MyBatis 和 cdi 来做到这一点?我调查了使用 DatabaseIdProvider and having multiple environment configurations but looks like they will not work for this scenario. With multiple environment configurations I can create different sql session factories, but how will cdi for mappers work in that case? I would like to use cdi as much as possible. Will MyBatis Guice help with this? I have looked at a 的问题,但我无法确定 Guice 是否会在这种情况下提供帮助,因为我需要在同一个服务调用中查询多个数据库。
环境配置定义数据源和事务管理器。
然后连接到多个数据库至少需要 SqlSessionFactory:
Reader reader = Resources.getResourceAsReader(classpathConfigFilename);
new SqlSessionFactoryBuilder().build(reader, environment, properties);
每个环境调用一个
如果目的是整合数据,我猜这两种数据模型略有不同(然后查询、映射器、typeHandler ...),那么 SqlSessionFactory 最好从不同的 mybatis-config 文件创建并使用它们默认环境:
new SqlSessionFactoryBuilder().build(reader, properties);
怎么这么不解决问题?
如果您编辑问题以提供有关上下文、示例和您尝试过的内容的更多信息,可能会得到更准确的答案。
指南:当然可以使用,但不是这个成就所必需的。
编辑:
下面是生成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;
或者inject直接mapper for from SqlSession of environment B :
import org.mybatis.cdi.Mapper;
@Inject
@Named("B")
@Mapper
protected MyMapper mapper;
这在 jBoss 中的我的应用程序 运行 中有效,但此处没有任何 jBoss 特定内容。
看了documentation for transaction management,这个就很清楚了。
我推荐使用
@Transactional(executorType = ExecutorType.REUSE)
专为批量操作准备语句一次。
编辑 2:
mybatis.cdi 片段中的注释对我当时使用的版本 1.0.0.beta3 有效。在进一步的测试版中,它们略有改进,然后几乎不需要调整就可以使用最终版本(仅一个月)。
您需要定义 2 个 SqlSessionFactories。单独的环境可能适合您的需要,但也可以使用完全独立的配置和对象/class 层次结构。无论如何,您可以根据需要在映射器或映射器扫描器的配置中传递每一个。
有关配置映射器的各种方法,请参阅 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 数据源用于两个数据库连接。
我有一个需求,在将数据返回给用户之前连接到多个数据库以查询和整合数据。有没有办法使用 MyBatis 和 cdi 来做到这一点?我调查了使用 DatabaseIdProvider and having multiple environment configurations but looks like they will not work for this scenario. With multiple environment configurations I can create different sql session factories, but how will cdi for mappers work in that case? I would like to use cdi as much as possible. Will MyBatis Guice help with this? I have looked at a
环境配置定义数据源和事务管理器。 然后连接到多个数据库至少需要 SqlSessionFactory:
Reader reader = Resources.getResourceAsReader(classpathConfigFilename);
new SqlSessionFactoryBuilder().build(reader, environment, properties);
每个环境调用一个
如果目的是整合数据,我猜这两种数据模型略有不同(然后查询、映射器、typeHandler ...),那么 SqlSessionFactory 最好从不同的 mybatis-config 文件创建并使用它们默认环境:
new SqlSessionFactoryBuilder().build(reader, properties);
怎么这么不解决问题? 如果您编辑问题以提供有关上下文、示例和您尝试过的内容的更多信息,可能会得到更准确的答案。
指南:当然可以使用,但不是这个成就所必需的。
编辑:
下面是生成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;
或者inject直接mapper for from SqlSession of environment B :
import org.mybatis.cdi.Mapper;
@Inject
@Named("B")
@Mapper
protected MyMapper mapper;
这在 jBoss 中的我的应用程序 运行 中有效,但此处没有任何 jBoss 特定内容。
看了documentation for transaction management,这个就很清楚了。 我推荐使用
@Transactional(executorType = ExecutorType.REUSE)
专为批量操作准备语句一次。
编辑 2:
mybatis.cdi 片段中的注释对我当时使用的版本 1.0.0.beta3 有效。在进一步的测试版中,它们略有改进,然后几乎不需要调整就可以使用最终版本(仅一个月)。
您需要定义 2 个 SqlSessionFactories。单独的环境可能适合您的需要,但也可以使用完全独立的配置和对象/class 层次结构。无论如何,您可以根据需要在映射器或映射器扫描器的配置中传递每一个。
有关配置映射器的各种方法,请参阅 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 数据源用于两个数据库连接。