【问题标题】:Eclipselink entity mappings cacheEclipselink 实体映射缓存
【发布时间】:2014-02-06 01:59:11
【问题描述】:

我正在为我的项目使用 EclipseLink。 我扩展了 XMLMetadataSource(以提供自定义类加载器),因为我坚持的实体是运行时创建的。它工作正常。

我在关注时收到“未知实体类型”。

  • 创建实体

  • 创建映射

  • 创建实体管理器工厂,提供自定义类加载器

  • 创建实体管理器并持久化。 - 它工作正常。

  • 现在删除实体,并从类加载器中删除

  • 创建相同的实体,

  • 再次创建映射(当然看起来一样)

  • 尝试使用新属性(新类加载器、映射文件)刷新实体管理器工厂

  • 尝试坚持 - 抱怨“未知类型”

任何想法,如果 EL 缓存 XML 映射。 我试图再次重新创建工厂,但同样的错误。

我尝试了 MySQL 和 Derby。使用 'drop-and-create-tables' 和 'create-or-extend-tables' 。

同样的结果。

【问题讨论】:

    标签: jpa orm mapping eclipselink entitymanager


    【解决方案1】:

    我用 Eclipse 链接提交了一个错误。

    https://bugs.eclipse.org/bugs/show_bug.cgi?id=426310

    【讨论】:

      【解决方案2】:

      这不是 EL 中所说的错误。但问题在于 EL“没有构建或重新创建 'class-->class_descriptor' 映射(一个包含每个实体的类对象和实体描述的内部映射)。我偶然发现了这个。对于那些感兴趣的人,这里是一个示例代码这可能会有所帮助。

      public class Test1 {
      public Test1(String pu, Map<String, Object> props ) {
          pu_name = pu;        
          properties = new HashMap<String, Object> ();
          properties.putAll(props);
          loader = new MyClassLoader();
      }
      public void initialization( ) {                
          mms = new WAMetadataSource();
          properties.put(PersistenceUnitProperties.METADATA_SOURCE, mms);
          properties.put(PersistenceUnitProperties.CLASSLOADER,loader);
      
          if(emf == null || !emf.isOpen()) {
              synchronized(Test1.class) {
                  if (emf == null || !emf.isOpen()) {
                      emf = Persistence.createEntityManagerFactory(pu_name, properties);                    
                  } 
              }            
          } else {
                      JpaHelper.getEntityManagerFactory(emf).refreshMetadata(properties);        
          }
          System.out.println("======> refreshed. emf.hascode : " + emf.hashCode() + ", loader.h : " + loader.hashCode());
      }    public EntityManager getEntityManager(Map<String, Object> props) {
          if (em == null) {
              em = emf.createEntityManager(props);
          }
      
          return em;
      } public void persist(Object obj) {
          try {
              getEntityManager(properties);
              System.out.println("===> em.hascode =" + em.hashCode() +", " +  JpaHelper.getEntityManager(em).getProperties().get(PersistenceUnitProperties.CLASSLOADER).hashCode() );
              em.clear();
              em.getTransaction().begin();
              em.persist(obj);
              em.getTransaction().commit();
          } finally {
          }    
      }public Object getRuntimeEntityObject(int ii) {
              Object obj=null;
              Class clazz = loader.loadClass("com.xxx.sample.entity.runtime.User");
              if(ii == 1){
                  obj = clazz.getConstructor(String.class).newInstance("Jai Ramjiki-1");                
              } else {
                  obj = clazz.getConstructor(String.class).newInstance("Jai Ramjiki-2");
              }
              obj = clazz.cast(obj);
              return obj;
      }public static void main(String[] args) {
          Map<String, Object> props = new HashMap<String, Object>();
          props.put(PersistenceUnitProperties.JDBC_DRIVER, "com.mysql.jdbc.Driver");
          props.put(PersistenceUnitProperties.JDBC_URL, "jdbc:mysql://localhost:3306/test" );
          props.put(PersistenceUnitProperties.JDBC_USER, "root");
          props.put(PersistenceUnitProperties.JDBC_PASSWORD, "root");
          props.put(PersistenceUnitProperties.DDL_GENERATION, "create-or-extend-tables");
      
          Test1 t1 = new Test1("mysql", props);         
          Object obj1 = t1.getRuntimeEntityObject(1);     
          System.out.println(" ****> obj1 = " + obj1 + ", classloader hashcode : " + obj1.getClass().getClassLoader().hashCode() );
          t1.initialization();
          t1.persist(obj1);
          System.out.println("Class 1 : " + obj1.getClass().hashCode() + ", obj1 : " + obj1);
          t1.close();
      
          // now drop the previous class loader and rerun same. 
      
          Test1 t2 = new Test1("mysql", props);
          Object obj2 = t2.getRuntimeEntityObject(2);
          System.out.println(" ****> obj2 = " + obj2 + ", classloader hashcode : " + obj2.getClass().getClassLoader().hashCode() );
          t2.initialization();
          t2.persist(obj2);
          t2.close();
      
      
          Object obj3 = t1.getRuntimeEntityObject(1);
          System.out.println(" ****> obj3 = " + obj3 + ", classloader hashcode : " + obj3.getClass().getClassLoader().hashCode() );
          t1.persist(obj3);
      
      
      }
      

      并扩展 XMLMetadatSource

       @Override
      public XMLEntityMappings getEntityMappings(Map<String, Object> properties, ClassLoader classLoader, SessionLog log) {
          properties.put(PersistenceUnitProperties.METADATA_SOURCE_XML_FILE, "eclipselink-orm-user.xml");
          properties.put(PersistenceUnitProperties.VALIDATOR_FACTORY, null);
          return super.getEntityMappings(properties, classLoader, log);
      }
      

      并在扩展 ClassLoader 的 CustomClassloader 中使用 javassist 创建一个运行时类

          public void createRuntimeClass(String className) throws Exception {        
          CtClass bclass = pool.makeClass(className);
          bclass.addConstructor(CtNewConstructor.defaultConstructor(bclass));        
          Map<String, String> fields = new HashMap<String, String>(); 
          addFields(fields); 
          int noOfFields = fields.size(); 
          CtClass[] fclasses = new CtClass[noOfFields];
      
          int ii=0;
          for (Entry<String, String> field : fields.entrySet()) {
              String fieldName = field.getKey();
              String fieldType = field.getValue();
              //.. code to add field
              bclass.addField(bfield);            
              //add getter method.
              // add getter and setters
          }        
          CtConstructor userConstructor = CtNewConstructor.make(constructorSource, bclass);
          bclass.addConstructor(userConstructor);
          byte bytes [] = bclass.toBytecode();        
          Class cls = bclass.toClass(this, null);
          loadedClasses.put(className, cls);
          loadClassBytes.put(className, bytes);    
      }
      

      并覆盖 loadClass 和 getResourceAsStream 方法。

      public Class<?> loadClass(String name) throws ClassNotFoundException {return clazz = loadedClasses.get(name);}
      
      public InputStream getResourceAsStream(String name) {return loadClassBytes.get(className);}
      

      希望对你有帮助

      EL 提供了一种方法来清除当前项目的缓存,并设置描述符映射。但他们都没有工作。不确定这是预期的行为,或者他们错误地暴露了该 API。

      戈皮

      【讨论】:

        【解决方案3】:

        是的,持久性单元加载只进行一次。如果您使用 XMLMetadataSource 更改映射,则必须告诉工厂使用 EMF 上的 refreshMetadata() 刷新其映射,如下所述: http://wiki.eclipse.org/EclipseLink/DesignDocs/340192#Refresh

        之后,获得的下一个 EntityManager 将使用新的映射,而现有的 EM 仍将使用旧的映射。

        【讨论】:

        • 感谢您的回复。事实上我正在刷新
        • 感谢您的回复。事实上,我正在使用以下方法进行刷新。 MyXMLMetadataSourceInstance.setClassLoader(myclassloader); props.put(PersistenceUnitProperties.METADATA_SOURCE, MyXMLMetadataSourceInstance); JpaHelper.getEntityManagerFactory(emfactory).refreshMetadata(props);
        • 我注意到,'org.eclipse.persistence.internal.sessions.AbstractSession' /** PERF: 项目中的缓存描述符中的描述符。 */ 瞬态保护 Map 描述符;第二次无法返回类描述符对象(删除运行时创建的实体,再次使用相同的名称重新创建)我怀疑它已被缓存,刷新时它不会被清除。无论如何,如何确保清除所有缓存。我简要地查看了实现 ProjectCache 接口,但看起来创建 Project 对象是一项艰巨的任务。
        • 您是否尝试使用不同的类加载器?用于持久性单元的类加载器与 METADATA_SOURCE 无关,而是用于创建工厂的原始类加载器。
        • 我使用了一个自定义类加载器,它了解运行时生成的类。和 props.put(PersistenceUnitProperties.CLASSLOADER, mycl);
        猜你喜欢
        • 2011-08-19
        • 2012-05-25
        • 1970-01-01
        • 2011-07-13
        • 1970-01-01
        • 2017-12-17
        • 1970-01-01
        • 2013-12-29
        • 1970-01-01
        相关资源
        最近更新 更多