【问题标题】:Cyclic serialisation with Many to Many relationship with Hibernate与Hibernate的多对多关系的循环序列化
【发布时间】:2010-02-08 05:07:27
【问题描述】:

我有一个父母(程序)pojo,与他们的孩子(订阅者)有多对多的关系。

问题是当它序列化一个程序时,它也会序列化程序的订阅者,这涉及到序列化他们的程序,这涉及到序列化他们的订阅者,直到它序列化数据库中的每个程序和订阅者。

ERD 看起来像:程序 订阅者

这意味着返回的 17KB 数据块 (json) 变成了 6.9MB。因此反过来又会浪费时间序列化数据然后返回。

为什么我的父母送孩子回来父母送孩子?我怎样才能阻止这种情况,以便我只获得每个程序的订阅者?我假设我的注释做错了,也许?我想保持多对多关系,但没有这种深度嵌套的数据检索。

(注意:我之前尝试过添加尽可能多的懒惰注释,看看是否有帮助。它没有。也许我也做错了?)

Program.java

@Entity
@Table(name="programs")
public class Program extends Core implements Serializable, Cloneable {
   ...
   @ManyToMany()
   @JoinTable(name="program_subscribers",
         joinColumns={@JoinColumn(name="program_uid")},
         inverseJoinColumns={@JoinColumn(name="subscriber_uid")})
   public Set<Subscriber> getSubscribers() { return subscribers; }
   public void setSubscribers(Set<Subscriber> subscribers) { this.subscribers = subscribers; }

Subscriber.java

@Entity
@Table(name="subscribers")
public class Subscriber extends Core implements Serializable {
   ...
   @ManyToMany(mappedBy="subscribers")
   public Set<Program> getPrograms() { return programs; }
   public void setPrograms(Set<Program> programs) { this.programs = programs; 

}

实施

public Collection<Program> list() {
  return new Programs.findAll();
}

【问题讨论】:

    标签: java hibernate orm jpa


    【解决方案1】:

    您没有提到您用于 JSON 序列化的框架,所以我假设为 JAXB。无论如何,这个想法是以某种方式使Subscriber.getPrograms(..) 瞬态,这样它就不会被序列化。 Hibernate 会处理这些“循环”,但其他的则不会。所以:

    @XmlTransient
    @ManyToMany(..)
    public Set<Program> getPrograms()...
    

    如果您使用其他框架,它可能有不同的注释/配置来指定瞬态字段。就像transient 关键字一样。

    另一种方法是自定义映射器以手动处理循环,但这很乏味。

    【讨论】:

    • 这是一个交给我的项目,我不是 100% 用于 JSON 序列化的东西。我看到对 com.sdicons.json.mapper.JSONMapper.SimpleMapperHelper 的引用。我们有一个方法 public JSONValue toJSON(Object pojo) throws MapperException {}。 (猜猜这是你自己的序列化)
    • 另外,如果我注释 getPrograms() @XmlTransient 这是否意味着我永远无法返回订阅者程序?
    • 是的。另一种是自定义映射器以手动处理循环。
    【解决方案2】:

    1) “你的”序列化是如何工作的。我的意思是它是 JAXB 还是自定义序列化或其他。 2)几乎所有的框架都让你设置序列化的深度。我的意思是你可以在 2 中设置例如深度。 3)我建议你不要序列化有孩子的对象,标记他们(孩子)瞬态,并单独序列化。

    【讨论】:

      【解决方案3】:
      【解决方案4】:

      来自龙目岛图书馆。或者覆盖equals和hashcode。仅在哈希码内部使用唯一字段(例如 id)。

      @EqualsAndHashCode(callSuper = false, of = {"id"})
      

      【讨论】:

        【解决方案5】:

        Bozho 和 ponkin 都在正确的轨道上。我需要停止对数据进行在线序列化,但最大的问题是我无法更改发生序列化的 pojo -> toJSON 类/方法。我还担心在 toJSON() 方法上投入时间,考虑到我在序列化时受到了如此大的性能影响,我希望在获得数据之前而不是之后进行修复。

        另外,由于我列出的多对多双向设计的性质,我总是会遇到这个循环程序/订阅者/程序/...问题。

        解决方案:(至少现在)我删除了 Subscriber.getProgram() 方法并在 ProgramDAO 上创建了一个查找器方法,该方法返回订阅者的程序。

        public List<Program> findBySubscriber(Subscriber subscriber) {
          String hql = "select p " +
             "from Program p " +
             " join p.subscribers s " +
             "where s = :sub"
             ;    
        
          Query q = getSession().createQuery(hql);
          q.setEntity("sub", subscriber);
        
          List<Program> l = q.list();
          return l;
        }
        

        对于任何 CRUD 工作,我认为我只需要遍历 Programs.getSubscribers,或者编写更多 hql 辅助方法。

        【讨论】:

          猜你喜欢
          • 2014-11-13
          • 1970-01-01
          • 2011-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多