我知道在互联网上有很多解决同一问题的例子。但是我试图获得帮助的是架构方面的问题。
我有一个简单的spring项目,其中有一个配置类,我正在尝试配置两个数据源 (distDataSource,shipmentDataSource)。我为下面提到的两个数据源( MyBatisDISTDataSource,MyBatisShipmentDataSource )有两个单独的类。
这两个数据仓库分别工作正常,但是当我尝试一起执行它时,控制台上会出现异常。
控制台异常日志
线程“主”中的异常 org.springframework.beans.factory.UnsatisfiedDependencyException: 创建名称为“ distDAOImpl”的bean时出错:不满意的依赖关系 通过字段“ distMapper”表示;嵌套异常为 org.springframework.beans.factory.UnsatisfiedDependencyException: 在文件中定义名称为“ distMapper”的bean时出错 [D:\ eclipse \ ShippingModule \ shipment-module-v2 \ CustEquip-CourierShipmentService-PickupSvc \ target \ classes \ com \ shipment \ mapper \ DistMapper.class]:通过bean属性表示的不满意依赖性 'sqlSessionFactory';嵌套异常为 org.springframework.beans.factory.NoUniqueBeanDefinitionException:否 类型为“ org.apache.ibatis.session.SqlSessionFactory”的合格Bean 可用:预期的单个匹配bean,但发现2: distSqlSessionFactory,shipmentSqlSessionFactory位于 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor $ AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) 在 org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) 在 org.springframework.beans.factory.support.AbstractBeanFactory $ 1.getObject(AbstractBeanFactory.java:306) 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) 在 org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) 在 org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) 在 org.springframework.context.annotation.AnnotationConfigApplicationContext。(AnnotationConfigApplicationContext.java:84) 在 com.telus.shipment.app.starter.SchedulePickup.main(SchedulePickup.java:11) 造成原因: org.springframework.beans.factory.UnsatisfiedDependencyException: 在文件中定义名称为“ distMapper”的bean时出错 [D:\ eclipse \ ShippingModule \ shipment-module-v2 \ CustEquip-CourierShipmentService-PickupSvc \ target \ classes \ com \ shipment \ mapper \ DistMapper.class]:通过bean属性表示的不满意依赖性 'sqlSessionFactory';嵌套异常为 org.springframework.beans.factory.NoUniqueBeanDefinitionException:否 类型为“ org.apache.ibatis.session.SqlSessionFactory”的合格Bean 可用:预期的单个匹配bean,但发现2: distSqlSessionFactory,shipmentSqlSessionFactory位于 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1357) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1249) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) 在 org.springframework.beans.factory.support.AbstractBeanFactory $ 1.getObject(AbstractBeanFactory.java:306) 在 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) 在 org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) 在 org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) 在 org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) 在 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor $ AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 14更多原因: org.springframework.beans.factory.NoUniqueBeanDefinitionException:否 类型为“ org.apache.ibatis.session.SqlSessionFactory”的合格Bean 可用:预期的单个匹配bean,但发现2: distSqlSessionFactory,shipmentSqlSessionFactory位于 org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:173) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) 在 org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) 在 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1342) ...另外25个
配置类
@Component
@Configuration
@Profile("local")
public class EnvironmentConfigLocal implements EnvironmentConfig {
@Autowired @Qualifier("DISTDataSource") private MyBatisDISTDataSource distDataSource;
@Autowired @Qualifier("ShipmentDataSource") private MyBatisShipmentDataSource shipmentDataSource;
@PostConstruct
public void postConstruct() {
System.out.println("Selected Profile : Local");
}
@Bean
public static PropertySourcesPlaceholderConfigurer dataProperties(final Environment environment) {
final PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
final YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
final SpringProfileDocumentMatcher matcher = new SpringProfileDocumentMatcher();
matcher.addActiveProfiles(environment.getActiveProfiles());
yaml.setDocumentMatchers(matcher);
yaml.setResources(new ClassPathResource("application.yaml"));
propertySourcesPlaceholderConfigurer.setProperties(yaml.getObject());
return propertySourcesPlaceholderConfigurer;
}
@Bean
public DataSourceTransactionManager distTransactionManager() throws SQLException {
return new DataSourceTransactionManager(distDataSource);
}
@Bean
public DataSourceTransactionManager shipmentTransactionManager() throws SQLException {
return new DataSourceTransactionManager(shipmentDataSource);
}
@Bean
@Override
public SqlSessionFactory distSqlSessionFactory() throws Exception {
SqlSessionFactoryBean distSessionFactory = new SqlSessionFactoryBean();
distSessionFactory.setDataSource(distDataSource);
return distSessionFactory.getObject();
}
@Bean
@Override
public SqlSessionFactory shipmentSqlSessionFactory() throws Exception {
SqlSessionFactoryBean shipmentSessionFactory = new SqlSessionFactoryBean();
shipmentSessionFactory.setDataSource(shipmentDataSource);
return shipmentSessionFactory.getObject();
}
}
MyBatisDISTDataSource
@Component
@Qualifier("DISTDataSource")
public class MyBatisDISTDataSource extends PooledDataSource {
@Value("${dist.db.poolMaximumActiveConnections}") int poolMaximumActiveConnections;
@Value("${dist.db.poolMaximumIdleConnections}") int poolMaximumIdleConnections;
public MyBatisDISTDataSource(
@Value("${dist.db.driver-class}") String driver,
@Value("${dist.db.url}") String url,
@Value("${dist.db.user}") String username,
@Value("${dist.db.password}") String password) {
super(driver, url, username, password);
System.out.println("DIST DB Attr: \n\t"
+driver+"\n\t"
+url+"\n\t"
+username+"\n\t"
+password+"\n\t");
}
@PostConstruct
private void setDataSourceProperties() {
this.setPoolMaximumActiveConnections(poolMaximumActiveConnections);
this.setPoolMaximumIdleConnections(poolMaximumIdleConnections);
}
}
MyBatisShipmentDataSource
@Component
@Qualifier("ShipmentDataSource")
public class MyBatisShipmentDataSource extends PooledDataSource {
@Value("${shipment.db.poolMaximumActiveConnections}") int poolMaximumActiveConnections;
@Value("${shipment.db.poolMaximumIdleConnections}") int poolMaximumIdleConnections;
public MyBatisShipmentDataSource(
@Value("${shipment.db.driver-class}") String driver,
@Value("${shipment.db.url}") String url,
@Value("${shipment.db.user}") String username,
@Value("${shipment.db.password}") String password) {
super(driver, url, username, password);
System.out.println("Shipment DB Attr: \n\t"
+driver+"\n\t"
+url+"\n\t"
+username+"\n\t"
+password+"\n\t");
}
@PostConstruct
private void setDataSourceProperties() {
this.setPoolMaximumActiveConnections(poolMaximumActiveConnections);
this.setPoolMaximumIdleConnections(poolMaximumIdleConnections);
}
}
DistMapper
@Mapper
@Component
public interface DistMapper {
@Select({"select * "
+ "from CONTACT_ADDRESS CA, ADDRESS A"
+ "where CONTACTING_ID = '10001134' "
+ "and PROVINCE_CD ='ON' "
+ "and STREET_NUMBER = '15'"})
@Results({@Result(column = "CONTACTING_ID", property = "contactingId", jdbcType = JdbcType.DECIMAL)})
public List<OutletAddress> findAddressByOutletId();
}
ShipmentMapper
@Mapper
@Component
public interface ShipmentMapper {
@Select({"select C.CONTACT_ID "
+ "from SHIPMENT_EVENT_TRACKING SE, SHIPMENT S, CONTACT_ADDR CA, CONTACT C "
+ "where SE.EVENT_CD = 'PICKUP' "
+ "and SE.SHIPMENT_ID = s.shipment_id "
+ "and S.SENDER_ADDR_ID = CA.CONTACT_ADDR_ID "
+ "and CA.CONTACT_ID = c.contact_id "
+ "and C.GROUP_CD = 'OT' "
+ "and SE.EVENT_OCCURRED_IND = 'N' "
+ "and S.CREATION_TS >= (select CURRENT_TIMESTAMP - interval '30' day from dual)"
+ "and S.SCHEDULE_PICKUP_IND = 'Y'"})
@Results({
@Result(column = "CONTACT_ID", property = "contactId", jdbcType = JdbcType.DECIMAL)})
public CopyOnWriteArrayList<EligibleShipment> findShipmentsByOutlet();
}
答案 0 :(得分:0)
使用spring-mybatis
,您可以register一对一地映射,也可以使用scanning映射器。
如果要手动注册映射器,请确保将正确的SqlSessionFactory
传递给每个映射器。如果您今年春天不这样做,将尝试自动装配SqlSessionFactory
,由于其中有两个,您将得到一个错误,即找不到单个bean。
如果使用扫描映射器,请为其指定参数,以便适当的映射器使用正确的SqlSessionFactory
。
一种方法是将应该使用不同DataSource
的映射器放置到不同的包中。在这种情况下,您需要像这样创建两个MapperScannerConfigurer
bean(假设映射器位于com.mycompany.myapp.distMappersPackage
和com.mycompany.myapp.shipmentMappersPackage
中)
@Bean
public MapperScannerConfigurer distMapperScannerConfigurer() throws Exception {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.mycompany.myapp.distMappersPackage");
configurer.setSqlSessionFactoryBeanName("distSqlSessionFactory");
return configurer;
}
@Bean
public MapperScannerConfigurer shipmentMapperScannerConfigurer() throws Exception {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setBasePackage("com.mycompany.myapp.shipmentMappersPackage");
configurer.setSqlSessionFactoryBeanName("shipmentSqlSessionFactory");
return configurer;
}
或者,您可以创建两个不同的注释,并在映射器上使用它们,如下所示:
@DistMapperMarker
public interface DistMapper {
...
}
@ShipmentMapperMarker
public interface ShipmentMapper {
...
}
在这种情况下,映射器可以放在一个包中,但是您可以在annotationClass
上指定MapperScannerConfigurer
:
@Bean
public MapperScannerConfigurer distMapperScannerConfigurer() throws Exception {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setAnnotationClass(DistMapperMarker.class);
configurer.setSqlSessionFactoryBeanName("distSqlSessionFactory");
return configurer;
}
@Bean
public MapperScannerConfigurer shipmentMapperScannerConfigurer() throws Exception {
MapperScannerConfigurer configurer = new MapperScannerConfigurer();
configurer.setAnnotationClass(ShipmentMapperMarker.class);
configurer.setSqlSessionFactoryBeanName("shipmentSqlSessionFactory");
return configurer;
}
对于java base spring配置,您还可以尝试使用MapperScan
并将参数指定为其属性。这将需要您将弹簧配置至少分为两类。我没有使用这种方法,所以不确定是否可以正常工作。
答案 1 :(得分:0)
@Primary
在SqlSessionFactory bean之一上解决了我的问题。
@Bean
@Primary
@Override
public SqlSessionFactory sqlSessionFactory2() throws Exception {
SqlSessionFactoryBean sessionFactory2 = new SqlSessionFactoryBean();
sessionFactory2.setDataSource(dataSource2);
return sessionFactory2.getObject();
}