[Feature] add table prefix

This commit is contained in:
songyinyin 2020-07-19 15:06:37 +08:00
parent 9ac3929a8e
commit d159654fc6
18 changed files with 184 additions and 21 deletions

View File

@ -1,6 +1,9 @@
package com.github.kfcfans.powerjob.server.persistence.config;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateProperties;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateSettings;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
@ -15,6 +18,8 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -39,6 +44,9 @@ public class CoreJpaConfig {
@Resource(name = "omsCoreDatasource")
private DataSource omsCoreDatasource;
@Resource
private PowerJobPhysicalNamingStrategy powerJobPhysicalNamingStrategy;
public static final String CORE_PACKAGES = "com.github.kfcfans.powerjob.server.persistence.core";
/**
@ -49,7 +57,7 @@ public class CoreJpaConfig {
*
* @return 配置Map
*/
private static Map<String, Object> genDatasourceProperties() {
private Map<String, Object> genDatasourceProperties() {
JpaProperties jpaProperties = new JpaProperties();
jpaProperties.setOpenInView(false);
@ -57,7 +65,14 @@ public class CoreJpaConfig {
HibernateProperties hibernateProperties = new HibernateProperties();
hibernateProperties.setDdlAuto("update");
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), new HibernateSettings());
// 配置JPA自定义表名称策略
HibernateSettings hibernateSettings = new HibernateSettings();
List<HibernatePropertiesCustomizer> customizers = new ArrayList<>();
customizers.add(
new NamingStrategiesHibernatePropertiesCustomizer(powerJobPhysicalNamingStrategy, null));
hibernateSettings.hibernatePropertiesCustomizers(customizers);
return hibernateProperties.determineHibernateProperties(jpaProperties.getProperties(), hibernateSettings);
}
@Primary
@ -79,4 +94,31 @@ public class CoreJpaConfig {
return new JpaTransactionManager(Objects.requireNonNull(initCoreEntityManagerFactory(builder).getObject()));
}
/**
* 参考 HibernateJpaConfiguration.NamingStrategiesHibernatePropertiesCustomizer
*/
private static class NamingStrategiesHibernatePropertiesCustomizer implements HibernatePropertiesCustomizer {
private final PhysicalNamingStrategy physicalNamingStrategy;
private final ImplicitNamingStrategy implicitNamingStrategy;
NamingStrategiesHibernatePropertiesCustomizer(PhysicalNamingStrategy physicalNamingStrategy,
ImplicitNamingStrategy implicitNamingStrategy) {
this.physicalNamingStrategy = physicalNamingStrategy;
this.implicitNamingStrategy = implicitNamingStrategy;
}
@Override
public void customize(Map<String, Object> hibernateProperties) {
if (this.physicalNamingStrategy != null) {
hibernateProperties.put("hibernate.physical_naming_strategy", this.physicalNamingStrategy);
}
if (this.implicitNamingStrategy != null) {
hibernateProperties.put("hibernate.implicit_naming_strategy", this.implicitNamingStrategy);
}
}
}
}

View File

@ -0,0 +1,113 @@
package com.github.kfcfans.powerjob.server.persistence.config;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.io.Serializable;
import java.util.Locale;
/**
* 自定义表前缀配置项 oms.table-prefix 不配置时不增加表前缀
* 参考实现{@link org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy}
* <p>
* 1. 继承 PhysicalNamingStrategy 实现自定义表前缀
* </p>
* <p>
* 2. 修改@Query(nativeQuery = true)和其SQL用对象名和属性名代替表名和数据库字段名
* </p>
*
* @author songyinyin
* @date 2020/7/18 下午 11:01
* @since 3.1.4
*/
@Component
public class PowerJobPhysicalNamingStrategy implements PhysicalNamingStrategy, Serializable {
@Value("${oms.table-prefix:}")
private String tablePrefix;
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
/**
* 映射物理表名称把实体表 AppInfoDO DO 去掉再加上表前缀
*
* @param name 实体名称
* @param jdbcEnvironment jdbc环境变量
* @return 映射后的物理表
*/
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
Identifier identifier = apply(name, jdbcEnvironment);
String text = identifier.getText();
String noDOText = StringUtils.endsWithIgnoreCase(text, "do") ? text.substring(0, text.length() - 2) : text;
String newText = StringUtils.hasLength(tablePrefix) ? tablePrefix + noDOText : noDOText;
return new Identifier(newText, identifier.isQuoted());
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return apply(name, jdbcEnvironment);
}
private Identifier apply(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name == null) {
return null;
}
StringBuilder builder = new StringBuilder(name.getText().replace('.', '_'));
for (int i = 1; i < builder.length() - 1; i++) {
if (isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
builder.insert(i++, '_');
}
}
return getIdentifier(builder.toString(), name.isQuoted(), jdbcEnvironment);
}
/**
* Get an identifier for the specified details. By default this method will return an
* identifier with the name adapted based on the result of
* {@link #isCaseInsensitive(JdbcEnvironment)}
*
* @param name the name of the identifier
* @param quoted if the identifier is quoted
* @param jdbcEnvironment the JDBC environment
* @return an identifier instance
*/
protected Identifier getIdentifier(String name, boolean quoted, JdbcEnvironment jdbcEnvironment) {
if (isCaseInsensitive(jdbcEnvironment)) {
name = name.toLowerCase(Locale.ROOT);
}
return new Identifier(name, quoted);
}
/**
* Specify whether the database is case sensitive.
*
* @param jdbcEnvironment the JDBC environment which can be used to determine case
* @return true if the database is case insensitive sensitivity
*/
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return true;
}
private boolean isUnderscoreRequired(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
}
}

