问题描述
之前Hibernate中的实体类,对应数据库的字段,例如实体类中驼峰命令是:createDate,对应到数据库是带下划线的:create_date字段,一般来说是需要加@Column特别指定对应数据库表的字段的,例如:
@Column(name = "create_date")
public Date getCreateDate() {
public void setCreateDate(Date createDate) {
this.createDate = createDate;
@Column(name = "create_date")
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
@Column(name = "create_date")
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
这样也带来了几个不是很方便的地方:
- 如果类似的字段比较多,创建是类题的字段的工作量比较大
- Hibernate的@Column注解是写在getter上面的,如果你想使用lombok来省略getter和setter,就不行了
所以有必要研究下Hibernate下能否启用自动驼峰命令字段转数据库表的下换线字段的功能。
问题解决
网上都说只要在 application.yml 中增加
spring.jpa.hibernate.properties.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
经过本人测试无效,这个PhysicalNamingStrategyStandardImpl实际就是啥也没有转换
后来这样做才是正确的:
新建Camel2SnakeNamingStrategy.java 实现驼峰转下换线
package com.terrynow.test
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class Camel2SnakeNamingStrategy extends PhysicalNamingStrategyStandardImpl {
public Identifier toPhysicalCatalogName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
public Identifier toPhysicalColumnName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
public Identifier toPhysicalSchemaName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
public Identifier toPhysicalSequenceName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
public Identifier toPhysicalTableName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
private Identifier convertToSnakeCase(final Identifier identifier) {
if (identifier == null) {
final String newName = identifier.getText().replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
return Identifier.toIdentifier(newName);
package com.terrynow.test
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class Camel2SnakeNamingStrategy extends PhysicalNamingStrategyStandardImpl {
@Override
public Identifier toPhysicalCatalogName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalColumnName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalSchemaName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalSequenceName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalTableName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
private Identifier convertToSnakeCase(final Identifier identifier) {
if (identifier == null) {
return null;
}
final String newName = identifier.getText().replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
return Identifier.toIdentifier(newName);
}
}
package com.terrynow.test
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
public class Camel2SnakeNamingStrategy extends PhysicalNamingStrategyStandardImpl {
@Override
public Identifier toPhysicalCatalogName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalColumnName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalSchemaName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalSequenceName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
@Override
public Identifier toPhysicalTableName(final Identifier identifier, final JdbcEnvironment jdbcEnv) {
return convertToSnakeCase(identifier);
}
private Identifier convertToSnakeCase(final Identifier identifier) {
if (identifier == null) {
return null;
}
final String newName = identifier.getText().replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
return Identifier.toIdentifier(newName);
}
}
然后在 Application 中配置:
主要看这句:factoryBean.setPhysicalNamingStrategy(new Camel2SnakeNamingStrategy());//驼峰转下划线实现
其他的根据实际情况修改
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
package com.terrynow.test;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
// 排除 DataSource, JPARepositories, HibernateJpa 的自动配置
@SpringBootApplication(exclude = {
// DataSourceAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
@EnableTransactionManagement(proxyTargetClass = true)
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
// Package contain entity classes
factoryBean.setPackagesToScan("com.terrynow.test.entity");
factoryBean.setDataSource(dataSource);
factoryBean.setPhysicalNamingStrategy(new Camel2SnakeNamingStrategy());//驼峰转下划线实现
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
/*
* Copyright (c) 2021.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.terrynow.test;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
//@EnableDiscoveryClient
// 排除 DataSource, JPARepositories, HibernateJpa 的自动配置
@SpringBootApplication(exclude = {
// DataSourceAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
// 开启事务管理
@EnableTransactionManagement(proxyTargetClass = true)
public class MyApplication {
@Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Autowired
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
// Package contain entity classes
factoryBean.setPackagesToScan("com.terrynow.test.entity");
factoryBean.setDataSource(dataSource);
factoryBean.setPhysicalNamingStrategy(new Camel2SnakeNamingStrategy());//驼峰转下划线实现
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
}
/*
* Copyright (c) 2021.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.terrynow.test;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
//@EnableDiscoveryClient
// 排除 DataSource, JPARepositories, HibernateJpa 的自动配置
@SpringBootApplication(exclude = {
// DataSourceAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
// 开启事务管理
@EnableTransactionManagement(proxyTargetClass = true)
public class MyApplication {
@Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
@Autowired
@Bean(name = "sessionFactory")
public SessionFactory getSessionFactory(DataSource dataSource) throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
// Package contain entity classes
factoryBean.setPackagesToScan("com.terrynow.test.entity");
factoryBean.setDataSource(dataSource);
factoryBean.setPhysicalNamingStrategy(new Camel2SnakeNamingStrategy());//驼峰转下划线实现
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
@Autowired
@Bean(name = "transactionManager")
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
return new HibernateTransactionManager(sessionFactory);
}
}
如果是普通SpringMVC项目整合Hibernate5启用实体类驼峰命令转数据库表字段下划线实现,也做类似的配置,详见:https://blog.terrynow.com/2022/05/02/springmvc-hibernate-auto-convert-pojo-camel-to-underline-strategy/
文章评论