有 Java 编程相关的问题?

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

java组织。springframework。豆。工厂NonuniqueBeandDefinitionException:没有类型为“org”的限定bean。阿帕奇。伊巴蒂斯。一场SqlSessionFactory'

我知道在互联网上有很多关于同一问题的例子。但我想得到的是架构层面的帮助

我有一个简单的spring项目,其中我有一个配置类。我正在尝试配置两个数据源 (distDataSource,shipmentDataSource)。对于下面提到的两个数据源(MyBatisDISTDataSource,MyBatisShipmentDataSource),我有两个单独的类

这两个DataSorce分别工作得很好,但当我试图同时执行它时,控制台上出现异常

控制台异常日志

Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'distDAOImpl': Unsatisfied dependency expressed through field 'distMapper'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'distMapper' defined in file [D:\eclipse\ShippingModule\shipment-module-v2\CustEquip-CourierShipmentService-PickupSvc\target\classes\com\shipment\mapper\DistMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.apache.ibatis.session.SqlSessionFactory' available: expected single matching bean but found 2: distSqlSessionFactory,shipmentSqlSessionFactory at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84) at com.telus.shipment.app.starter.SchedulePickup.main(SchedulePickup.java:11) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'distMapper' defined in file [D:\eclipse\ShippingModule\shipment-module-v2\CustEquip-CourierShipmentService-PickupSvc\target\classes\com\shipment\mapper\DistMapper.class]: Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.apache.ibatis.session.SqlSessionFactory' available: expected single matching bean but found 2: distSqlSessionFactory,shipmentSqlSessionFactory at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1357) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1249) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:208) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1138) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585) ... 14 more Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.apache.ibatis.session.SqlSessionFactory' available: expected single matching bean but found 2: distSqlSessionFactory,shipmentSqlSessionFactory at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:173) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1116) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1342) ... 25 more

配置类

@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();
}

共 (2) 个答案

  1. # 1 楼答案

    使用spring-mybatis可以逐个使用register映射器,也可以使用scanning映射器

    如果手动注册映射程序,请确保将正确的SqlSessionFactory传递给每个映射程序。如果您今年不这样做,spring将尝试自动连线SqlSessionFactory,因为您有两个,您将得到一个没有找到单个bean的错误

    如果使用扫描映射器,请为其指定参数,以便适当的映射器使用正确的SqlSessionFactory。 一种方法是将应该使用不同DataSource的映射器放置到不同的包中。在这种情况下,您需要像这样创建两个MapperScannerConfigurerbean(假设映射器位于com.mycompany.myapp.distMappersPackagecom.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 {
       ...
    }
    

    在这种情况下,映射程序可以在一个包中,但您可以在MapperScannerConfigurer上指定annotationClass

    @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,并将参数指定为它的属性。这将要求您将spring配置分为至少两个类。我没有使用过这种方法,所以我不确定它是否有效

  2. # 2 楼答案

    在其中一个SqlSessionFactory bean上@Primary解决了我的问题

        @Bean
        @Primary
        @Override
        public SqlSessionFactory sqlSessionFactory2() throws Exception {
            SqlSessionFactoryBean sessionFactory2 = new SqlSessionFactoryBean();
            sessionFactory2.setDataSource(dataSource2);
            return sessionFactory2.getObject();
        }