java - 防止@Entity重新创建数据库表 - Spring Boot

标签 java spring-boot spring-data-jpa spring-boot-jpa

我对 spring boot data jpa 有点陌生,据我所知@Entity 用于表示应用程序中的数据库表,对于这个项目我使用 spring-boot 2.2.5.RELEASEH2 在内存数据库中。

到目前为止我已经知道了。

resources/data.sql 内部

CREATE TABLE CURRENCY (
  id INT AUTO_INCREMENT  PRIMARY KEY,
  name VARCHAR(250) NOT NULL,
  code VARCHAR(250) NOT NULL
);

CREATE TABLE EXCHANGE_CURRENCY (
  id INT AUTO_INCREMENT  PRIMARY KEY,
  IdFx1 INT NOT NULL,
  IdFx2 INT NOT NULL,
  equivalent DECIMAL NOT NULL,
  FOREIGN KEY (IdFx1) REFERENCES CURRENCY(id),
  FOREIGN KEY (IdFx2) REFERENCES CURRENCY(id)
);

我的实体类

import javax.persistence.*;

@Entity
@Table(name = "CURRENCY")
public class Currency {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String code;
}

存储库

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface CurrencyRepository extends CrudRepository<Currency, Long> {

    @Query("SELECT c FROM CURRENCY WHERE c.code LIKE %:code%")
    List<Currency> findCurrencyByCode(@Param("code") String code);

}

和服务

import com.currency.canonical.models.Currency;
import com.currency.canonical.request.ExchangeValueRequest;
import com.currency.canonical.response.ExchangeValueResponse;
import com.currency.dao.CurrencyService;
import com.currency.dao.repository.CurrencyRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class CurrencyConversionServiceImpl implements CurrencyConversionService {

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

    @Autowired
    private CurrencyRepository currencyRepository;

    @Override
    public ExchangeValueResponse performCurrencyConversion(ExchangeValueRequest request) {
        final long initialTime = System.currentTimeMillis();

        ExchangeValueResponse objExchangeValueResponse = new ExchangeValueResponse();

        try {
            List<Currency> currencyList = currencyRepository.findCurrencyByCode(request.getMonedaOrigen());
            currencyList.forEach(System.out::println);

        } catch (Exception e) {

        }

        return objExchangeValueResponse;
    }
}

执行应用程序时出现此错误

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #2 of URL [file:/C:/Users/Usuario/Documents/IdeaProjects/currency-converter/currency-converter-resource/target/classes/data.sql]: CREATE TABLE CURRENCY ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(250) NOT NULL, code VARCHAR(250) NOT NULL ); nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Tabla "CURRENCY" ya existe
Table "CURRENCY" already exists; SQL statement:
CREATE TABLE CURRENCY ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(250) NOT NULL, code VARCHAR(250) NOT NULL ) [42101-200]

为什么 @Entity 试图重新创建一个应该只表示的表,有没有办法禁用它?

最佳答案

这里的问题是文件名 data.sql,正如 spring 所建议的那样,有两个重要的文件可以帮助您控制数据库的创建,它们是

  • schema.sql - 顾名思义,此文件包含创建数据库架构所需的 DDL 语句。
  • data.sql - 此文件将包含正确填充初始数据库所需的所有 DML 语句。

您的应用程序的问题是 DDL 是在 data.sql 文件中指定的,这会使 spring 感到困惑,它会尝试将 DDL 视为 DML。

您问题的解决方案是将 data.sql 重命名为 schema.sql spring 将处理其余部分。

我还发现了存储库的另一个问题,因为您使用的是自定义查询 @Query("SELECT code FROM CURRENCY WHERE code LIKE %:code%") 可能会导致错误存储库已启动,因为 java 实体名称区分大小写。您可以通过以下方式解决此问题 -

一个。因为它的一个类似查询 spring 存储库已经支持它,你可以像这样重写方法 -

List<Currency> findByCodeLike(@Param("code") String code);

B.使用 JPQL 查询,与您在代码中所做的相同,只是更改表名,因为 JPA 实体名称区分大小写

@Query("SELECT code FROM Currency WHERE code LIKE %:code%")
List<Currency> findCurrencyByCode(@Param("code") String code);

C.如果您仍想使用数据库模式“CURRENCY”中的表名保留当前查询,则可以在 @Query 中使用 nativeQuery 标志让 spring 知道您正在使用 native 查询而不是 JPQL -

@Query(value = "SELECT code FROM CURRENCY WHERE code LIKE %:code%", nativeQuery = true)
List<Currency> findCurrencyByCode(@Param("code") String code);

希望这对您有所帮助!

关于java - 防止@Entity重新创建数据库表 - Spring Boot,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62688045/

相关文章:

java - 如何根据从数据库中获取的数据一般地构造对象

java - 如何在抽屉导航的最后一个项目下添加一些空间?

java - spring boot - 在 META-INF/spring.factories 中找不到自动配置 - gradle

java - 如何在多个 Spring boot 应用程序之间共享 H2 内存数据库?

java - java 的 make 文件有问题

java - 在数组中查找重复项,用java中重复出现次数最多的数组填充第二个数组

java - 运行 cucumber 测试时,为什么会跳过它们?

java - Hibernate/JPA - 仅在表存在时才对表进行操作

hibernate - 如何通过 Spring Data JPA 知道底层数据库名称

java - Spring Data Mongo @Indexed 多次创建索引