Как я могу отлаживать репозиторий Spring Boot с H2 в базе данных памяти?

Я работаю над Spring Boot и пытаюсь использовать базу данных H2 (в памяти) для своих модульных тестов. Моя реализация репозитория Spring Data не работает, и мне нужна помощь в ее отладке.

Я сократил свой проект (не используя исходный проект) до следующего примера, чтобы изолировать и продемонстрировать проблему. Проект можно найти на GitHub.

Структура проекта Eclipse:

структура проекта

пом.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0.1</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>
    <dependency>
        <groupId>javax.transaction</groupId>
        <artifactId>jta</artifactId>
        <version>1.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-model</artifactId>
        <version>3.5.4</version>
    </dependency>
    <dependency>
        <groupId>org.modelmapper</groupId>
        <artifactId>modelmapper</artifactId>
        <version>2.2.0</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <executable>true</executable>
                <skipTests>true</skipTests>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

<repositories>
    <repository>
        <id>spring-releases</id>
        <url>https://repo.spring.io/libs-release</url>
    </repository>
</repositories>
<pluginRepositories>
    <pluginRepository>
        <id>spring-releases</id>
        <url>https://repo.spring.io/libs-release</url>
    </pluginRepository>
</pluginRepositories>

application.properties:

debug=true

logging.level.root=WARN
logging.level.org.foo=WARN
logging.level.org.springframework=WARN

spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test_database;DB_CLOSE_DELAY=-1
spring.datasource.username=sa
spring.datasource.password=sa

spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

Основной класс конфигурации:

@SpringBootApplication
@Configuration
@PropertySource("classpath:application.properties")
@EnableJpaRepositories(basePackages = "org.foo.repositories")
@EntityScan("org.foo.entities")
@EnableTransactionManagement
public class Application {

    Logger logger = LoggerFactory.getLogger(Application.class);

    public static void main(String[] args) {
        Logger logger = LoggerFactory.getLogger(Application.class);
        SpringApplication.run(Application.class, args);
        logger.info("Application started");
    }

    @Bean
    public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
        return args -> {

            logger.trace("Let's inspect the beans provided by Spring Boot:");
            String[] beanNames = ctx.getBeanDefinitionNames();
            Arrays.sort(beanNames);
            for (String beanName : beanNames) {
                logger.trace(beanName);
            }
        };
    }
}

Класс студенческих сущностей:

package org.foo.entities;

import javax.persistence.Entity;
import javax.persistence.Id;
import lombok.Data;

@Entity
@Data
public class Student {

    @Id
    private long id;

    private String first_name;

    private String last_name;

}

Класс StudentRepository:

@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
    @Override
    List<Student> findAll();
}

Класс StudentRepositoryTester:

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
@ContextConfiguration(classes = { org.foo.Application.class }, loader = AnnotationConfigContextLoader.class)
public class StudentRepositoryTester {

    Logger logger = LoggerFactory.getLogger(StudentRepositoryTester.class);

    @Autowired
    private StudentRepository studentRepository;

    @Test
    public void findAllTester() {
        Iterable<Student> students = studentRepository.findAll();
        for(Student student: students) {
            logger.info(student.toString());
        }
        long size = StreamSupport.stream(students.spliterator(), false).count();
        assertTrue(students != null && size == 3);
    }

}

данные.sql:

USE `test_database`;

INSERT INTO `students` (`id`,`first_name`,`last_name`) VALUES (1,'First1','Last1');
INSERT INTO `students` (`id`,`first_name`,`last_name`) VALUES (2,'First2','Last2');
INSERT INTO `students` (`id`,`first_name`,`last_name`) VALUES (3,'First3','Last3');

схема.sql:

DROP ALL OBJECTS; 

CREATE SCHEMA `test_database`;
USE `test_database`;

CREATE TABLE `students` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `first_name` varchar(45) NOT NULL,
  `last_name` varchar(45) NOT NULL,
  PRIMARY KEY (`id`)
);

