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

时间:2020-07-02 02:27:45

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

据我所知,我是Spring引导数据jpa的新手,据我所知,@ Entity用于表示应用程序中的数据库表,对于该项目,我使用spring-boot 2.2.5.RELEASEH2内存数据库。

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

在资源/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为什么要尝试重新创建应该仅代表的表,并且有办法禁用它?

3 个答案:

答案 0 :(得分:2)

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

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

与您的应用程序有关的问题是,在data.sql文件中指定了DDL,这会使spring感到困惑,并且会考虑将其视为DML来尝试执行DDL。

您所遇到的问题的解决方法是将data.sql重命名为schema.sql,而spring将处理其余的问题。

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

A。由于其类似的查询,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”中那样保留当前查询的表名,则可以使用nativeQuery中的@Query标志让spring知道您正在使用本机查询而不是JPQL-< / p>

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

希望这会有所帮助!

答案 1 :(得分:1)

发生错误是因为在您运行应用程序时,它尝试重新创建表,其解决方法如下:

  1. 在创建表之前,在data.sql中添加drop table if exists [tablename]
  2. 将语句从CREATE TABLE更改为CREATE TABLE IF NOT EXISTS

答案 2 :(得分:0)

JPA具有用于DDL生成的功能,可以将其设置为在启动时针对数据库运行。这是通过两个外部属性控制的:

  1. spring.jpa.generate-ddl(布尔值)打开和关闭功能 并且与供应商无关。
  2. spring.jpa.hibernate.ddl-auto(枚举)是一种Hibernate功能, 可以更精细地控制行为。

参考spring boot JPA docs

spring.jpa.hibernate.ddl-auto属性如何工作?您可以参考以下基于环境的配置。

相关问题