文本文件格式如下:
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7319-1
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7323-501
RTC 07|CHG D|SPL 0RBN1|MFR 81205
数据字段并不等长,就是有的行有4个数据内容,有可能有6个...
前面的英文为字段的名称?
有没有大虾指点下?
22 个解决方案
#1
首先从文件中读取数据,每当读完一条纪录是,把它转换成oracle的插入语句。你可以执行,也可以存在一个大字符串里,最后一起执行
#2
用字符串拆分split()方法把名称过滤掉。并且根据判断来生成SQL语句
#3
我现在就是按照两位所说的那样做,可是在导入过程当中,大概需要一个多小时,结果JSP页面因为等待时间过长而超时.
一个是看大家有什么成功的经验,或者是有好的处理方法,能够不超时,或者是加快导入的时间?
一个是看大家有什么成功的经验,或者是有好的处理方法,能够不超时,或者是加快导入的时间?
#4
用EJB把,分布式处理。
#5
http://www.builder.com.cn/2002/0806/57323.shtml
kankanasdf
kankanasdf
#6
用消息驱动bean
#7
不知道Spring+Hibernate+Struts这方面有什么思路吗?
#8
我以前寫過的
可參考修改一下
應該可以湊合著用
package com.XXX;
import com.my.db.myDb;
import com.my.file.*;
import com.my.schedule..myOperaEdiRec;
import com.my.schedule..myXa;
import com.my.util.myDate;
import com.my.util.myUtil;
import org.apache.log4j.Logger;
import javax.servlet.ServletContext;
import java.io.BufferedReader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
public class myXBPersocards {
private PreparedStatement psmtInsPersocard;
private myDb oDb;
private myFile oFile;
private myXBlog oLoger;
private BufferedReader oReader;
private Logger oLogger;
private int iAllRecNum;//所有的記錄
private int iOkRecNum;//成功的記錄
private final int iChkBegin = 3;
private final int iChkEnd = 10;
private final int iChkLen = 418;
//字段總長度
private String sFields[];
private final int iFieldsLen[] = {8, 16, 8, 11};
private ServletContext Application; //Context對象
/**
* 定義相慶欄位*
*/
private String FILE_NO;
private String INF_DATE;
private String LINK_NO_N;
private String END_DATE;
private int ERR_NO;//錯語代碼
private String RTN_MSG;//處理訊息
private int iCount=0;
public myXBPersocards(myFile file, myDb db, myXBlog loger, ServletContext application, Logger logger_)
throws Exception {
oReader = null;
this.oDb = db;
this.oFile = file;
this.oLoger = loger;
this.oLogger = logger_;
this.Application = application;
iAllRecNum = 0;
iOkRecNum = 0;
initSql();
try {
oReader = oFile.getReader();
readFile(oReader);
oDb.commit();
} catch (Exception e) {
oLoger.error("讀取文件時出錯:" + e.getMessage());
oLogger.error("讀取文件時出錯:" + e.getMessage());
throw new Exception("讀取文件時出錯:" + e.getMessage());
} finally {
if (oReader != null) oReader.close();
if (psmtInsPersocard != null) oDb.closePrepareStmt(psmtInsPersocard);
}
}
/**
* 初如化sql.
*
* @throws Exception
*/
private void initSql() throws Exception {
String sqlInsPersocard = "insert into Persocard \n" +
"(FILE_NO,INF_DATE,LINK_NO_N,END_DATE \n" +
"values \n " +
"(?,?,?,?)";
psmtInsPersocard = oDb.prepareStmt(sqlInsPersocard);
}
/**
* 切分fields的字段長度
*
* @param line
* @return
* @throws Exception
*/
protected String[] tokenizerLine(String line) throws Exception {
int iBegin = 0;
String str[] = new String[iFieldsLen.length];
byte[] buf = line.getBytes();
for (int i = 0; i < iFieldsLen.length; i++) {
str[i] = new String(buf, iBegin, iFieldsLen[i]);
iBegin += iFieldsLen[i];
}
return str;
}
/**
* 讀文件
*
* @param oReader
* @throws Exception
*/
private boolean readFile(BufferedReader oReader) throws Exception {
int curNum = 0; //該檔案的總行數
int readLineTot = 0; //首行的第3~10碼為資料筆數(E)
ArrayList oList = null;
boolean isBadLen = false; //首行的長度是否OK
String sLine;
String sEDI_NO = myOperaEdiRec.getEdiNO(this.oDb);
//轉檔記錄編號
while ((sLine = oReader.readLine()) != null) {
if (curNum == 0) {
oLogger.info(oFile.getFileName() + "序號" + sEDI_NO);
readLineTot = Integer.parseInt(sLine.substring(iChkBegin - 1, iChkEnd).trim());
if (sLine.getBytes().length != iChkLen) {//如果記錄的長度不對,不處理.
isBadLen = true;
oLoger.error("文檔資料長度不對");
break;
}
} else {
if (oList == null) oList = new ArrayList();
oList.add(curNum - 1, sLine);
}
curNum++;
}
if (isBadLen) return false;
if (readLineTot > 0) {
if ((curNum - 1) != readLineTot || oList == null) {
return false;
} else {
iAllRecNum = readLineTot;//處理的總筆數
}
} else {
return false;
}
//處理可以用的資料
try {
for (int i = 0; i < oList.size(); i++) {
try {
processLine((String) oList.get(i));
iOkRecNum++;
} catch (Exception e) {
oLoger.error("處理一行記錄時出錯:" + e.getMessage());
oLogger.error("處理一行記錄時出錯:" + e.getMessage());
e.printStackTrace();
}
}
} catch (Exception e) {
oLogger.error("轉檔錯誤:" + e.getMessage());
}
oLogger.info("轉檔處理結束");
return true;
}
/**
* 處理一行記錄.
*
* @param sLine
* @throws Exception
*/
private void processLine(String sLine) throws Exception {
sFields = tokenizerLine(sLine);
iCount++;
oLoger.info("第幾筆資料"+iCount);
System.out.println("第幾筆資料"+iCount);
setLineField();//設定欄位
insertPersocard();//新增記錄
}
/**
* 新增資料
*
* @throws Exception
*/
private void insertPersocard() throws Exception {
try {
oDb.setCurrentPrepareStmt(psmtInsPersocard);
psmtInsPersocard.clearParameters();
psmtInsPersocard.setString(1, FILE_NO);
psmtInsPersocard.setString(2, INF_DATE);
psmtInsPersocard.setString(3, LINK_NO_N);
psmtInsPersocard.setString(4, END_DATE);
oDb.prepareUpdate();
} catch (Exception e) {
oLoger.error("新增資料檔時出錯:" + e.getMessage());
oLogger.error("新增資料檔時出錯:" + e.getMessage());
e.printStackTrace();
throw e;
}
}
/**
* 設定欄位的記錄.
*
* @throws Exception
*/
private void setLineField() throws Exception {
FILE_NO = oFile.getFileExt();
INF_DATE = sFields[1].trim();
LINK_NO_N = sFields[2].trim();
END_DATE = sFields[3].trim();
}
}
可參考修改一下
應該可以湊合著用
package com.XXX;
import com.my.db.myDb;
import com.my.file.*;
import com.my.schedule..myOperaEdiRec;
import com.my.schedule..myXa;
import com.my.util.myDate;
import com.my.util.myUtil;
import org.apache.log4j.Logger;
import javax.servlet.ServletContext;
import java.io.BufferedReader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
public class myXBPersocards {
private PreparedStatement psmtInsPersocard;
private myDb oDb;
private myFile oFile;
private myXBlog oLoger;
private BufferedReader oReader;
private Logger oLogger;
private int iAllRecNum;//所有的記錄
private int iOkRecNum;//成功的記錄
private final int iChkBegin = 3;
private final int iChkEnd = 10;
private final int iChkLen = 418;
//字段總長度
private String sFields[];
private final int iFieldsLen[] = {8, 16, 8, 11};
private ServletContext Application; //Context對象
/**
* 定義相慶欄位*
*/
private String FILE_NO;
private String INF_DATE;
private String LINK_NO_N;
private String END_DATE;
private int ERR_NO;//錯語代碼
private String RTN_MSG;//處理訊息
private int iCount=0;
public myXBPersocards(myFile file, myDb db, myXBlog loger, ServletContext application, Logger logger_)
throws Exception {
oReader = null;
this.oDb = db;
this.oFile = file;
this.oLoger = loger;
this.oLogger = logger_;
this.Application = application;
iAllRecNum = 0;
iOkRecNum = 0;
initSql();
try {
oReader = oFile.getReader();
readFile(oReader);
oDb.commit();
} catch (Exception e) {
oLoger.error("讀取文件時出錯:" + e.getMessage());
oLogger.error("讀取文件時出錯:" + e.getMessage());
throw new Exception("讀取文件時出錯:" + e.getMessage());
} finally {
if (oReader != null) oReader.close();
if (psmtInsPersocard != null) oDb.closePrepareStmt(psmtInsPersocard);
}
}
/**
* 初如化sql.
*
* @throws Exception
*/
private void initSql() throws Exception {
String sqlInsPersocard = "insert into Persocard \n" +
"(FILE_NO,INF_DATE,LINK_NO_N,END_DATE \n" +
"values \n " +
"(?,?,?,?)";
psmtInsPersocard = oDb.prepareStmt(sqlInsPersocard);
}
/**
* 切分fields的字段長度
*
* @param line
* @return
* @throws Exception
*/
protected String[] tokenizerLine(String line) throws Exception {
int iBegin = 0;
String str[] = new String[iFieldsLen.length];
byte[] buf = line.getBytes();
for (int i = 0; i < iFieldsLen.length; i++) {
str[i] = new String(buf, iBegin, iFieldsLen[i]);
iBegin += iFieldsLen[i];
}
return str;
}
/**
* 讀文件
*
* @param oReader
* @throws Exception
*/
private boolean readFile(BufferedReader oReader) throws Exception {
int curNum = 0; //該檔案的總行數
int readLineTot = 0; //首行的第3~10碼為資料筆數(E)
ArrayList oList = null;
boolean isBadLen = false; //首行的長度是否OK
String sLine;
String sEDI_NO = myOperaEdiRec.getEdiNO(this.oDb);
//轉檔記錄編號
while ((sLine = oReader.readLine()) != null) {
if (curNum == 0) {
oLogger.info(oFile.getFileName() + "序號" + sEDI_NO);
readLineTot = Integer.parseInt(sLine.substring(iChkBegin - 1, iChkEnd).trim());
if (sLine.getBytes().length != iChkLen) {//如果記錄的長度不對,不處理.
isBadLen = true;
oLoger.error("文檔資料長度不對");
break;
}
} else {
if (oList == null) oList = new ArrayList();
oList.add(curNum - 1, sLine);
}
curNum++;
}
if (isBadLen) return false;
if (readLineTot > 0) {
if ((curNum - 1) != readLineTot || oList == null) {
return false;
} else {
iAllRecNum = readLineTot;//處理的總筆數
}
} else {
return false;
}
//處理可以用的資料
try {
for (int i = 0; i < oList.size(); i++) {
try {
processLine((String) oList.get(i));
iOkRecNum++;
} catch (Exception e) {
oLoger.error("處理一行記錄時出錯:" + e.getMessage());
oLogger.error("處理一行記錄時出錯:" + e.getMessage());
e.printStackTrace();
}
}
} catch (Exception e) {
oLogger.error("轉檔錯誤:" + e.getMessage());
}
oLogger.info("轉檔處理結束");
return true;
}
/**
* 處理一行記錄.
*
* @param sLine
* @throws Exception
*/
private void processLine(String sLine) throws Exception {
sFields = tokenizerLine(sLine);
iCount++;
oLoger.info("第幾筆資料"+iCount);
System.out.println("第幾筆資料"+iCount);
setLineField();//設定欄位
insertPersocard();//新增記錄
}
/**
* 新增資料
*
* @throws Exception
*/
private void insertPersocard() throws Exception {
try {
oDb.setCurrentPrepareStmt(psmtInsPersocard);
psmtInsPersocard.clearParameters();
psmtInsPersocard.setString(1, FILE_NO);
psmtInsPersocard.setString(2, INF_DATE);
psmtInsPersocard.setString(3, LINK_NO_N);
psmtInsPersocard.setString(4, END_DATE);
oDb.prepareUpdate();
} catch (Exception e) {
oLoger.error("新增資料檔時出錯:" + e.getMessage());
oLogger.error("新增資料檔時出錯:" + e.getMessage());
e.printStackTrace();
throw e;
}
}
/**
* 設定欄位的記錄.
*
* @throws Exception
*/
private void setLineField() throws Exception {
FILE_NO = oFile.getFileExt();
INF_DATE = sFields[1].trim();
LINK_NO_N = sFields[2].trim();
END_DATE = sFields[3].trim();
}
}
#9
看来我们得在服务器外单开一个线程了。
#10
用一个随服务器自动启动的servlet每隔一段时间去读取servletContext中的Vector();
Vector里放上我们的语句。然后在这个servlet里执行。不知道能不能行得通
Vector里放上我们的语句。然后在这个servlet里执行。不知道能不能行得通
#11
多谢!
我仔细研究一下各位的思路,再把结果放上来!
我仔细研究一下各位的思路,再把结果放上来!
#12
倒个数据跟JSP有什么关系?
这也要用SSH架构? 寒。。
这也要用SSH架构? 寒。。
#13
用 sqlldr 吧,很简单的。
#14
呵呵`遇到相同的问题了`我的数据量没有你的大`
#15
除了数据量大,没别的瓶颈了吧,也就是:
1.读文件
2.拼sql
3.写数据库
但是我觉得,要实现的比较合理,还是要仔细定义些东西的:
首先定义一个bean,包括所有字段
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7319-1
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7323-501
RTC 07|CHG D|SPL 0RBN1|MFR 81205
从数据看,关键是拼sql
以下是我的思路:
public class Test
{
private String template = "insert into xxxTable (RTC,CHG,SPL,MFR,PNR) values "
+ "('value_RTC','value_CHG','value_SPL','value_MFR','value_PNR');";
private Connection conn = null;
private PreparedStatement pstmt = null;
public static void main(String[] args)
{
try
{
Test t = new Test();
t.parseFile();
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void parseFile() throws SQLException
{
String sss = "RTC 07|CHG D|SPL 0RBN1|MFR 81205";
Scanner scanner = new Scanner(sss);
String token = null;
token = scanner.findInLine("RTC\\s+\\w+\\|?");
if (token != null)
{
template = template.replaceAll("value_RTC", token.replaceAll(
"RTC\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("CHG\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_CHG", token.replaceAll(
"CHG\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("SPL\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_SPL", token.replaceAll(
"SPL\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("MFR\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_MFR", token.replaceAll(
"MFR\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("PNR\\s+[\\w-]*\\|?");
if (token != null)
{
template = template.replaceAll("value_PNR", token.replaceAll(
"PNR\\s+", "").replaceAll("\\|", ""));
}
template = template.replaceAll("value_\\w+", "");
pstmt.addBatch(template);
}
}
象这种比较短的sql,addBatch上3、5万次,再pstmt.executeBatch();一次应该就可以
当然更好的办法应该是:用ultraedit之类的工具将文本文件弄成规范的格式,然后改改文件扩展名,直接用数据库导入功能,呵呵
1.读文件
2.拼sql
3.写数据库
但是我觉得,要实现的比较合理,还是要仔细定义些东西的:
首先定义一个bean,包括所有字段
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7319-1
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7323-501
RTC 07|CHG D|SPL 0RBN1|MFR 81205
从数据看,关键是拼sql
以下是我的思路:
public class Test
{
private String template = "insert into xxxTable (RTC,CHG,SPL,MFR,PNR) values "
+ "('value_RTC','value_CHG','value_SPL','value_MFR','value_PNR');";
private Connection conn = null;
private PreparedStatement pstmt = null;
public static void main(String[] args)
{
try
{
Test t = new Test();
t.parseFile();
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void parseFile() throws SQLException
{
String sss = "RTC 07|CHG D|SPL 0RBN1|MFR 81205";
Scanner scanner = new Scanner(sss);
String token = null;
token = scanner.findInLine("RTC\\s+\\w+\\|?");
if (token != null)
{
template = template.replaceAll("value_RTC", token.replaceAll(
"RTC\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("CHG\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_CHG", token.replaceAll(
"CHG\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("SPL\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_SPL", token.replaceAll(
"SPL\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("MFR\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_MFR", token.replaceAll(
"MFR\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("PNR\\s+[\\w-]*\\|?");
if (token != null)
{
template = template.replaceAll("value_PNR", token.replaceAll(
"PNR\\s+", "").replaceAll("\\|", ""));
}
template = template.replaceAll("value_\\w+", "");
pstmt.addBatch(template);
}
}
象这种比较短的sql,addBatch上3、5万次,再pstmt.executeBatch();一次应该就可以
当然更好的办法应该是:用ultraedit之类的工具将文本文件弄成规范的格式,然后改改文件扩展名,直接用数据库导入功能,呵呵
#16
汗~~~~~~~导数据不需要用SSH吧,直接用写个Java类运行就可以啦~
#17
如果你非要用JSP,那么请单独启动一个线程来导入,或者写一个存储过程供Java调用,或者如楼上所说写个Java类单独运行,在JSP中直接写这种逻辑,嗯,应该是比较业余的做法。
#18
用消息驱动Bean异步执行,然后jsp不停刷新好了
#19
关注下,记得 pl/sql developer 有个倒文本的工具的不知道用不用的上
#20
按照我的经验,JSP提交时间过长的问题应该这样解决:页面仅提供上传功能,将该文本上传到服务器,然后由后台完成导入。
#21
以前我做過這樣的程序,用正則表達式拆分一行的數據,拆分成一組值,然后拼湊出SQL,可以每讀取200行拼湊出一個SQL,再執行(因為sql過長會執行失敗的):
比如:
insert into tablename (col1,col2,col3,col4)
select values1,value2,value3,value4
union
select value1,value2,value3,value4
union
select value1,value2,value3,value4
...
然后execute
比如:
insert into tablename (col1,col2,col3,col4)
select values1,value2,value3,value4
union
select value1,value2,value3,value4
union
select value1,value2,value3,value4
...
然后execute
#22
其实文件导库的实现原理大多数人都知道,都最烦人的就是效率问题,如何做到导入100万条的数据所需要的时间最少呢,个人觉得如果你插库时所需的数据不都是来自文件,也就是说要根据文件的某些数据去找另一些表再插入指定表的话,建议采用存储过程,把与数据库相关所有操作都写到存储过程里面,这样速度较快。除些之外,应想尽方法减少与数据库的通信次数,最好就利用批处理。最后说一点,像你这样大数据导库的,肯定是采用异步方法进行处理。
#1
首先从文件中读取数据,每当读完一条纪录是,把它转换成oracle的插入语句。你可以执行,也可以存在一个大字符串里,最后一起执行
#2
用字符串拆分split()方法把名称过滤掉。并且根据判断来生成SQL语句
#3
我现在就是按照两位所说的那样做,可是在导入过程当中,大概需要一个多小时,结果JSP页面因为等待时间过长而超时.
一个是看大家有什么成功的经验,或者是有好的处理方法,能够不超时,或者是加快导入的时间?
一个是看大家有什么成功的经验,或者是有好的处理方法,能够不超时,或者是加快导入的时间?
#4
用EJB把,分布式处理。
#5
http://www.builder.com.cn/2002/0806/57323.shtml
kankanasdf
kankanasdf
#6
用消息驱动bean
#7
不知道Spring+Hibernate+Struts这方面有什么思路吗?
#8
我以前寫過的
可參考修改一下
應該可以湊合著用
package com.XXX;
import com.my.db.myDb;
import com.my.file.*;
import com.my.schedule..myOperaEdiRec;
import com.my.schedule..myXa;
import com.my.util.myDate;
import com.my.util.myUtil;
import org.apache.log4j.Logger;
import javax.servlet.ServletContext;
import java.io.BufferedReader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
public class myXBPersocards {
private PreparedStatement psmtInsPersocard;
private myDb oDb;
private myFile oFile;
private myXBlog oLoger;
private BufferedReader oReader;
private Logger oLogger;
private int iAllRecNum;//所有的記錄
private int iOkRecNum;//成功的記錄
private final int iChkBegin = 3;
private final int iChkEnd = 10;
private final int iChkLen = 418;
//字段總長度
private String sFields[];
private final int iFieldsLen[] = {8, 16, 8, 11};
private ServletContext Application; //Context對象
/**
* 定義相慶欄位*
*/
private String FILE_NO;
private String INF_DATE;
private String LINK_NO_N;
private String END_DATE;
private int ERR_NO;//錯語代碼
private String RTN_MSG;//處理訊息
private int iCount=0;
public myXBPersocards(myFile file, myDb db, myXBlog loger, ServletContext application, Logger logger_)
throws Exception {
oReader = null;
this.oDb = db;
this.oFile = file;
this.oLoger = loger;
this.oLogger = logger_;
this.Application = application;
iAllRecNum = 0;
iOkRecNum = 0;
initSql();
try {
oReader = oFile.getReader();
readFile(oReader);
oDb.commit();
} catch (Exception e) {
oLoger.error("讀取文件時出錯:" + e.getMessage());
oLogger.error("讀取文件時出錯:" + e.getMessage());
throw new Exception("讀取文件時出錯:" + e.getMessage());
} finally {
if (oReader != null) oReader.close();
if (psmtInsPersocard != null) oDb.closePrepareStmt(psmtInsPersocard);
}
}
/**
* 初如化sql.
*
* @throws Exception
*/
private void initSql() throws Exception {
String sqlInsPersocard = "insert into Persocard \n" +
"(FILE_NO,INF_DATE,LINK_NO_N,END_DATE \n" +
"values \n " +
"(?,?,?,?)";
psmtInsPersocard = oDb.prepareStmt(sqlInsPersocard);
}
/**
* 切分fields的字段長度
*
* @param line
* @return
* @throws Exception
*/
protected String[] tokenizerLine(String line) throws Exception {
int iBegin = 0;
String str[] = new String[iFieldsLen.length];
byte[] buf = line.getBytes();
for (int i = 0; i < iFieldsLen.length; i++) {
str[i] = new String(buf, iBegin, iFieldsLen[i]);
iBegin += iFieldsLen[i];
}
return str;
}
/**
* 讀文件
*
* @param oReader
* @throws Exception
*/
private boolean readFile(BufferedReader oReader) throws Exception {
int curNum = 0; //該檔案的總行數
int readLineTot = 0; //首行的第3~10碼為資料筆數(E)
ArrayList oList = null;
boolean isBadLen = false; //首行的長度是否OK
String sLine;
String sEDI_NO = myOperaEdiRec.getEdiNO(this.oDb);
//轉檔記錄編號
while ((sLine = oReader.readLine()) != null) {
if (curNum == 0) {
oLogger.info(oFile.getFileName() + "序號" + sEDI_NO);
readLineTot = Integer.parseInt(sLine.substring(iChkBegin - 1, iChkEnd).trim());
if (sLine.getBytes().length != iChkLen) {//如果記錄的長度不對,不處理.
isBadLen = true;
oLoger.error("文檔資料長度不對");
break;
}
} else {
if (oList == null) oList = new ArrayList();
oList.add(curNum - 1, sLine);
}
curNum++;
}
if (isBadLen) return false;
if (readLineTot > 0) {
if ((curNum - 1) != readLineTot || oList == null) {
return false;
} else {
iAllRecNum = readLineTot;//處理的總筆數
}
} else {
return false;
}
//處理可以用的資料
try {
for (int i = 0; i < oList.size(); i++) {
try {
processLine((String) oList.get(i));
iOkRecNum++;
} catch (Exception e) {
oLoger.error("處理一行記錄時出錯:" + e.getMessage());
oLogger.error("處理一行記錄時出錯:" + e.getMessage());
e.printStackTrace();
}
}
} catch (Exception e) {
oLogger.error("轉檔錯誤:" + e.getMessage());
}
oLogger.info("轉檔處理結束");
return true;
}
/**
* 處理一行記錄.
*
* @param sLine
* @throws Exception
*/
private void processLine(String sLine) throws Exception {
sFields = tokenizerLine(sLine);
iCount++;
oLoger.info("第幾筆資料"+iCount);
System.out.println("第幾筆資料"+iCount);
setLineField();//設定欄位
insertPersocard();//新增記錄
}
/**
* 新增資料
*
* @throws Exception
*/
private void insertPersocard() throws Exception {
try {
oDb.setCurrentPrepareStmt(psmtInsPersocard);
psmtInsPersocard.clearParameters();
psmtInsPersocard.setString(1, FILE_NO);
psmtInsPersocard.setString(2, INF_DATE);
psmtInsPersocard.setString(3, LINK_NO_N);
psmtInsPersocard.setString(4, END_DATE);
oDb.prepareUpdate();
} catch (Exception e) {
oLoger.error("新增資料檔時出錯:" + e.getMessage());
oLogger.error("新增資料檔時出錯:" + e.getMessage());
e.printStackTrace();
throw e;
}
}
/**
* 設定欄位的記錄.
*
* @throws Exception
*/
private void setLineField() throws Exception {
FILE_NO = oFile.getFileExt();
INF_DATE = sFields[1].trim();
LINK_NO_N = sFields[2].trim();
END_DATE = sFields[3].trim();
}
}
可參考修改一下
應該可以湊合著用
package com.XXX;
import com.my.db.myDb;
import com.my.file.*;
import com.my.schedule..myOperaEdiRec;
import com.my.schedule..myXa;
import com.my.util.myDate;
import com.my.util.myUtil;
import org.apache.log4j.Logger;
import javax.servlet.ServletContext;
import java.io.BufferedReader;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
public class myXBPersocards {
private PreparedStatement psmtInsPersocard;
private myDb oDb;
private myFile oFile;
private myXBlog oLoger;
private BufferedReader oReader;
private Logger oLogger;
private int iAllRecNum;//所有的記錄
private int iOkRecNum;//成功的記錄
private final int iChkBegin = 3;
private final int iChkEnd = 10;
private final int iChkLen = 418;
//字段總長度
private String sFields[];
private final int iFieldsLen[] = {8, 16, 8, 11};
private ServletContext Application; //Context對象
/**
* 定義相慶欄位*
*/
private String FILE_NO;
private String INF_DATE;
private String LINK_NO_N;
private String END_DATE;
private int ERR_NO;//錯語代碼
private String RTN_MSG;//處理訊息
private int iCount=0;
public myXBPersocards(myFile file, myDb db, myXBlog loger, ServletContext application, Logger logger_)
throws Exception {
oReader = null;
this.oDb = db;
this.oFile = file;
this.oLoger = loger;
this.oLogger = logger_;
this.Application = application;
iAllRecNum = 0;
iOkRecNum = 0;
initSql();
try {
oReader = oFile.getReader();
readFile(oReader);
oDb.commit();
} catch (Exception e) {
oLoger.error("讀取文件時出錯:" + e.getMessage());
oLogger.error("讀取文件時出錯:" + e.getMessage());
throw new Exception("讀取文件時出錯:" + e.getMessage());
} finally {
if (oReader != null) oReader.close();
if (psmtInsPersocard != null) oDb.closePrepareStmt(psmtInsPersocard);
}
}
/**
* 初如化sql.
*
* @throws Exception
*/
private void initSql() throws Exception {
String sqlInsPersocard = "insert into Persocard \n" +
"(FILE_NO,INF_DATE,LINK_NO_N,END_DATE \n" +
"values \n " +
"(?,?,?,?)";
psmtInsPersocard = oDb.prepareStmt(sqlInsPersocard);
}
/**
* 切分fields的字段長度
*
* @param line
* @return
* @throws Exception
*/
protected String[] tokenizerLine(String line) throws Exception {
int iBegin = 0;
String str[] = new String[iFieldsLen.length];
byte[] buf = line.getBytes();
for (int i = 0; i < iFieldsLen.length; i++) {
str[i] = new String(buf, iBegin, iFieldsLen[i]);
iBegin += iFieldsLen[i];
}
return str;
}
/**
* 讀文件
*
* @param oReader
* @throws Exception
*/
private boolean readFile(BufferedReader oReader) throws Exception {
int curNum = 0; //該檔案的總行數
int readLineTot = 0; //首行的第3~10碼為資料筆數(E)
ArrayList oList = null;
boolean isBadLen = false; //首行的長度是否OK
String sLine;
String sEDI_NO = myOperaEdiRec.getEdiNO(this.oDb);
//轉檔記錄編號
while ((sLine = oReader.readLine()) != null) {
if (curNum == 0) {
oLogger.info(oFile.getFileName() + "序號" + sEDI_NO);
readLineTot = Integer.parseInt(sLine.substring(iChkBegin - 1, iChkEnd).trim());
if (sLine.getBytes().length != iChkLen) {//如果記錄的長度不對,不處理.
isBadLen = true;
oLoger.error("文檔資料長度不對");
break;
}
} else {
if (oList == null) oList = new ArrayList();
oList.add(curNum - 1, sLine);
}
curNum++;
}
if (isBadLen) return false;
if (readLineTot > 0) {
if ((curNum - 1) != readLineTot || oList == null) {
return false;
} else {
iAllRecNum = readLineTot;//處理的總筆數
}
} else {
return false;
}
//處理可以用的資料
try {
for (int i = 0; i < oList.size(); i++) {
try {
processLine((String) oList.get(i));
iOkRecNum++;
} catch (Exception e) {
oLoger.error("處理一行記錄時出錯:" + e.getMessage());
oLogger.error("處理一行記錄時出錯:" + e.getMessage());
e.printStackTrace();
}
}
} catch (Exception e) {
oLogger.error("轉檔錯誤:" + e.getMessage());
}
oLogger.info("轉檔處理結束");
return true;
}
/**
* 處理一行記錄.
*
* @param sLine
* @throws Exception
*/
private void processLine(String sLine) throws Exception {
sFields = tokenizerLine(sLine);
iCount++;
oLoger.info("第幾筆資料"+iCount);
System.out.println("第幾筆資料"+iCount);
setLineField();//設定欄位
insertPersocard();//新增記錄
}
/**
* 新增資料
*
* @throws Exception
*/
private void insertPersocard() throws Exception {
try {
oDb.setCurrentPrepareStmt(psmtInsPersocard);
psmtInsPersocard.clearParameters();
psmtInsPersocard.setString(1, FILE_NO);
psmtInsPersocard.setString(2, INF_DATE);
psmtInsPersocard.setString(3, LINK_NO_N);
psmtInsPersocard.setString(4, END_DATE);
oDb.prepareUpdate();
} catch (Exception e) {
oLoger.error("新增資料檔時出錯:" + e.getMessage());
oLogger.error("新增資料檔時出錯:" + e.getMessage());
e.printStackTrace();
throw e;
}
}
/**
* 設定欄位的記錄.
*
* @throws Exception
*/
private void setLineField() throws Exception {
FILE_NO = oFile.getFileExt();
INF_DATE = sFields[1].trim();
LINK_NO_N = sFields[2].trim();
END_DATE = sFields[3].trim();
}
}
#9
看来我们得在服务器外单开一个线程了。
#10
用一个随服务器自动启动的servlet每隔一段时间去读取servletContext中的Vector();
Vector里放上我们的语句。然后在这个servlet里执行。不知道能不能行得通
Vector里放上我们的语句。然后在这个servlet里执行。不知道能不能行得通
#11
多谢!
我仔细研究一下各位的思路,再把结果放上来!
我仔细研究一下各位的思路,再把结果放上来!
#12
倒个数据跟JSP有什么关系?
这也要用SSH架构? 寒。。
这也要用SSH架构? 寒。。
#13
用 sqlldr 吧,很简单的。
#14
呵呵`遇到相同的问题了`我的数据量没有你的大`
#15
除了数据量大,没别的瓶颈了吧,也就是:
1.读文件
2.拼sql
3.写数据库
但是我觉得,要实现的比较合理,还是要仔细定义些东西的:
首先定义一个bean,包括所有字段
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7319-1
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7323-501
RTC 07|CHG D|SPL 0RBN1|MFR 81205
从数据看,关键是拼sql
以下是我的思路:
public class Test
{
private String template = "insert into xxxTable (RTC,CHG,SPL,MFR,PNR) values "
+ "('value_RTC','value_CHG','value_SPL','value_MFR','value_PNR');";
private Connection conn = null;
private PreparedStatement pstmt = null;
public static void main(String[] args)
{
try
{
Test t = new Test();
t.parseFile();
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void parseFile() throws SQLException
{
String sss = "RTC 07|CHG D|SPL 0RBN1|MFR 81205";
Scanner scanner = new Scanner(sss);
String token = null;
token = scanner.findInLine("RTC\\s+\\w+\\|?");
if (token != null)
{
template = template.replaceAll("value_RTC", token.replaceAll(
"RTC\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("CHG\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_CHG", token.replaceAll(
"CHG\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("SPL\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_SPL", token.replaceAll(
"SPL\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("MFR\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_MFR", token.replaceAll(
"MFR\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("PNR\\s+[\\w-]*\\|?");
if (token != null)
{
template = template.replaceAll("value_PNR", token.replaceAll(
"PNR\\s+", "").replaceAll("\\|", ""));
}
template = template.replaceAll("value_\\w+", "");
pstmt.addBatch(template);
}
}
象这种比较短的sql,addBatch上3、5万次,再pstmt.executeBatch();一次应该就可以
当然更好的办法应该是:用ultraedit之类的工具将文本文件弄成规范的格式,然后改改文件扩展名,直接用数据库导入功能,呵呵
1.读文件
2.拼sql
3.写数据库
但是我觉得,要实现的比较合理,还是要仔细定义些东西的:
首先定义一个bean,包括所有字段
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7319-1
RTC 07|CHG D|SPL 0RBN1|MFR 81205|PNR AAM7323-501
RTC 07|CHG D|SPL 0RBN1|MFR 81205
从数据看,关键是拼sql
以下是我的思路:
public class Test
{
private String template = "insert into xxxTable (RTC,CHG,SPL,MFR,PNR) values "
+ "('value_RTC','value_CHG','value_SPL','value_MFR','value_PNR');";
private Connection conn = null;
private PreparedStatement pstmt = null;
public static void main(String[] args)
{
try
{
Test t = new Test();
t.parseFile();
}
catch (SQLException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void parseFile() throws SQLException
{
String sss = "RTC 07|CHG D|SPL 0RBN1|MFR 81205";
Scanner scanner = new Scanner(sss);
String token = null;
token = scanner.findInLine("RTC\\s+\\w+\\|?");
if (token != null)
{
template = template.replaceAll("value_RTC", token.replaceAll(
"RTC\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("CHG\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_CHG", token.replaceAll(
"CHG\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("SPL\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_SPL", token.replaceAll(
"SPL\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("MFR\\s+\\w*\\|?");
if (token != null)
{
template = template.replaceAll("value_MFR", token.replaceAll(
"MFR\\s+", "").replaceAll("\\|", ""));
}
token = scanner.findInLine("PNR\\s+[\\w-]*\\|?");
if (token != null)
{
template = template.replaceAll("value_PNR", token.replaceAll(
"PNR\\s+", "").replaceAll("\\|", ""));
}
template = template.replaceAll("value_\\w+", "");
pstmt.addBatch(template);
}
}
象这种比较短的sql,addBatch上3、5万次,再pstmt.executeBatch();一次应该就可以
当然更好的办法应该是:用ultraedit之类的工具将文本文件弄成规范的格式,然后改改文件扩展名,直接用数据库导入功能,呵呵
#16
汗~~~~~~~导数据不需要用SSH吧,直接用写个Java类运行就可以啦~
#17
如果你非要用JSP,那么请单独启动一个线程来导入,或者写一个存储过程供Java调用,或者如楼上所说写个Java类单独运行,在JSP中直接写这种逻辑,嗯,应该是比较业余的做法。
#18
用消息驱动Bean异步执行,然后jsp不停刷新好了
#19
关注下,记得 pl/sql developer 有个倒文本的工具的不知道用不用的上
#20
按照我的经验,JSP提交时间过长的问题应该这样解决:页面仅提供上传功能,将该文本上传到服务器,然后由后台完成导入。
#21
以前我做過這樣的程序,用正則表達式拆分一行的數據,拆分成一組值,然后拼湊出SQL,可以每讀取200行拼湊出一個SQL,再執行(因為sql過長會執行失敗的):
比如:
insert into tablename (col1,col2,col3,col4)
select values1,value2,value3,value4
union
select value1,value2,value3,value4
union
select value1,value2,value3,value4
...
然后execute
比如:
insert into tablename (col1,col2,col3,col4)
select values1,value2,value3,value4
union
select value1,value2,value3,value4
union
select value1,value2,value3,value4
...
然后execute
#22
其实文件导库的实现原理大多数人都知道,都最烦人的就是效率问题,如何做到导入100万条的数据所需要的时间最少呢,个人觉得如果你插库时所需的数据不都是来自文件,也就是说要根据文件的某些数据去找另一些表再插入指定表的话,建议采用存储过程,把与数据库相关所有操作都写到存储过程里面,这样速度较快。除些之外,应想尽方法减少与数据库的通信次数,最好就利用批处理。最后说一点,像你这样大数据导库的,肯定是采用异步方法进行处理。