首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

怎么自动备份删除的对象(3)

2012-10-25 
如何自动备份删除的对象(3)到目前为止我们有了一套从Object自动生成MapString,Object的工具,下面要作的

如何自动备份删除的对象(3)

到目前为止我们有了一套从Object自动生成Map<String,Object>的工具,下面要作的就是把这个Map中的信息给持久化了,依照不同的持久化方式和后继对删除对象的查询方式,这又有着不同的solution。比如持久化到文件系统和数据库,显然要用不同的方式。

目前这个系统采用的是数据库,OR-Mapping用的是Toplink。对于删除的数据,在前台有能够查询的界面,可供业务人员查询。针对这样的需求,需要解决以下的几个问题。

首先,在何处获得被删除的对象?BaseDao.deleteObject(Object obj)似乎是一个不错的入口,可惜的是,Toplink对于private owner的对象会自动删除,而service developer不会向下面这样去删除一个对象

?

//如果想在BaseDao.deleteObject(obj)中捕获删除对象,//那就要求service这样去删除一个具有private owner 属性的Orderfor (Item item: order.getItems()){    getBaseDao().deleteObject(item);}getBaseDao().deleteObject(order);

?

所以,为了透明地得到所有Toplink实际删除了的对象,要在每个UnitOfWork生成时要注册一个Toplink的SessionEventListener

?

