简体   繁体   English

用于测试的 Spring Boot H2 db 抛出“找不到表”和“SQL 语法错误”

[英]Spring Boot H2 db for testing throws "Table not found" and "SQL syntax error"

I develop simple Store app with Spring boot.我使用 Spring Boot 开发简单的 Store 应用程序。 My app uses MySQL database deployed in the docker container and it works fine.我的应用程序使用部署在 docker 容器中的 MySQL 数据库,并且运行良好。 Now I want to test my app and I came to the conclusion that H2 in-memory db would be enough for testing.现在我想测试我的应用程序,我得出的结论是H2 in-memory db足以进行测试。 As I'm fresh to testing spring apps, I encountered errors associated with creating tables in the H2 test database.由于我刚开始测试 Spring 应用程序,我遇到了与在 H2 测试数据库中创建表相关的错误。 Those are errors which I came across这些是我遇到的错误

First error :第一个错误

    alter table store_order_items 
       drop 
       foreign key FKikqpbj6xmmyoblsolyhk250tq" via JDBC Statement
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at org.hibernate.tool.schema.internal.SchemaDropperImpl.applySqlString(SchemaDropperImpl.java 
[...]
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "STORE_ORDER_ITEMS" not found (this database is empty); SQL statement:

Second error :第二个错误

org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL "
    create table store_order_items (
       Id bigint not null auto_increment,
        quantity bigint,
        order_Id bigint,
        product_Id bigint,
        primary key (Id)
    ) engine=InnoDB" via JDBC Statement
    at org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
    at org.hibernate.tool.schema.internal.SchemaCreatorImpl.applySqlString(SchemaCreatorImpl.java:458) ~[hibernate-core-5.6.9.Final.jar:5.6.9.Final]
[...]
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "\000a    create table store_order_items (\000a       Id bigint not null auto_increment,\000a        quantity bigint,\000a        order_Id bigint,\000a        product_Id bigint,\000a        primary key (Id)\000a    ) engine[*]=InnoDB"; expected "identifier"; SQL statement:

src/test/resources/ application.properties : src/test/resources/ application.properties

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;

spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect
spring.h2.console.enabled=true


logging.level.org.hibernate.SQL=DEBUG
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

spring.jpa.hibernate.ddl-auto=create
spring.jpa.generate-ddl=true
spring.jpa.defer-datasource-initialization=true

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

Test class :测试类

@ExtendWith(SpringExtension.class)
@SpringBootTest
@Transactional
public class UserRepositoryTests {

    private static final Logger LOGGER = Logger.getLogger(UserRepositoryTests.class.getName());

    @Autowired
    private UserRepositoryImpl userRepository;

    @Autowired
    private PasswordEncoder encoder;


    @Test
    void contextLoads() {
        System.out.println(encoder.encode("123"));
// dummy test just to test if tables are built properly
    }

model/OrderItem.java:模型/OrderItem.java:

@Entity
@Table(name = "store_order_items")
@NamedQueries({
        @NamedQuery(name=OrderItem.ORDER_ITEM_FIND_ALL, query=OrderItem.ORDER_ITEM_FIND_ALL_JPQL)
})
public class OrderItem {

    // get list of all orders
    public static final String ORDER_ITEM_FIND_ALL = "orderItemAll";
    public static final String ORDER_ITEM_FIND_ALL_JPQL = "SELECT oi FROM OrderItem oi";


    // id will be replaced with two foreign keys
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long Id;

    private Long quantity;

    @JsonBackReference
    @ManyToOne
    private Order order;

    @JsonBackReference
    @ManyToOne
    private Product product;

// getters and setters omitted
}

model/Order.java:模型/Order.java:

@Entity
@Table(name = "store_orders")
@NamedQueries({
        @NamedQuery(name=Order.ORDER_FIND_ALL, query=Order.ORDER_FIND_ALL_JPQL),
        @NamedQuery(name=Order.ORDER_SUMMARIES, query=Order.ORDER_SUMMARIES_JPQL)
})
public class Order {

// named queries omitted

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long Id;

    private String orderDate;

    @JsonBackReference
    @ManyToOne
    private User user;

    @JsonManagedReference
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<OrderItem> orderItems = new ArrayList<>();

// getters and setters omitted
}

I tried changing column names or using different spring.datasource.url 's but id didn't work.我尝试更改列名或使用不同的spring.datasource.url但 id 不起作用。 I can upload more source code if needed.如果需要,我可以上传更多源代码。

Based on our conversation on the comments, using the parameter MODE worked for OP.根据我们对评论的对话,使用参数 MODE 对 OP 有效。 So the solution was to change this configuration from:所以解决方案是从以下位置更改此配置:

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;

To

spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL

Note the MODE=MySQL added to the end.注意MODE=MySQL添加到末尾。 This will make H2 database implementation to ignore or replace certain MySQL reserved words with its (H2) equivalent ones.这将使 H2 数据库实现忽略某些 MySQL 保留字或将其替换为 (H2) 等效保留字。

Op also had to change another configuration for it to solve all problems and the other one as setting the ddl-auto setting from: Op 还必须更改另一种配置以解决所有问题,另一种是设置ddl-auto设置:

spring.jpa.hibernate.ddl-auto=create

To

spring.jpa.hibernate.ddl-auto=update

Please also note comment from Evgenij Ryazanov so check the version you are in and correct it accordingly:另请注意Evgenij Ryazanov的评论,因此请检查您所在的版本并进行相应的更正:

DATABASE_TO_UPPER=FALSE should only be used with H2 1.4.197 and older versions, for H2 1.4.198 Beta and newer versions DATABASE_TO_LOWER=TRUE should be specified with MySQL compatibility mode, otherwise all unquoted identifiers will be case-sensitive. DATABASE_TO_UPPER=FALSE只能用于 H2 1.4.197 和旧版本,对于 H2 1.4.198 Beta 和更新版本DATABASE_TO_LOWER=TRUE应该使用 MySQL 兼容模式指定,否则所有未加引号的标识符将区分大小写。 By经过

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM