在J2EE Web项目开发中,Excel导入导出批量处理数据是比较常见的。在Excel导入时涉及到业务逻辑之类的校验。譬如说:导入的数据是否存在于数据库中,否做添加数据操作,是则作更新操作,大部分系统不只是单纯的更新数据,根据某些业务规则来确认是否更新数据,需要取到要更新的数据。而这个时候如果要遍历导入的数据集合,去数据库查询并取到与之相关的持久化数据,最终根据相关业务逻辑进行再一步操作。当然了像这种方式,如果要导入的数据有两三千条,那岂不是最少也要查询两三千次数据库?如果还有其他业务也需要查询数据库那么与数据库的交互就更频繁了,所以这种做法一般情况下不是太合理的,我们在实际开发中应该尽可能的减少和数据库的交互,以达到性能要求。
我们可以从数据库中查询出相应的要更新的数据集合,这里我们叫它持久化数据集合,如果说要查找出与导入的数据集合中相应的数据,使用双重循环也是不错的选择。先循环导入的数据集合,然后拿当前遍历到的数据再来一个循环去持久化数据集合中查找对应的对象。但是一般建议不这样做,使用二分法(折半查找)替代双重循环要好的多。下面一个小demo演示了如何使用二分法在集合中查找相应的对象。
public class User implements Comparable<User>, Serializable{
private static final long serialVersionUID = -5410921420480739669L;
private String name; // 姓名
private String nationalIdentifier; // 身份证号码
/**
* 实现Comparable接口的compareTo方法,该方法表示传入的对象与当前对象谁大谁小
* 传入的参数对象u的属性nationalIdentifier大于当前对象的natioanlIdentifier返回正数
* 否则返回负数,相等返回0(有兴趣的朋友可以查看String类的源码)
* 使用二分法在集合中查询某个元素的前提是该集合已经排序好了,如果要查找的元素是自定义类,则必须实现Comparable接口并实现compareTo接口
*/
@Override
public int compareTo(User u) {
if(u != null)
// 调用了String类的compareTo方法
return this.nationalIdentifier.compareTo(u.nationalIdentifier);
return -1;
}
/**
* 重写Object类的equals方法
* 在这里两个User对象的姓名和身份证号码相等表示这两个User对象相等
*/
@Override
public boolean equals(Object obj){
User u = (User) obj;
if(
this.name.equals(u.name)
&&
this.nationalIdentifier.equals(u.nationalIdentifier)
) {
return Boolean.TRUE;
}
return Boolean.FALSE;
}
public User(String _name, String _nationalIdentifier){
this.name = _name;
this.nationalIdentifier = _nationalIdentifier;
}
// ... 其他代码
}
public class Application{
public static void main(String[] args) {
// 假设这里的iList是要导入的Excel数据集合 iList = import list
List<User> iList = new ArrayList<User>(2);
iList.add(new User("学点啥小许", "www.xuediansha.com/city.php?ename=shenzhen"));
iList.add(new User("学点啥小周", "www.xuediansha.com/city.php?ename=guangzhou"));
// 这里假设pList是从数据库中查询的持久化集合 pList = persistent list
List<User> pList = new ArrayList<User>(6);
pList.add(new User("学点啥老武", "www.xuediansha.com/city.php?ename=xian"));
pList.add(new User("学点啥老周", "www.xuediansha.com/city.php?ename=beijing"));
pList.add(new User("学点啥老许", "www.xuediansha.com/city.php?ename=shanghai"));
pList.add(new User("学点啥小许", "www.xuediansha.com/city.php?ename=shenzhen"));
// 在使用二分法在集合中查找某个元素需要将该集合进行排序,使用Collections工具类的sort方法即可
Collections.sort(pList);
// cUser = current user
User cUser;
// eUser = each User
for(User eUser : iList) {
cUser = binarySearch(pList, eUser);
if(cUser != null) {
System.out.println(cUser.getName());
// ... 其他操作
}
}
}
/**
* 使用二分法在list集合中查找user对象
* @param list 传入的持久化数据集合
* @param user 要查询的对象
* @return
*/
public static User binarySearch(List<User> list, User user) {
// curPos = current position
int curPos;
// startPos = start position
int startPos = 0;
// endPos = end position
int endPos = list.size() - 1;
// cUser = current user
User cUser;
int counts = 0;
while(true) {
// curPos = current position
curPos = (startPos + endPos) / 2;
cUser = list.get(curPos);
if(user.equals(cUser)) {
System.out.printf("查找了%d次\n", counts);
return cUser;
} else if (endPos < startPos) {
return (cUser = null);
} else {
if(user.compareTo(cUser) > 0) {
startPos = curPos + 1;
} else {
endPos = curPos - 1;
}
}
counts++;
}
}
}
当然了,执行这样的批量更新操作,在将持久化数据查询出来的同时最好锁定这些数据,至于使用何种锁机制,根据不同系统业务来做决定(悲观锁/乐观锁)。