Spring Boot 的 Hibernate 字段命名问题(命名策略)

Posted

技术标签:

【中文标题】Spring Boot 的 Hibernate 字段命名问题(命名策略)【英文标题】:Hibernate field naming issue with Spring Boot (naming strategy) 【发布时间】:2020-06-06 20:56:24 【问题描述】:

请注意,此代码确实适用于普通 Spring,但不适用于 Spring Boot(v1.3.3),我是否缺少某些东西,因为这是从有效的 spring 应用程序导入的。下面的代码来自spring boot app

@Entity
@Table(name="project")
public class Project implements Serializable

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="id")
    private int id;

    @Column(name="teamId")
    private int teamId;

    //private String Rentabiliteit;

    @Column
    //@Index(name="IProject_status",columnNames="Status")
    private String status;

    @Column
    //@Index(name="IProject_naam",columnNames="Naam")
    private String naam;
    //public Prototype m_Prototype;
    //public Team m_Team;


SQL

CREATE TABLE IF NOT EXISTS `project` (
`id` int(11) NOT NULL,
`teamId` int(11) DEFAULT NULL,
`status` varchar(255) DEFAULT NULL,
`naam` varchar(255) DEFAULT NULL
 ) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=latin1;

错误

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:           
 Unknown column 'project0_.team_id' in 'field list'

已编辑:Application.yml

spring:

mvc:
  view:
    prefix: /WEB-INF/jsp/
    suffix: .jsp

datasource:
    url: jdbc:mysql://localhost:3306/oxyplast
    username: oxyplastuser
    password: oxyplastuserpw

jpa:
  properties:
    hibernate:
      current_session_context_class: org.springframework.orm.hibernate4.SpringSessionContext 
      namingStrategy: org.hibernate.cfg.DefaultNamingStrategy

【问题讨论】:

我怀疑问题是否出在您发布的代码中。你能发布完整的堆栈跟踪吗? github.com/thibitus/SE4-Oxyplast/tree/master/OxyplastSpringBoot @MadhusudanaReddySunnapu 这太长了,但我这是造成问题的原因 查看了域包。 Project 是唯一被注释为实体的类。剩下的都是普通班。这是正确的吗?您可以发布其中包含根本原因字符串的部分堆栈跟踪吗? 这个github线程很有用:github.com/spring-projects/spring-boot/issues/2129 【参考方案1】:

自 SPRING-BOOT 1.4 以来

从 1.4 开始,由于切换到 Hibernate 5,命名策略已更新为 SpringPhysicalNamingStrategy 其中should be very close 为 1.3 默认值。

另请参阅:

Spring's naming strategy

以前的版本

Spring Boot 提供 ImprovedNamingStrategy 作为默认命名策略,这使得 Hibernate 搜索 team_id 列(从 int teamId 字段推断)。由于您的表中不存在此列,因此这是错误的原因。来自 Hibernate 文档:

一种改进的命名策略,它更喜欢嵌入下划线而不是混合大小写名称

你有两个选择:

    明确提供列名@Column(name="teamId")。在早期的 Boot 版本中曾经有一个 bug,现在没有了。

    在 Spring Boot 属性中更改命名策略,并告诉它使用EJB3NamingStrategy,它不会将camelCase 转换为snake_case,而是保持原样。 p>

【讨论】:

我提供了明确的列名,它可以被 hiberante 以不同的方式映射吗?有没有办法看到这个? 在我的 application.yml 中有这一行 我已经通过将其重命名为 teamid(不带大写 I)解决了这个问题!非常感谢您的参与和帮助 添加这些属性为我解决了这个问题:--spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl --spring.jpa.hibernate.naming .physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl 我通过在文件 application.properties 中添加这一行来解决问题:spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl【参考方案2】:

以下策略对我有用

spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.DefaultComponentSafeNamingStrategy

【讨论】:

spring.jpa.hibernate.naming-strategy 在最新版本中不存在此解决方案可能有效但不会在最新版本中。【参考方案3】:

最新版本:

    spring-boot-starter-data-jpa: ➡ 1.5.2.RELEASE
    hibernate-core:5.0.12.Final

这个类

PhysicalNamingStrategyStandardImpl

需要扩展并添加到休眠属性中。

这是一个完整的工作版本

    public class PhysicalNamingStrategyImpl extends PhysicalNamingStrategyStandardImpl implements Serializable 

    public static final PhysicalNamingStrategyImpl INSTANCE = new PhysicalNamingStrategyImpl();

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



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

在配置数据源时应该像这样将它链接到休眠状态。

properties.put("hibernate.physical_naming_strategy", "my.Package.PhysicalNamingStrategyImpl");

这是数据源配置的完整工作版本

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "entityManagerFactory",
        basePackages =  "com.xxxxxx.repository" 
)
public class SharedDataSourceConfig 

    @Value("$startup.ddl-auto")
    String hbm2ddl;

    @Primary
    @Bean(name = "dataSource")
    @ConfigurationProperties("spring.datasource.shared")
    public DataSource customerDataSource() 
        return DataSourceBuilder.create().build();
    

    @Primary
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("dataSource") DataSource dataSource) 
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.hbm2ddl.auto", hbm2ddl);
        properties.put("hibernate.physical_naming_strategy", "my.package.PhysicalNamingStrategyImpl");
        return builder
                .dataSource(dataSource)
                .packages(PackageScannerHelper.getPackagesToScan())
                .persistenceUnit("shared")
                .properties(properties)
                .build();
    

    @Primary
    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("entityManagerFactory") EntityManagerFactory
                    entityManagerFactory
    ) 
        return new JpaTransactionManager(entityManagerFactory);
    

【讨论】:

【参考方案4】:

如果您使用的是 Spring Boot 2.0.2 和 Hibernate 5.3.4,则设置以下属性将解决此问题。

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

【讨论】:

我在我的项目中尝试了同样的方法,但它不起作用。我已在此链接***.com/questions/61010482/… 中发布了我的问题【参考方案5】:

这对我来说适用于 spring boot 1.4.0 和 hibernate entitymanager 4.3.8.Final

application.properties

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

【讨论】:

【参考方案6】:

application.properties

spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.DefaultComponentSafeNamingStrategy

以上属性对我有用。 休眠 4.3.11.Final spring boot 1.4.2.RELEASE

【讨论】:

以上是关于Spring Boot 的 Hibernate 字段命名问题(命名策略)的主要内容,如果未能解决你的问题,请参考以下文章

制作多个 EntityManager(Spring-Boot-JPA、Hibernate、MSSQL)

Spring boot/Hibernate 创建表失败

Hibernate 和 CRUDRepository Spring Boot

Spring Boot JPA Hibernate - 以毫秒精度存储日期

spring boot DAO之Hibernate

深入JVM分析spring-boot应用hibernate-validator