SpringBoot-Data-JPA2.0命名策略详解

最近有个项目因为命名策略的原因导致数据库表的不符合标准,所以看了下源码,废话不多说上代码!

现有的命名策略

  1. jpa现有的命名策略设置:hibernate.implicit_naming_strategy(隐式),hibernate.physical_naming_strategy(物理显示)
  2. implicit_naming_strategy 有5个策略:实现ImplicitNamingStrategy接口,其中SpringImplicitNamingStrategy策略是实现了ImplicitNamingStrategyJpaCompliantImpl只是重写了关联表的表名方法
    前4中基于hibernate
  3. physical_naming_strategy 有2个策略:实现PhysicalNamingStrategy接口,
    分别是PhysicalNamingStrategyStandardImpl、SpringPhysicalNamingStrategy。其中SpringPhysicalNamingStrategy 会将所有的大写都转成小写并加"_". 在这里插入图片描述

项目大概

使用SpringBoot2.4.2,mysql5.7
项目目录: 我这里因为项目需要用的是多数据源,隐式策略为默认,数据源1物理策略默认,数据源2物理策略为 SpringPhysicalNamingStrategy在这里插入图片描述

数据源读取配置文件并注入
@Configuration
public class DataSourceConfig {

    @Bean(name = "primaryDataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource(){return DataSourceBuilder.create().build();
    }

    @Bean(name = "secondDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.second")
    public DataSource secondDataSource(){return DataSourceBuilder.create().build();
    }
}

**主数据源**
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(entityManagerFactoryRef = "primaryEntityManagerFactory", // 配置连接工厂 entityManagerFactory
        transactionManagerRef = "primaryTransactionManager", // 配置 事物管理器 transactionManager
        basePackages = {"com.mj.jpaname.primary.repository"})
public class PrimaryDataSourceConfig {

    @Autowired
    private Environment env;

    @Autowired
    @Qualifier("primaryDataSource")
    private DataSource primaryDataSource;

    @Primary
    @Bean(name = "primaryEntityManager")
    public EntityManager entityManager() {
        return primaryEntityManagerFactory().getObject().createEntityManager();
    }

    @Bean(name = "primaryTransactionManager")
    public PlatformTransactionManager primaryTransactionManager() {
        EntityManagerFactory factory = primaryEntityManagerFactory().getObject();
        return new JpaTransactionManager(factory);
    }

    @Bean(name = "primaryEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(primaryDataSource);
        factory.setPackagesToScan("com.mj.jpaname.primary.domain");
        factory.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
        Properties jpaProperties = new Properties();
        jpaProperties.put("hibernate.hbm2ddl.auto", "update");
        jpaProperties.put("hibernate.show_sql", env.getProperty("spring.jpa.show-sql"));
        jpaProperties.put("hibernate.format_sql", env.getProperty("spring.jpa.properties.hibernate.format_sql"));
        jpaProperties.put("hibernate.dialect", env.getProperty("spring.jpa.hibernate.dialect"));
        jpaProperties.put("hibernate.current_session_context_class", "org.springframework.orm.hibernate5.SpringSessionContext");
        factory.setJpaProperties(jpaProperties);
        factory.setPersistenceUnitName("primaryPersistenceUnit");
        return factory;
    }
}

二数据源:将primary改成second ,并在secondEntityManagerFactory()方法中加入
jpaProperties.put("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");

配置文件

spring:
  datasource:
    primary:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/cs?useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true&serverTimezone=Asia/Shanghai
      username: root
      password: 123456

    second:
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/cs2?useUnicode=true&characterEncoding=UTF-8&useOldAliasMetadataBehavior=true&serverTimezone=Asia/Shanghai
      username: root
      password: 123456

  jpa:
    # 显示sql
    show-sql: false
    properties:
      hibernate:
        format_sql: true
    hibernate:
      ddl-auto: update
      dialect: org.hibernate.dialect.MySQL55Dialect

实体类

@Entity
@Setter
@Getter
@NoArgsConstructor
@Table(name = "t_teacher")
public class TeacherEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(name = "create_date")
    private Date createDate;

    @Column(name = "update_d")
    private Date updateDate;
}

@Entity
@Setter
@Getter
@NoArgsConstructor
public class StudentEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private Date createDate;
    private Date updateDate;
}

@Entity
@Setter
@Getter
@NoArgsConstructor
public class UserEntity implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private Date createDate;
}

@Entity
@Setter
@Getter
@NoArgsConstructor
@Table(name = "t_things")
public class ThingsEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    @Column(name = "create_date")
    private Date createDate;

}

分析

  1. 首先在我们设置的2个数据源配置的工厂类 LocalContainerEntityManagerFactoryBean 继承了AbstractEntityManagerFactoryBean 抽象类,该抽象类实现了InitializingBean,所以必须实现afterPropertiesSet()方法,在初始化bean的时候执行。所以在项目启动后会调用afterPropertiesSet(),里面会设置对应的命名策略。
  2. LocalContainerEntityManagerFactoryBeanafterPropertiesSet()会调用分类的afterPropertiesSet在这里插入图片描述
  3. EntityManagerFactory emf = provider.createContainerEntityManagerFactory(this.persistenceUnitInfo, getJpaPropertyMap()); ,其中**getJpaPropertyMap()**就是我们在里面设置的配置 .
    在这里插入图片描述
  4. EntityManagerFactoryBuilderImpl的构造方法中会建立对应的策略选择器
    在这里插入图片描述
  5. 在建立策略选择器会将对应默认策略设置好已被后续的使用,隐式的命名策略也是在这里设置的
    在这里插入图片描述
    在这里插入图片描述
  6. MetadataBuilderImpl类中创建对象时, this.options = new MetadataBuildingOptionsImpl( serviceRegistry );
    这步很关键,因为创建MetadataBuilderImpl时设置了命名策略且后面使用的命名策略都是从这个options得到的。
    在这里插入图片描述
    StrategySelectorImpl.resolveDefaultableStrategy() 该类根据配置中有无设置对应的命名策略,其中隐身命名策略若没有设置,则都上面的策略选择器中获取defaultImplicitNamingStrategyJpaCompliantImpl策略,而显示命名策略默认获取PhysicalNamingStrategyStandardImpl 策略,这样命名策略设置完成。
  7. 开始对实体类管理器bulid建立,来建立对应的表、字段。
    在这里插入图片描述
  8. MetadataBuildingProcess.complete会将之前的策略等设置包装成一个MetadataBuildingContextRootImpl 共后面使用.
    在这里插入图片描述
  9. 在建立表的过程中会解析实体类上是否标注了**@Table** 这个注解
    在这里插入图片描述
  10. 根据**@Table** 设置的属性来建立对应的表,根据是否有tableName来决定和命名策略来获得模型。在这里插入图片描述在这里插入图片描述
  11. 根据第8上面设置的MetadataBuildingContextRootImpl的options。若没有tableName则根据设置的隐式命名策略,获取对应模型名。若有tableName的话则用tableName。
  12. 最后会根据当前设置的物理策略来确定最后的表名
    在这里插入图片描述
    13.同期字段的话会根据是否添加**@Column** 注解来进行设置。

结果

需注意表名的大写会变成小写
在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值