上周2月26日提出的需求,为了外网数据迁移到内网需要编写Oracle数据导出导入程序。马大哈提出了思路,使用XML格式存储数据。
在27号进行了尝试,能将数据导出为XML格式,数据库的Blob字段转为String类型写入XML文件中。之后发现导入程序在读取XML文件是报错,错误提示不符合XML文件格式。原因是XML文件中Blob转为String在文件中显示乱码,乱码字符干扰读取。
在3月3号(昨天),换了种导出导入方法,写Java程序运行exp命令进行导出,导出dmp文件,可以完成导入导出功能,但是需要程序运行的机器安装Oracle客户端,而且可能会出现由于操作错误,重复导入的情况。
今天主要重新对27号方法进行了改进尝试,马大哈和我对于导出程序的Blob字段处理函数做了修改,想法是讲Blob字段的数据流直接转为byte数组,之后将byte数组存入XML文件中,最终可以进行导出,导出程序能够解析XML文件内容,同时写入数据库后,数据同源数据相同,无丢失。目前导出导入一条线能够走通,导入程序需要进一步添加功能。(写于3月4号)
出现的问题:
3月6号加入了导出数据文件压缩打包,导入程序中需要判断数据是否已导入,所以需要加入select语句查询数据库,由于数据量稍大,出现了超过最大游标数量的错误。7号想了一个主意,在根据文件夹读取文件的方法中连接数据库,之后每读50条关闭重连数据库,能够保证不报错。但是不知道这种方式是否符合正常设计规范。
不知道在批量循环查询这种情况有什么方法能够不出现超过最大游标数的错误,还在寻找。。。
目前程序基本能够完成数据导入导出任务,而形成可复用的程序还需进一步改进。
数据导出代码:
package ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import org.;
import org.;
import org.;
import org.;
import org.;
//导出数据存入XML
public class ReadDb{
public Connection conn = ();
public CompressBook book = new CompressBook();
public int k = 0;
private static final String HTMLFILEPATH="C:/htmldatafile/";
private static final String IMGFILEPATH="C:/imgdatafile/";
private static final String HTMLTABLE = "TB_CDPF_RADAR_HTML";
private static final String IMGTABLE = "TB_CDPF_RADAR_IMG";
public static String ConvertBLOBtoString( BlobContent) {
StringBuffer strB = new StringBuffer("");
try {
InputStream is = ();
int i = 0;
List<byte[]> bytelist = new LinkedList<byte[]>();
byte[] bytes = new byte[1024];
int len = (bytes);
while(len!=-1){
(bytes);
bytes = new byte[1024];
len = (bytes);
}
for(byte[] tempbytes : bytelist){
for (byte b : tempbytes) {
(b+" ");
}
}
();
} catch (Exception e) {
();
return null;
}
return ();
}
public String readDbtoXmlHTML() {
// 连接数据库
String sql = "select * from "+HTMLTABLE+" where ISEXP=0";
String updateSql = "update "+HTMLTABLE+" set ISEXP=1 where IR_SID=?";
ResultSet result = (sql, conn);
// List<File> htmlfiles = new LinkedList<File>();
try {
if(!new File(HTMLFILEPATH).exists()){
new File(HTMLFILEPATH).mkdir();
}
ResultSetMetaData resultSetMetaData = ();
int columnCount = ();
Element[] elements = new Element[columnCount];
String[] elmentNames = new String[columnCount];
for(int i=0;i<columnCount;i++){
elmentNames[i] = (i+1);
}
Set<String> hkeys = new HashSet<String>();
// Element studyInfo=("studyInfo");
// 当有值时查询
int ctrlBatchNumber = 0;
PreparedStatement pstmt = (updateSql);
while (()) {
// 增加每个节点
Document document = ();
Element cdpfRadarHtmlInfo = ("CdpfRadarHtmlInfo");
(cdpfRadarHtmlInfo);
Element cdpfRadarHtml = ("cdpfRadarHtml");
(("IR_HKEY"));
(1, (("IR_SID")));
();
ctrlBatchNumber++;
for(int i=0;i<columnCount;i++){
elements[i] = (elmentNames[i]);
if((i+1)==29 || (i+1)==30 || (i+1) == 39){
BLOB blob = (BLOB) (i+1);
elements[i].setText(ConvertBLOBtoString(blob));
}else{
if(null==(i+1)){
elements[i].setText("");
}else{
elements[i].setText((i+1));
}
}
}
XMLWriter write = new XMLWriter(new FileOutputStream(new File(
HTMLFILEPATH+"html"+(ctrlBatchNumber)+"-sid"+(("IR_SID"))+".xml") ) );
(document);
();
// (new File(
// HTMLFILEPATH+"html"+(ctrlBatchNumber)+"-sid"+(("IR_SID"))+".xml"));
if(ctrlBatchNumber%100==0){
();
// (());
("html表导出完成100条!");
if(()!=0){
readDbtoXmlIMG(().replace("[", "").replace("]", ""));
();
}
}
}
if(ctrlBatchNumber==0){
return "没有可以导出的数据!";
}
// (());
();
if(()!=0){
readDbtoXmlIMG(().replace("[", "").replace("]", ""));
();
}
("完成!");
// (HTMLFILEPATH, HTMLFILEZIP, false);
(HTMLFILEPATH);
deleteDir(new File(HTMLFILEPATH));
// (IMGFILEPATH, IMGFILEZIP, false);
(IMGFILEPATH);
deleteDir(new File(IMGFILEPATH));
// return ().replace("[", "").replace("]", "");
return "导出完成!";
} catch (Exception e) {
();
return "导出出错,错误信息:"+();
}
}
public void readDbtoXmlIMG(String hkeys) {
// 连接数据库
String sql = "select * " +
"from "+IMGTABLE+" " +
"where IR_HKEY in ("+hkeys+")";
// (sql);
ResultSet result = (sql, conn);
// List<File> imgfiles = new LinkedList<File>();
if(!new File(IMGFILEPATH).exists()){
new File(IMGFILEPATH).mkdir();
}
try {
// 查询数据
ResultSetMetaData resultSetMetaData = ();
int columnCount = ();
Element[] elements = new Element[columnCount];
String[] elmentNames = new String[columnCount];
for(int i=0;i<columnCount;i++){
elmentNames[i] = (i+1);
}
while (()) {
// 增加每个节点
Document document = ();
Element cdpfRadarIMGInfo = ("CdpfRadarIMGInfo");
(cdpfRadarIMGInfo);
Element cdpfRadarIMG = ("cdpfRadarIMG");
for(int i=0;i<columnCount;i++){
elements[i] = (elmentNames[i]);
if((i+1)==7){
BLOB blob = (BLOB) (i+1);
elements[i].setText(ConvertBLOBtoString(blob));
}else{
if(null==(i+1)){
elements[i].setText("");
}else{
elements[i].setText((i+1));
}
}
}
k++;
XMLWriter write = new XMLWriter(new FileOutputStream(new File(
IMGFILEPATH+"img"+(k)+".xml")));
(document);
();
("img表已导出"+k+"条");
} catch (Exception e) {
();
}
}
public void expData(){
ReadDb r = new ReadDb();
();
();
}
private static boolean deleteDir(File dir) {
if (()) {
String[] children = ();
for (int i = 0; i < ; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// 目录此时为空,可以删除
return ();
}
public static void main(String[] args){
ReadDb r = new ReadDb();
();
}
}
数据导入代码:
目前还无注释,需进一步更新注释,完善为可复用程序代码会更新。(写于3月7号)
3月9号更新:完善了部分代码,可以将导出的数据压缩为zip文件,之后导入可以直接读取zip压缩文件中的内容,然后写入数据库中。导入导出程序添加servlet可以做成web服务器上运行的小系统。
3月28日更新:导出程序在本周三(3月25)做了修改。Oracle数据库查询中in后面的数据不能超过一千个,超过会报错。于是将程序改为html表每导出100条,开始导出img表中相关的数据。
可复用程序根据目前的程序来写已经越来越困难。。。