我们现在开发的系统很多东西是定制的,比如表单、流程等,这样系统的迁移出现了问题,比如在公司为用户定制了一些功能,拿到用户那去的时候,就需要将定制的数据也拷贝过去,由于定制的信息比较杂,既有数据库表记录,也有文件,致使迁移数据经常发生问题,不是丢数据了,就是数据重复,导致定制的功能运行不起来。
所以我就考虑为系统做一个针对定制的数据能够导入导出的程序,我想我们要操作的数据主要有两类,物理表记录和文件,其实很多系统的数据都是这些东西,所以我就想开发的这套程序不要仅能完成现在的需求,应该是灵活的、可扩展的,可以针对这一类的需求都能完成。
经过仔细考虑和寻找可用的资源,我终于把这套程序作出来了,其中表数据操作我使用的是dbunit,感觉比较好用,而且支持很多数据库,其实dbunit不是干这个用的,使用来测试数据库程序操作的,不过干这个用更爽。
现在导入导出我们系统的定制数据已经没有问题了,对于其他一些简单的表数据或文件备份也没有问题,如果将来出现更复杂的需求,或出现新的备份对象,我觉也应该可以扩展完成。
下面我说一下我的实现思路。
这套程序目前支持两大类备份源:数据库的表记录、文件,文件又分为Properties文件和xml文件。
考虑实现思路是,将需要备份或恢复的数据源按指定的格式列成一个“清单“(定义清单格式),程序解析清单(backuplistparser), 解析的过程就是将需要备份的内容细化成无数的备份源(backupsource),形成集合,在解析过程中有可能调用每个备份源的过滤器(filter)或者备份源之间的关联公式(Relationship)。
解析完成后,对所有的备份源进行循环,每个备份源将自己传给相应的备份工作者(bakcupworker),通过回调工作者的backup()方法完成备份, 恢复也是一样,调用工作者的import()方法完成。
下面我对程序清单和主要的类简要说明一下:
备份清单
程序清单是一个xml文件,包含两方面的信息,一是环境参数,比如数据库连接信息、需要备份的数据路径的等;二就是需要备份源的列表,每一个备份源又包含自己的描述信息、过滤条件,和别的备份源的关联条件。
下面是一个例子:
<?xml version="1.0" encoding="gb2312"?>
<backuplist>
//环境信息
<context>
//系统文件的路径,
比如C:\WebSphere\AppServer\installedApps\lc-ecp\v3log.ear\v3log.war\eaiPath
<sysfileroot>I:/eaipath</sysfileroot>
//存放导出数据的路径
<backupfileroot>c:/temp</backupfileroot>
//数据库连接信息,目前只支持db2,用的是jcc连接
<servername>lc-ecp</servername>
<databasename>v3ecpdb</databasename>
<user>db2admin</user>
<password>ourecp</password>
</context>
//备份源列表
//数据库表processtype
<backupsource id="processtype" type="table" tablename="WFPROCESSTYPE">
//过滤器,值用‘,’分割,仅备份字段id值等于P1119505745079或P1115713181485
//可以不设置过滤器
<filter>
<property name="ID" value="P1119505745079,P1115713181485"/>
</filter>
//关联的备份源
<relationships>
//关联的备份源wfproperty
<relationship id="wfproperty">
<relation>one-to-many</relation>
//关联的条件是表processtype字段id的值和wfproperty的字段objid的值相等
<relationdefine><![CDATA[ID=OBJID]]></relationdefine>
</relationship>
//关联的备份源wflocaloperate,是文件备份源
<relationship id="wflocaloperate">
<relation>one-to-one</relation>
//关联的条件是wflocaloperate备份源的文件名包含表processtype字段id值
<relationdefine><![CDATA[ID=include]]></relationdefine>
</relationship>
//关联的备份源wflocaloperate,是xml文件备份源
<relationship id="process">
<relation>one-to-meny</relation>
//关联的条件是wflocaloperate备份源的xml文件的process节点的参数type的值等于表processtype字段id值
<relationdefine filterclass=""><![CDATA[ID=nodeattr:process.type]]></relationdefine>
</relationship>
</relationships>
</backupsource>
<backupsource id="wfproperty" type="table" tablename="WFPROPERTY">
</backupsource>
<backupsource id="wflocaloperate" type="file" path="/wflocaloperate/" filename="">
</backupsource>
<backupsource id="process" type="xmlfile" path="/wf/process/" filename="">
<relationships>
<relationship id="wffield">
<relation>one-to-one</relation>
<relationdefine><![CDATA[nodeattr:process.id=nodeattr:process.id]]></relationdefine>
</relationship>
</relationships>
</backupsource>
</backuplist>
SysBackupExport
数据导出入口程序,传入清单文件,调用BackupListXmlParse进行解析,形成备份源的集合,然后根据导出方式请求,进行数据导出。
有五种到处方式:
Ø exportAll,全部数据导出,循环导出清单所有备份源,会执行每一个备份源filter,如果有的话
Ø exportAllIgnoreFilter,循环导出清单所有备份源,忽略filter,真正的全部导出
Ø ExportById 根据id导出某一备份源,会执行此备份源的filter,并且导出其关联备份源
Ø ExportByIdIgnoreFilter 根据id导出某一备份源,忽略此备份源的filter,并且导出其关联备份源
Ø ExportByIdIgnoreRelation 仅根据id导出某一备份源,会执行此备份源的filter,不导出关联备份源
Ø ExportByIdIgnoreFilterAndRelation仅根据id导出某一备份源,忽略此备份源的filter,不导出关联备份源
SysBackupImport
数据导入入口程序,传入清单文件调用BackupListXmlParse进行解析,形成备份源的集合,循环备份源导入,如果数据表记录重复,将会更新,如果文件重复,将会覆盖
BackupListXmlParse
解析备份清单,设置环境参数,循环设置每一个备份源,设置备份源的filter和Relationship,形成备份源的集合
backupsource
备份源对象,这里定义了一接口.
public interface BackupSource {
public void export(); //数据备份,导出,由BackupWorker完成
public void bImport(); //数据导入,由BackupWorker完成
public Map associate(Map sources, Map targetSources); //执行关联定义,获取自己相关联的备份源
public void filter();//执行过滤,由filter完成
public String getId();
public String getType();
public void setId(String string);
public Filter getFilter();
public void setFilter(Filter f);
public Filter createDefaultFilter();
public BackupWorker createDefaultWorker();
public List getRelationships();
public void setRelationships(List list);
}
目前实现有四个:
TableBackupSource 数据库物理表
FileBackupSource 普通文件
PropertiesBackupSource Properties文件
XmlfileBackupSource xml文件
Filter
过滤器,核心方法就是filter()方法,说白了就是为物理表备份源产生where条件,为文件备份源过滤那些文件允许备份。
定义了一个抽象类,有四个实现,分别针对不同的数据备份源:
DBTableQueryFilter
DefaultFileFilter
PropertiesFileFilter
XmlFileFilter
BackupWorker
完成真正的导入导出工作,定义了一个接口,核心方法就是两个export()和bimport(),
目前有三个实现。
DBQueryBackupWorker
DefaultFileBackupWorker
PropertiesBackupWorker
对于数据库表记录的存取,我没有自己写,感觉太复杂,我用的是开源项目DBUNIT,借用了它可以把表记录生成XML文件,并且还可以把XML文件再插回到物理表的功能.
对于文件的存取,自己写的,无非就是用流的写入写出罢了。就不细说了。
总体感觉,这套程序不大,基本实现了最初的想法,总共也就是十几个类,主要的收获就是按面向对象的思想来进行设计的,锻炼了一回(当然这样设计可能不是最好的,自我感觉尽力思考了,以后有更好的想法再改进)。
不足的地方,备份源之间的关联公式定义,感觉比较幼稚,而且不好扩充,暂时又想不出更好的方式;导入导出的数据最好能打一个包;目前只能支持db2数据库。
目前功能不是很强,应用范围比较窄,感觉应该还可以扩充,或者干点别的任务,比如用定时器定时备份系统的全部数据什么的,暂时就这样吧。