import java.util.Date;import java.util.Enumeration;import java.util.Map;import oracle.toplink.internal.helper.IdentityHashtable;import oracle.toplink.publicinterface.UnitOfWork;import oracle.toplink.sessions.SessionEvent;import oracle.toplink.sessions.SessionEventAdapter;public class RecordListener extends SessionEventAdapter {    protected static final FWIIntegrator integrator = FWIntegratorFactory.getIntegrator();    @Override    public void postCommitUnitOfWork(SessionEvent event) {        try {            UnitOfWork unitOfWork = (UnitOfWork) event.getSession();            UnitOfWork uow4DeletionRecord = null;            IdentityHashtable objectsDeletedDuringCommit = unitOfWork.getObjectsDeletedDuringCommit();            for (Enumeration<?> e = objectsDeletedDuringCommit.keys(); e.hasMoreElements();) {                Object key = e.nextElement();                RecordUtils recordUtils = RecordUtils.instance();                Map<String, Object> content = recordUtils.toContent(key);                if (content != null) {                    // since deleted objects are detected in post commit callback                    // we have to acquire another UOW to write DeletionRecord                    if (uow4DeletionRecord == null) {                        uow4DeletionRecord = ParamUtils.getDataSource().getSession().acquireUnitOfWork();                    }                    DeletionRecord deleteRecord = recordUtils.toDeleteRecord(content);                    deleteRecord.setOperatingTime(new Date());                    uow4DeletionRecord.assignSequenceNumber(deleteRecord);                    uow4DeletionRecord.registerNewObject(deleteRecord);                }            }            if (uow4DeletionRecord != null) {                uow4DeletionRecord.commit();                uow4DeletionRecord.release();            }        } catch (Exception e) {           // You may log it by yourself        }    }}
?
    private void initSessionAndUnitOfWork(ServerSession serverSession) {        clientSession = serverSession.acquireClientSession();        uw = clientSession.acquireUnitOfWork();        addListenerToUnitOfWork(uw);    }    private void addListenerToUnitOfWork(UnitOfWork uw) {        uw.getEventManager().addListener(new RecordListener());    }
?

?? 这个Listener的作用时间是postCommitUnitOfWork,目的是保证UnitOfWork.getObjectsDeletedDuringCommit()有值。当然,由于原有的UnitOfWork已经commit了,所以得新起一个UnitOfWork来写这些DeletionRecord对象

?

? DeletionRecord没有什么特别的东西,它包含一些查询所用到的warehouse,owner,location之类的业务字段(这些字段在数据库中会作索引,同时含有一个content字段,其中存储的是从那个Map转换过来的XML

public class DeletionRecord extends OidEnabledComponent {    private static interface DeletionRecordSetterCallback {        void setValue(DeletionRecord obj, Object value);    }    public static enum FieldType {        CLASS_NAME(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setClassName((String) value);            }        }),        WAREHOUSE_ID(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setWarehouseId((String) value);            }        }), OWNER_ID(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setOwnerId((String) value);            }        }), LOCATION_ID(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setLocationId((String) value);            }        }), ITEM_NO(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setItemNo((String) value);            }        }), ITEM_DESCRIPTION(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setItemDescription((String) value);            }        }), BIZ_TYPE(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setBizType((Long) value);            }        }), ASN_NO(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setAsnNo((String) value);            }        }), RECEIVE_DATE(new DeletionRecordSetterCallback() {            public void setValue(DeletionRecord obj, Object value) {                obj.setReceiveDate((Date) value);            }        });        private DeletionRecordSetterCallback setterCallback;        FieldType(DeletionRecordSetterCallback setterCallback) {            this.setterCallback = setterCallback;        };        public void setValue(DeletionRecord obj, Object value) {            this.setterCallback.setValue(obj, value);        }    }    private String className;    private String warehouseId;    private String ownerId;    private String locationId;    private String itemNo;    private String itemDescription;    private Long bizType;    private String asnNo;    private Date receiveDate;    private String operatorId;    private Date operatingTime;    private String content;    public String getClassName() {        return className;    }    public void setClassName(String className) {        this.className = className;    }    public String getWarehouseId() {        return warehouseId;    }    public void setWarehouseId(String warehouseId) {        this.warehouseId = warehouseId;    }    public String getOwnerId() {        return ownerId;    }    public void setOwnerId(String ownerId) {        this.ownerId = ownerId;    }    public String getLocationId() {        return locationId;    }    public void setLocationId(String locationId) {        this.locationId = locationId;    }    public String getItemNo() {        return itemNo;    }    public void setItemNo(String id) {        this.itemNo = id;    }    public String getItemDescription() {        return itemDescription;    }    public void setItemDescription(String name) {        this.itemDescription = name;    }    public Long getBizType() {        return bizType;    }    public void setBizType(Long bizType) {        this.bizType = bizType;    }    public String getAsnNo() {        return asnNo;    }    public void setAsnNo(String asnNo) {        this.asnNo = asnNo;    }    public Date getReceiveDate() {        return receiveDate;    }    public void setReceiveDate(Date receiveDate) {        this.receiveDate = receiveDate;    }    public String getOperatorId() {        return operatorId;    }    public void setOperatorId(String operatorId) {        this.operatorId = operatorId;    }    public Date getOperatingTime() {        return operatingTime;    }    public void setOperatingTime(Date operatingTime) {        this.operatingTime = operatingTime;    }    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }}
?

?? 需要注意的是,这个转换出来的deletionRecord不是在原有的UnitOfWork中写入的,所以那一段专门去catch了Exception。这是基于以下想法:即使自动备份失败了,也不应该影响正常的删除逻辑。如果认为自动备份失败就不能继续往下作的话,这个catch是要去掉的。

?

?? 至此,一个自动备份删除对象的简易框架就搭好了。总结一下,核心思想包括以下几点

? 1)通过Annotation和interface,使得一个对象能够在被删除时指出自己的哪些信息需要被记录

? 2)通过SessionEventListen得到所有被删除的对象,保持对使用者的透明

? 3)把结果信息分为两部分,需要查询的用单独的字段记录做索引,其余信息用一个单层的XML保存。

?

?

?

再深入考虑的话,这个框架可以有以下的改进:

一是用XML指定要删除的对象和属性,作到对原始文件的完全无侵入;二是持久化到数据库外其他的媒介如文件系统、网络等,这就可以抽象出一个Appender interface,再实现FileAppender, DBApplender等对象;最后如果性能有需要,可以把持久化被删除对象和删除业务对象的逻辑做成异步的,这样删除N个对象后才持久化一次删除动作,能够减少业务逻辑的延迟。

?

?

?

热点排行