用于SQLite的Spring boot2 JPA命名策略

时间:2019-10-04 14:46:19

标签: java sqlite spring-boot spring-data-jpa naming-strategy

我想用CrudRepository实现Spring Boot 2应用程序。我无法弄清楚应用程序中的命名策略是怎么回事。当我在存储库中调用一个方法(例如findAll())时,它会转换数据库中表的名称,并导致查询崩溃。 当然,我尝试了类似问题的解决方案:ImprovedNamingStrategy no longer working in Hibernate 5 Hibernate naming strategy changing table names

spring boot 2.1.8 (spring-boot-starter-data-jpa)

Spring boot完全忽略了application.properties文件中的命名策略属性(其他属性运行良好)

在spring boot 2.1.8的源代码中,我找到了战略道具的名称并将其复制到属性中:

可以分别通过设置spring.jpa.hibernate.naming.physical-strategyspring.jpa.hibernate.naming.implicit-strategy属性来配置物理和隐式策略实现的完全限定类名。 另外,如果在应用程序上下文中有ImplicitNamingStrategyPhysicalNamingStrategy bean,则Hibernate将自动配置为使用它们。 但这行不通。

谢谢。

application.properties

spring.application.name=file parser
driverClassName=org.sqlite.JDBC
url=jdbc:sqlite:C:\\Java\\ParseSite\\sample.db
user=admin
pass=123

#nothing works
spring.jpa.hibernate.naming.implicit-strategy=ru.laz.db.ImplicitNamingStrategyImpl
spring.jpa.hibernate.naming.physical-strategy=ru.laz.db.PhysicalNamingStrategyImpl
spring.jpa.properties.hibernate.physical_naming_strategy = ru.laz.db.PhysicalNamingStrategyImpl

spring.jpa.properties.hibernate.dialect = ru.laz.db.SQLitePrefs.SQLiteDialect

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <properties>
        <spring.boot.version>2.1.8.RELEASE</spring.boot.version>
        <java.version>1.8</java.version>
    </properties>

    <groupId>ru.laz</groupId>
    <artifactId>parse-site</artifactId>
    <version>0.1.0</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>${spring.boot.version}</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.asynchttpclient</groupId>
            <artifactId>async-http-client</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.11.3</version>
        </dependency>
        <dependency>
            <groupId>org.xerial</groupId>
            <artifactId>sqlite-jdbc</artifactId>
            <version>3.16.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>${spring.boot.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.10</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

NewsBlockRepo.java

@Repository
public interface NewsBlockRepo extends CrudRepository<NewsBlock,Integer> {

    //only this method works ok
    @Modifying
    @Transactional
    @Query(value = "insert or replace into news_blocks (date, title, url, body, sent) values (:date, :title, :url, :body, :sent)", nativeQuery = true)
    void insertOrIgnore(@Param("date") String date, @Param("title") String title, @Param("url") String url, @Param("body") String body, @Param("sent") int sent);
}

NewsBlock.java

package ru.laz.db;


import javax.persistence.*;

@Entity
@Table(name = "news_blocks")
public class NewsBlock {

    @Id
    @Column(name = "id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
        private int id;
    @Column(name = "date")
        private String date = "";//for unique constaint in sqlite
    @Column(name = "title")
        private String title = "";
    @Column(name = "url")
        private String url = "";
    @Column(name = "body")
        private String body = "";
    @Column(name = "sent")
        private int sent = 0;

    public long getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getSent() {
        return sent;
    }

    public void setSent(int sent) {
        this.sent = sent;
    }

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;
        if (!(o instanceof NewsBlock)) {
            return false;
        }
        NewsBlock nb = (NewsBlock) o;
        return this.url.equals(nb.getUrl()) && this.title.equals(nb.getTitle()) && this.body.equals(nb.getBody() );
    }

    @Override
    public String toString() {
        return "date: " + date + " title: "+title + " url: " + url + " text: " + body;
    }
}

我的PhysicalNamingStrategyImpl

    public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable {

        public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();

        @Override
        public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment context) {
            String nameModified = name.getText();
            // Do whatever you want with the name modification
            return new Identifier(nameModified, name.isQuoted());
        }
}

甚至是ImplicitNamingStrategyImpl

public class ImplicitNamingStrategyImpl extends ImplicitNamingStrategyJpaCompliantImpl {

        @Override
    protected Identifier toIdentifier(String stringForm, MetadataBuildingContext buildingContext) {
        return super.toIdentifier(stringForm, buildingContext);
    }
}

从存储库调用方法的最终控制器

    @RequestMapping("/getUnsent")
    public String getUnsent() throws Exception {
        return objectMapper.writeValueAsString(newsBlockRepo.findAll());
    }

错误:

org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (no such column: newsblock0_.id)

1 个答案:

答案 0 :(得分:0)

错误为no such column: newsblock0_.id。显然,它在news_block块表中说,没有id,这意味着spring-boot自声明以来就在Entity类中考虑了id。实体类或多或少等于您的表。

它期望您声明的所有变量都必须在表中,但是有时您声明的变量不必在表中。因此,您应该表示@Transient

@Transient批注用于指示字段不会保留在数据库中。