对一些需要将数据持久化的小型程序中,传统的关系型数据库显得庞大而不实用,oo数据库有一个学习曲线的问题,而使用xml是一种较好的选择.本文将就设计一个合理的xml持久化的解决方案进行探讨.
使用xml作为持久层解决方案的,它的基本功能要有:
1.对象的crud功能(本例中基本对象是member类).
2.保证线程安全,对桌面程序和web程序都一样适用.
3.有缓存,在存储介质即xml文件突然丢失的情况下还能有效工作.
本例采用了memberservice和memberpersistence两个类来协作完成这些功能.
memberservice是业务层和持久层之间的桥梁,用于对member对象的crud操作,内置一个hashtable来缓存member对象,即使文件突然丢失,缓存中的数据也不会被影响.它内置一个memberpersistence成员来完成与持久介质的交互.
实现添加,删除,更新的三个函数add(),delete(),update()都用lockobj实现了同步,这样就无需担心线程安全问题.其它函数对members成员没有修改,故不需要实现同步.
try{
memberpersistence.add(member);
members.put(member.getid(), member);
return true;
}
catch(xmlfilewriteexception ex){
system.out.println("member:" + member.getid() + " add error!");
return false;
}
|
当memberpersistence添加对象成功后,这个对象才会被添加到members中,这样保证了缓存和实际数据的同步;如果颠倒一下顺序,那末memberpersistence添加对象不成功时,出现xmlfilewriteexception异常,这是还需要在catch中删除刚才添加的对象,这样做人为加大了程序的复杂度,不如上面的做法简单高效.
关于查询函数的做法不明白的请见 http://www.blogjava.net/sitinspring/archive/2007/06/05/122119.html 中形式三.
下面是memberservice类的全部代码:
package com.sitinpsring.service;
import java.util.arraylist;
import java.util.collections;
import java.util.hashtable;
import java.util.iterator;
import java.util.list;
import com.sitinpsring.domain.member;
import com.sitinpsring.domain.memberfilter;
import com.sitinpsring.exception.xmlfilereadexception;
import com.sitinpsring.exception.xmlfilewriteexception;
import com.sitinpsring.persistence.memberpersistence;
public class memberservice {
private static hashtable<string, member> members;
private static memberpersistence memberpersistence;
private static final object lockobj = new object();
static {
try {
memberpersistence = new memberpersistence("member.xml");
members = memberpersistence.loadmemberfromfile();
} catch (xmlfilereadexception ex) {
system.out.println("can’t read the file:member.xml");
}catch (xmlfilewriteexception ex) {
system.out.println("can’t write to the file:member.xml");
}
}
public memberservice() {
}
public boolean hasmember(string id) {
return members.containskey(id);
}
public boolean hasmember(member member) {
return hasmember(member.getid());
}
public boolean add(member member) {
if (hasmember(member)) {
system.out.println("member:" + member.getid() + " has been exist!");
return false;
} else {
synchronized (lockobj) {
try{
memberpersistence.add(member);
members.put(member.getid(), member);
return true;
}
catch(xmlfilewriteexception ex){
system.out.println("member:" + member.getid() + " add error!");
return false;
}
}
}
}
public boolean update(member member) {
if (hasmember(member)) {
synchronized (lockobj) {
try{
memberpersistence.update(member);
member oldmember = members.get(member.getid());
oldmember.setname(member.getname());
oldmember.setage(member.getage());
return true;
}
catch(xmlfilewriteexception ex){
system.out.println("member:" + member.getid() + " upate error!");
return false;
}
}
} else {
system.out.println("member:" + member.getid()
+ " can’t been found!");
return false;
}
}
public boolean saveorupdate(member member) {
if (hasmember(member)) {
return update(member);
} else {
return add(member);
}
}
public boolean delete(member member) {
if (hasmember(member)) {
synchronized (lockobj) {
try{
memberpersistence.delete(member.getid());
members.remove(member.getid());
return true;
}catch(xmlfilewriteexception ex){
system.out.println("member:" + member.getid() + " delete error!");
return false;
}
}
} else {
system.out.println("member:" + member.getid()
+ " can’t been found!");
return false;
}
}
@suppresswarnings("unchecked")
public list<member> search(memberfilter memberfilter) {
arraylist<member> retval = new arraylist<member>();
for (iterator it = members.keyset().iterator(); it.hasnext();) {
string key = (string) it.next();
member member = members.get(key);
if (memberfilter.accept(member)) {
retval.add(member);
}
}
collections.sort(retval);
return retval;
}
public list<member> getall() {
memberfilter filter = new memberfilter() {
public boolean accept(member member) {
return true;
}
};
return search(filter);
}
public member getmemberbyid(string id) {
for (iterator it = members.keyset().iterator(); it.hasnext();) {
string key = (string) it.next();
member member = members.get(key);
if (member.getid().equals(id)) {
return member;
}
}
return null;
}
}
|
memberpersistence类是与xml文件打交道的类,通过它,数据才能真正存入持久介质-xml文件.它的函数都很好理解.这些函数工作时实际只会引发两种异常--读xml文件异常(一般由多个根节点导致)和写xml文件异常,会触发这些异常的
函数都应该对他们进行捕获和抛出处理.
package com.sitinpsring.persistence;
import java.io.file;
import java.io.filewriter;
import java.util.hashtable;
import java.util.iterator;
import java.util.list;
import org.dom4j.document;
import org.dom4j.documenthelper;
import org.dom4j.element;
import org.dom4j.io.saxreader;
import org.dom4j.io.xmlwriter;
import com.sitinpsring.domain.member;
import com.sitinpsring.exception.xmlfilereadexception;
import com.sitinpsring.exception.xmlfilewriteexception;
public class memberpersistence {
private string xmlfilepos;
private document document;
public memberpersistence(string xmlfilepos)
throws xmlfilereadexception,xmlfilewriteexception{
this.xmlfilepos = xmlfilepos;
if (isfileexist(this.xmlfilepos) == false) {
// create document when file not exist
createdocument();
return;
} else {
// get docunent when file exist
saxreader reader = new saxreader();
try {
document = reader.read(new file(this.xmlfilepos));
} catch (exception ex) {
throw new xmlfilereadexception(ex.getmessage());
}
}
}
private void createdocument() throws xmlfilewriteexception{
string text = "<members></members>";
try {
document = documenthelper.parsetext(text);
writedocumenttofile();
} catch (xmlfilewriteexception ex) {
throw ex;
}catch (exception ex) {
ex.printstacktrace();
}
}
private void writedocumenttofile() throws xmlfilewriteexception{
try {
xmlwriter writer = new xmlwriter(new filewriter(this.xmlfilepos));
writer.write(document);
writer.close();
} catch (exception ex) {
throw new xmlfilewriteexception(ex.getmessage());
}
}
public hashtable<string, member> loadmemberfromfile() {
hashtable<string, member> retval=new hashtable<string, member>();
list nodes = document.getrootelement().elements("member");
for (iterator it = nodes.iterator(); it.hasnext();) {
element elm = (element) it.next();
member member = new member(elm.attributevalue("id"),elm.elementtext("name"),
integer.parseint(elm.elementtext("age")));
retval.put(member.getid(), member);
}
return retval;
}
public boolean add(member member) throws xmlfilewriteexception{
try {
element rootelm = document.getrootelement();
element newmemberelm = rootelm.addelement("member");
newmemberelm.addattribute("id", member.getid());
element nameelm=newmemberelm.addelement("name");
nameelm.settext(member.getname());
element ageelm=newmemberelm.addelement("age");
ageelm.settext(string.valueof(member.getage()));
writedocumenttofile();
return true;
} catch (xmlfilewriteexception ex) {
throw ex;
}
}
public boolean update(member member) throws xmlfilewriteexception{
try {
element rootelm = document.getrootelement();
list nodes = rootelm.elements("member");
for (iterator it = nodes.iterator(); it.hasnext();) {
element elm = (element) it.next();
if(elm.attributevalue("id").equals(member.getid())){
elm.element("name").settext(member.getname());
elm.element("age").settext(string.valueof(member.getage()));
break;
}
}
writedocumenttofile();
return false;
} catch (xmlfilewriteexception ex) {
throw ex;
}
}
public boolean delete(string id) throws xmlfilewriteexception{
try {
element rootelm = document.getrootelement();
list nodes = rootelm.elements("member");
for (iterator it = nodes.iterator(); it.hasnext();) {
element elm = (element) it.next();
member member = new member(elm.attributevalue("id"),elm.elementtext("name"),
integer.parseint(elm.elementtext("age")));
if(member.getid().equals(id)){
rootelm.remove(elm);
break;
}
}
writedocumenttofile();
return false;
} catch (xmlfilewriteexception ex) {
throw ex;
}
}
public static boolean isfileexist(string filepath) {
boolean exists = (new file(filepath)).exists();
return exists;
}
}
|