Spring boot, кажется, не может найти конфигурации mybatis mapper (коллекция Mapped Statements не содержит значения)

Я работаю с mybatis и spring-boot.

Я страдал в течение нескольких часов с последующим сообщением.

2018-02-18 15:25:13.774 ERROR 77556 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for org.owls.mybatis.mapper.TestMapper.selectTimestamp
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for org.owls.mybatis.mapper.TestMapper.selectTimestamp] with root cause

java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for org.owls.mybatis.mapper.TestMapper.selectTimestamp

Мой источник основан на этом(Spring boot, начать с проекта) и добавить настройки Mybatis.

Я думаю, что каким-то образом mybatis не смог найти информацию о сопоставителе, поэтому я хотел бы напечатать список зарегистрированных сопоставителей mybatis в консоли. (Является ли это возможным?)

К вашему сведению, следуйте тому, что я реализовал.

Я использую application.yml добавить mybatis

mybatis:
    type-aliases-package: org.owls.mybatis.model
    type-handlers-package: org.owls.mybatis.handler
    mapper-locations: classpath:/resources/mybatis/mapper/*_mapper.xml 
    configuration:
        map-underscore-to-camel-case: true
        default-fetch-size: 100
        default-statement-timeout: 30

А это /resources/mybatis/mapper/test_mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.owls.mybatis.mapper.TestMapper">
    <select id="selectTimestamp" resultType="map">
        SELECT NOW() FROM DUAL
    </select>
</mapper>

Отсюда Java-коды.

Во-первых, интерфейс Mapper TestMapper который в org.owls.mybatis.mapper пакет

public interface TestMapper {
    @Select("SELECT NOW() FROM DUAL")
    public Map selectTimestamp() throws Exception;
}

Во-вторых, я сделал сервис, который генерирует SqlSessionTemplate, Вот код

@Service
public class MybatisService implements ApplicationContextAware {

    private Logger logger = Logger.getLogger(MybatisService.class);
    private ApplicationContext context;

    @Autowired
    DBService dbService;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }


    // Register a Object with a name, if not exists
    private void registerBean(String beanName, Object newBean){
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry)  context.getAutowireCapableBeanFactory();
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(newBean.getClass());
        BeanDefinition def = builder.getBeanDefinition();
        if(!registry.containsBeanDefinition(beanName)) registry.registerBeanDefinition(beanName, def);
    }


    /*
    * Managing SqlSessionFactory
    * */
    private SqlSessionFactory generateSqlSessionFactory(String dsId, DataSource ds) throws Exception {
        String beanName = dsId + "SqlSessionFactory";

        SqlSessionFactory sqlSessionFactory = null;
        try {
            Object registeredBean = context.getBean(beanName);
            logger.info("Found SqlSessionFactory bean [ " + beanName + " ]. Returns the instance");
            sqlSessionFactory = (SqlSessionFactory) registeredBean;
        } catch (NoSuchBeanDefinitionException e) {
            logger.info("Not found SqlSessionFactory bean [ " + beanName + " ]. Generate new one");
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            sqlSessionFactoryBean.setDataSource(ds);
            sqlSessionFactory = (SqlSessionFactory) sqlSessionFactoryBean.getObject();
            registerBean(beanName, sqlSessionFactory);
        }
        return sqlSessionFactory;
    }


    /*
    * Managing SqlSessionTemplate
    * */
    private SqlSessionTemplate generateSqlSessionTemplate(String dsId, SqlSessionFactory sqlSessionFactory) throws Exception {
        String beanName = dsId + "SqlSessionTemplate";
        SqlSessionTemplate sqlSessionTemplate = null;
        try {
            Object registeredBean = context.getBean(beanName);
            logger.info("Found SqlSessionTemplate bean [ " + beanName + " ]. Returns the instance");
            sqlSessionTemplate = (SqlSessionTemplate) registeredBean;
        } catch (NoSuchBeanDefinitionException e) {
            logger.info("Not found SqlSessionTemplate bean [ " + beanName + " ]. Generate new one");
            sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
            registerBean(beanName, sqlSessionFactory);
        }
        return sqlSessionTemplate;
    }


    public SqlSessionTemplate getSqlSessionTemplate(String dsId) {
        SqlSessionTemplate template = null;
        try {
            DataSource ds = dbService.getDS(dsId);
            SqlSessionFactory sqlSessionFactory = generateSqlSessionFactory(dsId, ds);
            template = generateSqlSessionTemplate(dsId, sqlSessionFactory);
        } catch (Exception e) {
            logger.error("Failed to fetch SqlSessionFactory. returns null value ", e);
        }
        return template;
    }
}

Наконец, в контроллере, я называю это с...

@Controller
@RequestMapping(value = {"/test"})
public class TestController {

    @Autowired
    MybatisService mybatisService;
    private SqlSessionTemplate sqlSessionTemplate;

    private Logger logger = Logger.getLogger(TestController.class);

    @PostConstruct
    public void init(){
        sqlSessionTemplate = mybatisService.getSqlSessionTemplate("test");
    }

    @RequestMapping(value = {"getCurrentTimestamp"})
    public @ResponseBody String getCurrentTimestamp() throws Exception {

        logger.info("=== SqlSessionTemplate Info in Controller :: " + sqlSessionTemplate);

        Map<String, Object> data = (Map) sqlSessionTemplate.selectOne("org.owls.mybatis.mapper.TestMapper.selectTimestamp");
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writeValueAsString(data);
    }
};

Я думаю, что сообщение об ошибке немного расплывчато. (Я не мог найти подсказку, которая является неправильной среди настроек - mapper xml, application.yml, db connection)

Спасибо за ответы. Доступ к полному исходному коду

======================== Редактировать #1. 19 Фев =============================

Я узнал, что SqlSessionFactoryConfiguration не имеет никакого картографа вообще.

Я мог бы распечатать список картографов следующим образом. В коде где генерирует SqlSessionFactory...

// FOR TEST 0219
MapperRegistry registry = sqlSessionFactory.getConfiguration().getMapperRegistry();


logger.info("=== Printing Mapper Registry starts");
registry.getMappers().forEach(mapper -> {
    logger.info("Mapper Registry :: " +  mapper.getName());
});
logger.info("=== Printing Mapper Registry ends");
// FOR TEST 0219

В моем случае он ничего не печатает, но может добавить маппер или пакет через MapperRegistry пример.

Вот что я думал

  1. SqlSessionFactory(предоставлено ibatis) требует DataSource
  2. SqlSessionTemplate(предоставлено ibatis) является конечной точкой и требует SqlSessionFactory
  3. В заключение, SqlSessionTemplate зависит от SqlSessionFactory который зависит от DataSource,

Если так, то как я мог правильно генерировать SqlSession* как бин в проекте, который использует динамический источник данных?

В моем верхнем коде (отредактированном) я смог добавить маппер как бин, но каждый SqlSessionFactory имеет те же Mappers(дублируется, так как MapperRegistry получить имя пакета в качестве параметра)

Как я могу установить разные сопоставители для соответствующих SqlSessionFactory?

0 ответов

Другие вопросы по тегам