Я вижу в журнале консоли, что H2 заполнен, поскольку я вижу, что выполняются операторы в data.sql. Больше ничего подозрительного в логе не вижу.

Конкретные вопросы:

  1. Запустив тестовый класс StudentRepositoryTester, я вижу (с точкой останова в утверждении), что объекты не возвращаются. Я не могу понять, почему. Возможно, я что-то упустил в аннотациях конфигурации Spring Boot?

  2. Я попытался проверить содержимое базы данных в точке останова, но не могу найти способ изучить базу данных H2. Я следую этому руководству, чтобы открыть приложение веб-обозревателя H2, но в localhost:8080 ничего не обслуживается. Я делаю что-то неправильно? В качестве альтернативы есть ли другой способ отладки того, что происходит в базе данных H2 (в памяти)?

Обратите внимание, что соответствующий проект Eclipse был загружен на GitHub для облегчения обсуждения.


person Pantelis Natsiavas    schedule 27.09.2018    source источник
comment
Вы очень стараетесь НЕ использовать Spring Boot. Начните с очистки вашего Application. Удалите все аннотации и оставьте только @SpringBootAplication все остальное применяется Spring Boot. Удалите findAll из StudentRepository Spring Data JPA уже содержит этот метод. Затем очистите свой тест, удалите все аннотации и оставьте только @SpringBootTest и @RunWith, затем повторите попытку.   -  person M. Deinum    schedule 27.09.2018
comment
@M.Deinum: Большое спасибо за ваши замечания. Я новичок в Spring (очевидно), и я следовал руководствам, в которых предлагалось использовать эти аннотации. Я следовал вашим инструкциям и все равно получаю тот же результат. Объекты не возвращены.   -  person Pantelis Natsiavas    schedule 27.09.2018
comment
Вы действительно сделали все, что я сказал... Особенно сократили аннотации на тестовом классе?!   -  person M. Deinum    schedule 27.09.2018
comment
@ М.Дейнум: Да. Я удалил Transactional и ContextConfiguration. Я оставил остальные. Также обратите внимание, что теперь в моем журнале я не вижу выполняемых операторов INSERT. Я могу видеть ученика с отброшенной таблицей, только если он существует, создайте ученика из таблицы (id bigint не null, first_name varchar (255), last_name varchar (255), первичный ключ (id))   -  person Pantelis Natsiavas    schedule 27.09.2018
comment
Вы также должны настроить JPA так, чтобы он НЕ управлял вашей схемой. Это включено по умолчанию. spring.jpa.generate-ddl=false иначе по умолчанию будет true для баз данных в памяти.   -  person M. Deinum    schedule 27.09.2018
comment
@ М.Дейнум: Без разницы. Не то, чтобы я мог идентифицировать, по крайней мере. Журнал выглядит так же... Обратите внимание, что я снова не вижу выполнения операторов INSERT. Я вижу только операторы DROP...   -  person Pantelis Natsiavas    schedule 27.09.2018
comment
Как уже говорилось, убедитесь, что спящий режим не управляет вашей схемой!... Утверждения, которые вы видите, взяты из спящего режима, а не из вашего schema.sql.   -  person M. Deinum    schedule 27.09.2018
comment
Давайте продолжим обсуждение в чате.   -  person Pantelis Natsiavas    schedule 27.09.2018


Ответы (2)


Включите ведение журнала операторов SQL, выполняемых Hibernate (в application.properties):

logging.level.org.hibernate.SQL=DEBUG

Это выведет все операторы SQL на консоль. Но без ввода переменных. Это должно помочь вам в устранении неполадок.

person luboskrnac    schedule 27.09.2018

Сценарии начальной загрузки H2 обрабатываются ScriptUtils

Поэтому увеличьте уровень ведения журнала в application.properties:

logging.level.org.springframework.jdbc.datasource.init.ScriptUtils=DEBUG
person lainatnavi    schedule 12.04.2020