我有足够大且已经在工作的项目,不是由程序员写的,而是由科学家编写的。该程序将大量数据保存在一个巨大的对象树中。几乎所有涉及的类都是可变的甚至更多 - 它们倾向于改变几乎所有方法中的其他对象的状态,甚至是getter和setter。这个对象树通过java序列化存储到磁盘。
我的任务是从序列化迁移到数据库,以减少内存消耗。手动重构这些可变的,在某些未知的时间点互相改变是完全地狱,特别是对我来说 - 不知道主题领域。
此类案例是否有任何方法,做法或重构模式?
答案 0 :(得分:1)
我认为您已在主题栏中回答了您的问题。使用JPA或带有Annotations的Hibernate,您可以使用现有的对象模型并将每个对象类视为自己的表。不要担心开始时的约束。
在每个类中,添加一个id属性,以便可以存储它,并实现equals
和hashCode
。 (所以你必须弄清楚是什么让一个物体等于另一个物体)。这有助于避免在数据库中创建重复项。
您需要编写代码来保留现有记录。也许访客模式在这里很合适。对于每个域对象,您添加一个方法,该方法接受访问者并调用它来持久保存该对象。
public DomainObject {
public DomainObject() {}
private int id; public int getId() { return id; } public void setId(int id) { this.id = id; }
private OtherObject myref;
// properties for 'myref' and other existing public fields may need to be added
void visit(IVisitor iv) {
// traverse object tree to hit leafs first
myref.visit(iv);
// pass to other referenced objects too.
iv.visit(this);
}
public boolean equals(Object alt) { return alt.id == id; }
public int hashCode() { return id.hashCode(); }
}
public interface IVisitor {
public void visit(Object o);
public void visit(DomainObject do);
}
public class PersistVisitor implements IVisitor {
// Your favorite injection annotation, perhaps, or populate through constructor
EntityManager em;
public void PersistVisitor(EntityManager em) { this.em = em; }
public void visit(Object o) {
em.persist(o);
}
public void visit(DomainObject do) {
// anything you need to do specifically for the DomainObject type
visit((Object)o);
}
}
在最初持久化记录之后,当您下次从Session或EntityManager加载根对象时,Hibernate将负责加载所有引用的实例。
随着时间的推移,您可以将业务逻辑移出模型类,但您不必这样做。 Hibernate将提交对对象模型中任何实例所做的任何更改,例如现有代码所做的更改。
(或者我猜你可以挂钩对象树的反序列化,以便在反序列化时保留或查找对象。我会把它作为另一个用户的练习。)