Hibernate
映射介绍Hibernate
中,默认的生成关系是将咱们驼峰命名的实体进行拼接下划线同时转小写。java
这种状况咱们能够接受,默认的设置很规范。spring
可是这样,咱们在实体之上声明了@Table
注解,并说咱们的表名是Mandatory_Instrument_Apply
,可是Hibernate
仍是将咱们的数据表映射为小写加下划线的形式。这种状况看起来就有些不合理了。数据库
由于须要兼容老项目,老项目的数据表命名不很很规范,因此须要用最小的成本实现数据库的兼容。浏览器
因此设计的表名映射格式为,若是不加@Table
注解,则将实体名按照Hibernate
默认的生成规则进行生成,若是加了@Table
注解,则填写的name
就做为表名映射,不进行任何处理。ide
抛出来一个问题,无从下手。spring-boot
打开浏览器,看看有没有前人的经验,Google
来Google
去发现找不着啥有价值的信息。可是在StackOverflow
上找到一篇引人思索的问题。测试
Spring boot JPA insert in TABLE with uppercase name with Hibernate - StackOverflowspa
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
将这个配置声明为org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
,就能实现大写的转换。hibernate
试试再说:设计
将配置按该问题的回答进行修改:
测试一番:
加了@Table
注解的,是咱们想要的配置,直接映射。那不加注解的呢?
这个又不是咱们想要的了,这个注解应该是直接将注解中的名或实体名映射到数据表,不作任何修改。
正当束手无策之时,再去看一下配置,有了新的领悟。
org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
,这个配置的不就是一个实现类吗?我是否是也能够写一个类而后将我写的类配置上呢?
点进去,发现不过是一个实现了PhysicalNamingStrategy
与Serializable
两个接口的类。
看实现的toPhysicalTableName
方法,应该就是生成数据表名的方法。直接将name
返回,这就和咱们以前猜测的一致,这个配置是直接将@Table
或实体名映射到数据表。
YunzhiNamingStrategy
创建配置类YunzhiNamingStrategy.java
,云智命名策略,分别实现上述PhysicalNamingStrategyStandardImpl
实现的两个接口。同时实现接口中声明的方法。
package com.mengyunzhi.demo.config; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import java.io.Serializable; /** * @author zhangxishuo on 2018/6/15 * 云智命名策略 * 实体与数据表名的关系配置 */ public class YunzhiNamingStrategy implements PhysicalNamingStrategy, Serializable { @Override public Identifier toPhysicalCatalogName(Identifier identifier, JdbcEnvironment jdbcEnvironment) { return null; } @Override public Identifier toPhysicalSchemaName(Identifier identifier, JdbcEnvironment jdbcEnvironment) { return null; } @Override public Identifier toPhysicalTableName(Identifier identifier, JdbcEnvironment jdbcEnvironment) { return null; } @Override public Identifier toPhysicalSequenceName(Identifier identifier, JdbcEnvironment jdbcEnvironment) { return null; } @Override public Identifier toPhysicalColumnName(Identifier identifier, JdbcEnvironment jdbcEnvironment) { return null; } }
而后将该项配置修改成咱们本身创建的实现类。
由于该接口中有多个配置项,如:数据库名、字段名等,咱们只想修改实体到数据表的命名策略,因此咱们找到了另外一个实现PhysicalNamingStrategy
命名策略的实现类:SpringPhysicalNamingStrategy
。
这就是咱们第一次演示的策略,不管添不添加@Table
注解,都会映射到小写的加下划线的表名。
同时这里的字段映射为小写下划线咱们是须要保留的,为了代码的复用,咱们用到了面向对象的继承大法。
package com.mengyunzhi.demo.config; import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; /** * @author zhangxishuo on 2018/6/15 * 云智命名策略 * 实体与数据表名的关系配置 */ public class YunzhiNamingStrategy extends SpringPhysicalNamingStrategy { }
咱们对父类中的toPhysicalTableName
方法不满意,Command + N
,重写父类方法。
package com.mengyunzhi.demo.config; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; /** * @author zhangxishuo on 2018/6/15 * 云智命名策略 * 实体与数据表名的关系配置 */ public class YunzhiNamingStrategy extends SpringPhysicalNamingStrategy { @Override public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) { return super.toPhysicalTableName(name, jdbcEnvironment); } }
咱们能够开始咱们的逻辑了。
有@Table
注解的,就按@Table
中的名称中,不然就按Spring
默认的父类走。
可是问题出现了,Identifier
中给咱们的名称就是已经处理好的名称。
假如这么写:
@Entity public class MandatoryInstrumentApply { }
那咱们的Identifier
中的text
值就是MandatoryInstrumentApply
。
@Entity @Table(name = "Mandatory_Instrument_Apply") public class MandatoryInstrumentApply { }
那咱们的Identifier
中的text
值就是Mandatory_Instrument_Apply
。
Hibernate
是把应该处理好的名称告诉咱们,可是不会告诉咱们这个名称是实体的名仍是在注解上获取的。
package com.mengyunzhi.demo.config; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy; import javax.persistence.Table; /** * @author zhangxishuo on 2018/6/15 * 云智命名策略 * 实体与数据表名的关系配置 */ public class YunzhiNamingStrategy extends SpringPhysicalNamingStrategy { // 定义包名 private static final String packageName = "com.mengyunzhi.demo.entity."; /** * 重写父类生成表名的方法 */ @Override public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) { try { // 获取实体类 Class entityClass = Class.forName(packageName + name.getText()); // 判断类上是否有Table注解 Boolean hasAnnotation = entityClass.isAnnotationPresent(Table.class); // 存在Table注解 if (hasAnnotation) { // 获取Table注解实例 Table table = (Table) entityClass.getAnnotation(Table.class); // 若是注解中的name字段不为空 if (!table.name().equals("")) { // 不对名称进行处理 return name; } } // 表示这是一个类名,按父类操做进行处理 return super.toPhysicalTableName(name, jdbcEnvironment); } catch (ClassNotFoundException e) { // 找不到实体类,说明确定是@Table注解中的名称 return name; } } }