View File

@ -13,7 +13,7 @@ import java.util.Date;
*/
@Data
@Entity
@Table(name = "app_info", uniqueConstraints = {@UniqueConstraint(name = "appNameUK", columnNames = {"appName"})})
@Table(uniqueConstraints = {@UniqueConstraint(name = "appNameUK", columnNames = {"appName"})})
public class AppInfoDO {
@Id

View File

@ -13,7 +13,7 @@ import java.util.Date;
*/
@Data
@Entity
@Table(name = "container_info", indexes = {@Index(columnList = "appId")})
@Table(indexes = {@Index(columnList = "appId")})
public class ContainerInfoDO {
@Id

View File

@ -18,7 +18,7 @@ import java.util.Date;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "instance_info", indexes = {@Index(columnList = "jobId"), @Index(columnList = "appId"), @Index(columnList = "instanceId")})
@Table(indexes = {@Index(columnList = "jobId"), @Index(columnList = "appId"), @Index(columnList = "instanceId")})
public class InstanceInfoDO {
@Id

View File

@ -18,7 +18,7 @@ import java.util.Date;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "job_info", indexes = {@Index(columnList = "appId")})
@Table(indexes = {@Index(columnList = "appId")})
public class JobInfoDO {

View File

@ -15,7 +15,7 @@ import java.util.Date;
@Data
@Entity
@NoArgsConstructor
@Table(name = "oms_lock", uniqueConstraints = {@UniqueConstraint(name = "lockNameUK", columnNames = {"lockName"})})
@Table(uniqueConstraints = {@UniqueConstraint(name = "lockNameUK", columnNames = {"lockName"})})
public class OmsLockDO {
@Id

View File

@ -15,7 +15,7 @@ import java.util.Date;
@Data
@Entity
@NoArgsConstructor
@Table(name = "server_info", uniqueConstraints = {@UniqueConstraint(columnNames = "ip")})
@Table(uniqueConstraints = {@UniqueConstraint(columnNames = "ip")})
public class ServerInfoDO {
@Id

View File

@ -13,7 +13,7 @@ import java.util.Date;
*/
@Data
@Entity
@Table(name = "user_info")
@Table
public class UserInfoDO {
@Id

View File

@ -17,7 +17,7 @@ import java.util.Date;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "workflow_info", indexes = {@Index(columnList = "appId")})
@Table(indexes = {@Index(columnList = "appId")})
public class WorkflowInfoDO {
@Id

View File

@ -17,7 +17,7 @@ import java.util.Date;
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "workflow_instance_info")
@Table
public class WorkflowInstanceInfoDO {
@Id

View File

@ -37,19 +37,19 @@ public interface InstanceInfoRepository extends JpaRepository<InstanceInfoDO, Lo
@Transactional
@Modifying
@CanIgnoreReturnValue
@Query(value = "update instance_info set status = ?2, running_times = ?3, actual_trigger_time = ?4, finished_time = ?5, task_tracker_address = ?6, result = ?7, instance_params = ?8, gmt_modified = ?9 where instance_id = ?1", nativeQuery = true)
@Query(value = "update InstanceInfoDO set status = ?2, runningTimes = ?3, actualTriggerTime = ?4, finishedTime = ?5, taskTrackerAddress = ?6, result = ?7, instanceParams = ?8, gmtModified = ?9 where instanceId = ?1")
int update4TriggerFailed(long instanceId, int status, long runningTimes, long actualTriggerTime, long finishedTime, String taskTrackerAddress, String result, String instanceParams, Date modifyTime);
@Transactional
@Modifying
@CanIgnoreReturnValue
@Query(value = "update instance_info set status = ?2, running_times = ?3, actual_trigger_time = ?4, task_tracker_address = ?5, instance_params = ?6, gmt_modified = ?7 where instance_id = ?1", nativeQuery = true)
@Query(value = "update InstanceInfoDO set status = ?2, runningTimes = ?3, actualTriggerTime = ?4, taskTrackerAddress = ?5, instanceParams = ?6, gmtModified = ?7 where instanceId = ?1")
int update4TriggerSucceed(long instanceId, int status, long runningTimes, long actualTriggerTime, String taskTrackerAddress, String instanceParams, Date modifyTime);
@Modifying
@Transactional
@CanIgnoreReturnValue
@Query(value = "update instance_info set status = ?2, running_times = ?3, gmt_modified = ?4 where instance_id = ?1", nativeQuery = true)
@Query(value = "update InstanceInfoDO set status = ?2, runningTimes = ?3, gmtModified = ?4 where instanceId = ?1")
int update4FrequentJob(long instanceId, int status, long runningTimes, Date modifyTime);
// 状态检查三兄弟对应 WAITING_DISPATCH WAITING_WORKER_RECEIVE RUNNING 三阶段
@ -64,13 +64,13 @@ public interface InstanceInfoRepository extends JpaRepository<InstanceInfoDO, Lo
long countByAppIdAndStatus(long appId, int status);
long countByAppIdAndStatusAndGmtCreateAfter(long appId, int status, Date time);
@Query(value = "select job_id from instance_info where job_id in ?1 and status in ?2", nativeQuery = true)
@Query(value = "select jobId from InstanceInfoDO where jobId in ?1 and status in ?2")
List<Long> findByJobIdInAndStatusIn(List<Long> jobIds, List<Integer> status);
// 删除历史数据JPA自带的删除居然是根据ID循环删2000条数据删了几秒也太拉垮了吧...
// 结果只能用 int 接收
@Modifying
@Transactional
@Query(value = "delete from instance_info where gmt_modified < ?1", nativeQuery = true)
@Query(value = "delete from InstanceInfoDO where gmtModified < ?1")
int deleteAllByGmtModifiedBefore(Date time);
}

View File

@ -20,7 +20,7 @@ public interface JobInfoRepository extends JpaRepository<JobInfoDO, Long> {
// 调度专用
List<JobInfoDO> findByAppIdInAndStatusAndTimeExpressionTypeAndNextTriggerTimeLessThanEqual(List<Long> appIds, int status, int timeExpressionType, long time);
@Query(value = "select id from job_info where app_id in ?1 and status = ?2 and time_expression_type in ?3", nativeQuery = true)
@Query(value = "select id from JobInfoDO where appId in ?1 and status = ?2 and timeExpressionType in ?3")
List<Long> findByAppIdInAndStatusAndTimeExpressionTypeIn(List<Long> appIds, int status, List<Integer> timeTypes);
Page<JobInfoDO> findByAppIdAndStatusNot(Long appId, int status, Pageable pageable);

View File

@ -17,7 +17,7 @@ public interface OmsLockRepository extends JpaRepository<OmsLockDO, Long> {
@Modifying
@Transactional
@Query(value = "delete from oms_lock where lock_name = ?1", nativeQuery = true)
@Query(value = "delete from OmsLockDO where lockName = ?1")
int deleteByLockName(String lockName);
OmsLockDO findByLockName(String lockName);

View File

@ -24,7 +24,7 @@ public interface WorkflowInstanceInfoRepository extends JpaRepository<WorkflowIn
// 结果只能用 int 接收
@Modifying
@Transactional
@Query(value = "delete from workflow_instance_info where gmt_modified < ?1", nativeQuery = true)
@Query(value = "delete from WorkflowInstanceInfoDO where gmtModified < ?1")
int deleteAllByGmtModifiedBefore(Date time);
int countByWorkflowIdAndStatusIn(Long workflowId, List<Integer> status);

View File

@ -15,4 +15,6 @@ spring.servlet.multipart.max-request-size=209715200
# akka ActorSystem 服务端口
oms.akka.port=10086
# 报警服务 bean名称
oms.alarm.bean.names=omsDefaultMailAlarmService
oms.alarm.bean.names=omsDefaultMailAlarmService
# 表前缀
#oms.table-prefix=pj_

View File

@ -14,6 +14,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
@ -41,6 +42,7 @@ public class RepositoryTest {
* 需要证明批量写入失败后会回滚
*/
@Test
@Transactional
public void testBatchLock() {
List<OmsLockDO> locks = Lists.newArrayList();
@ -59,6 +61,7 @@ public class RepositoryTest {
}
@Test
@Transactional
public void testUpdate() {
InstanceInfoDO updateEntity = new InstanceInfoDO();
updateEntity.setId(22L);
@ -68,6 +71,7 @@ public class RepositoryTest {
}
@Test
@Transactional
public void testExecuteLogUpdate() {
instanceInfoRepository.update4TriggerFailed(1586310414570L, 2, 100, System.currentTimeMillis(), System.currentTimeMillis(), "192.168.1.1", "NULL", "", new Date());
instanceInfoRepository.update4FrequentJob(1586310419650L, 2, 200, new Date());

View File

@ -33,4 +33,6 @@ oms.log.retention.local=0
oms.log.retention.remote=0
oms.container.retention.local=0
oms.container.retention.remote=0
oms.instanceinfo.retention=0;
oms.instanceinfo.retention=0;
# 表前缀
#oms.table-prefix=pj_