【问题标题】:Spring Data JPA + Hibernate : Inject Catalog/Schema at runtime in to JPA EntitiesSpring Data JPA + Hibernate:在运行时将目录/模式注入 JPA 实体
【发布时间】:2014-06-25 08:12:53
【问题描述】:

我们有一个场景,在目录/模式组合中,某个包内的实体类与所有其他包中使用的默认实体类不同。我正在尝试使用 PersistenceUnitPostProcessors 在运行时使用 javaassist 回调在 @Table 注释上设置目录和架构,如下所示。

问题: javaassist 注释上添加的成员值不会反映到与其关联的实际类中。请帮我找出错误的代码行;或者如果有其他方法可以实现这一点,非常高兴知道。

注意:我不想为每个目录/模式组合创建单独的 EntityManagerFactory - 在我们的案例中它并不是真正需要的,因为数据源是相同的。

spring 上下文中的相关内容:

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
   <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>

<tx:annotation-driven />     

<bean name="jpaDialect" class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" /> 
 <property name="persistenceUnitName" value="mainUnit" /> 
   <property name="packagesToScan" value="com.mycompany.lob.domain" />       
   <property name="jpaVendorAdapter">
     <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
   </property>
   <property name="persistenceUnitPostProcessors">
     <list>
        <bean class="com.mycompany.lob.jpa.CustomPersistenceUnitPostProcessor"/>
     </list>
  </property>
   <property name="jpaProperties">
     <props>
          <prop key="hibernate.dialect">org.hibernate.dialect.SqlmxDialect</prop>
          <prop key="hibernate.show_sql">true</prop>
          <prop key="hibernate.format_sql">true</prop>
          <prop key="hibernate.jdbc.batch_size">100</prop>
          <prop key="hibernate.order_inserts">true</prop>
          <prop key="hibernate.cache.use_second_level_cache">true</prop>
          <prop key="hibernate.connection.autocommit">true</prop>
          <prop key="hibernate.default_schema">DEFAULT_SCHEMA</prop>
          <prop key="hibernate.default_catalog">DEFAULT_CATALOG</prop>
     </props>
   </property>
</bean> 

PersistenceUnitPostProcessors 回调:

public class CustomPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
@Value("${user.schema}")
private String userSchema;
@Value("${user.catalog}")
private String userCatalog;
private static final Logger LOGGER = LoggerFactory.getLogger(CustomPersistenceUnitPostProcessor.class);
@SuppressWarnings("unchecked")
@Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
    LOGGER.info("MutablePersistenceUnitInfo : {} ",pui);
    List<String> jpadomains = pui.getManagedClassNames();
    for (Iterator<?> iterator = jpadomains.iterator(); iterator.hasNext();) {
        String clazzName = (String) iterator.next();
        if(clazzName.startsWith("com.mycompany.lob.domain.user")){
            try {
            //modify annotation attributes using JavaAssist
            ClassPool pool = ClassPool.getDefault();
            CtClass ctClass = pool.get(clazzName);
            ClassFile classFile = ctClass.getClassFile();
            ConstPool constPool = classFile.getConstPool();
             AnnotationsAttribute annotationsAttribute  = (AnnotationsAttribute)classFile.getAttribute(AnnotationsAttribute.visibleTag);
             if(annotationsAttribute!=null){
             //Get hold of @Table annotation
                 Annotation tableAnnotation = annotationsAttribute.getAnnotation("javax.persistence.Table");
                 if(tableAnnotation!=null){
                     tableAnnotation.addMemberValue("catalog", new StringMemberValue(userCatalog, constPool));
                     tableAnnotation.addMemberValue("schema", new StringMemberValue(userSchema, constPool));
                     annotationsAttribute.addAnnotation(tableAnnotation);
                     LOGGER.debug("Schema-Table : {} - {} ",  ((StringMemberValue)tableAnnotation.getMemberValue("schema")).getValue(), 
                                                        ((StringMemberValue)tableAnnotation.getMemberValue("name")).getValue() );
                     //write the file back
                     ctClass.writeFile();
                 }

             }
            } catch (Exception e) {
                LOGGER.error("Schema/Catalog could not be altered for {} ",clazzName);
            }
        }
    }

 }

}   

【问题讨论】:

  • 这永远不会起作用,类已经被休眠加载和扫描。之后更改表值将不起作用,因为映射元数据已经生成。包括和orm.xml 并将其外部化。在LocalContainerEntityManagerFactoryBean 上设置MappingResources 属性以加载外部文件以进行其他映射/覆盖。
  • @M. Deinum - 如果我将MappingResources 用于具有不同目录/模式组合的实体,则不能使用弹簧属性占位符来注入特定于环境的值。 另一个观察结果:当我用ctClass.toClass() 替换ctClass.writeFile() 时,注释属性更改开始对原始类产生影响,至少来自jUnit - 不确定它在部署到应用服务器时会如何表现。

标签: spring hibernate jpa runtime schema


【解决方案1】:

简单的答案: 19. Multitenancy

复杂的目录映射: Hibernate v5 中的interface PhysicalNamingStrategy 很有帮助。

public interface PhysicalNamingStrategy {
    public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment);
    public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment);
    ....
}

检查Hibernate 5 User Guidehow to config it中的Example 2. Example PhysicalNamingStrategy implementation

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-22
    • 2014-09-22
    • 2016-10-10
    • 2019-07-20
    • 2016-06-26
    • 2016-10-15
    • 1970-01-01
    • 2017-07-17
    相关资源
    最近更新 更多