線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1530
推到 Plurk!
推到 Facebook!

請問多筆資料插入時出錯如何恢復?

答題得分者是:bestlong
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-01-26 14:07:35 IP:202.174.xxx.xxx 未訂閱
請問各位大大,當用for迴圈要插入大筆資料時,中間出錯了(資料表損毀,資料庫連接中斷,資料型態錯誤),請問要如何恢復到未插入資料時的狀態?
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-01-26 14:12:09 IP:202.174.xxx.xxx 未訂閱
忘了說明,小弟用ADO寫的。
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-01-26 14:22:51 IP:211.22.xxx.xxx 未訂閱
因為不知道你的整體架構是怎樣的, 大量到多少? 是否同時有多人在異動? 都會影響處理的方式與結果. 所以只能說基本上是將資料的異動加入交易機制來保護. 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-01-26 14:35:33 IP:202.174.xxx.xxx 未訂閱
您好,小弟共有兩個表,一個是儲存所有產品的詳細資料和數量,大約不到1000筆,另一個表是入庫清單,大約不到100筆。 小弟想說如果利用for迴圈來將入庫清單更新到產品清單,如果中途出錯了要如何恢復到未更新前的狀態。 請問能不能給個交易機制的例子?
tech_state
版主


發表:44
回覆:638
積分:641
註冊:2003-02-10

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-01-26 20:18:13 IP:210.66.xxx.xxx 未訂閱
ADOConnection1->BeginTrans();  // 交易機制開始
try
{
   ...
   ADOConnection1->CommitTrans();  // 交易機制完成
}
catch(...)
{
   ADOConnection1->RollbackTrans();  // 交易機制回復資料
   ShowMessage("database insert fail");
}
 
Good Lucky !! ================================= 涵養怒中氣。謹防順口言。留心忙裡錯。珍惜有時錢。 是非終日有,不聽自然無 天下本無事,庸人自擾之
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-01-27 11:56:01 IP:202.174.xxx.xxx 未訂閱
AnsiString cmd;
try
{
  cmd = "insert into Table_A (SN) values('12345')";
  ADOConnection1->BeginTrans();
  ADOQuery1->Close();
  ADOQuery1->SQL->Clear();
  ADOQuery1->SQL->Add(cmd);
  ADOQuery1->ExecSQL();
}
catch(Exception &e)
{
  ADOConnection1->RollbackTrans();
  ShowMessage(cmd);
  return;
}    try
{
  cmd = "insert into Table_B (SN, Text) values('12345', 'ABC')";
  ADOQuery1->Close();
  ADOQuery1->SQL->Clear();
  ADOQuery1->SQL->Add(cmd);
  ADOQuery1->ExecSQL();
  ADOConnection1->CommitTrans();
}
catch(Exception &e)
{
  ADOConnection1->RollbackTrans();
  ShowMessage(cmd);
  return;
}
請問如果當Table_B插入出現錯誤時,為什麼Table_A的記錄不會清除掉?
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-01-27 17:26:43 IP:202.174.xxx.xxx 未訂閱
AnsiString cmd;    try
{
  cmd = "select * from Table_A where SN='12345'";
  ADOQuery1->Close();
  ADOQuery1->SQL->Clear();
  ADOQuery1->SQL->Add(cmd);
  ADOQuery1->Open();
}
catch(Exception &e)
{
  ShowMessage(cmd);
  ShowMessage(e.Message.c_str());
  return;
}    try
{
  if(ADOQuery1->RecordCount)
  {
    ADOQuery1->Edit();
    ADOQuery1->FieldByName("Date")->AsString = FormatDateTime("YYYY-MM-DD HH:MM:SS", Now());
  }
  else
  {
    ADOQuery1->Append();
    ADOQuery1->FieldByName("SN")->AsString = "12345";
    ADOQuery1->FieldByName("Date")->AsString = FormatDateTime("YYYY-MM-DD HH:MM:SS", Now());
  }
}
catch(Exception &e)
{
    ShowMessage(cmd);
    ShowMessage(e.Message.c_str());
    return;
}    try
{
    cmd = "select * from Table_B";
    ADOQuery2->Close();
    ADOQuery2->SQL->Clear();
    ADOQuery2->SQL->Add(cmd);
    ADOQuery2->Open();
}
catch(Exception &e)
{
    ShowMessage(cmd);
    ShowMessage(e.Message.c_str());
    return;
}    try
{
  ADOTable1->First()
  for(int i = 0; i < ADOTable1->RecordCount; i  )
  {
    ADOQuery2->Append();
    ADOQuery2->FieldByName("SN")->AsString = ADOTable1->FieldByName("SN")->AsString;
    ADOQuery2->FieldByName("ID")->AsString = ADOTable1->FieldByName("Id")->AsString;
    ADOQuery2->FieldByName("NUM")->AsInteger = ADOTable1->FieldByName("Num")->AsInteger;
    ADOTable1->Next();
  }
}
catch(Exception &e)
{
  ShowMessage(cmd);
  ShowMessage(e.Message.c_str());
  return;
}    try
{
  ADOConnection1->BeginTrans();
  ADOQuery1->UpdateBatch(arAll);
  ADOQuery2->UpdateBatch(arAll);
  ADOConnection1->CommitTrans();
}
catch(Exception &e)
{
  ADOConnection1->RollbackTrans();
  ShowMessage(e.Message.c_str());
  return;
}
以上ADOQuery的LockType皆設為ltBatchOptimistic。 這樣做的話,Table_B插入時出錯就可以恢復原狀。 但是為啥Table_A恢復不了?即使Table_A語法沒錯也應該恢復不是嗎?
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-01-27 22:07:59 IP:61.59.xxx.xxx 未訂閱
上篇你貼出的程式碼看起來不太像是完整的, 如果是節錄部份後再改過的那就很奇怪了. 請再確認 ADOQuery1, ADOQuery2 的 LockType 為 ltBatchOptimistic 還有 ADOQuery1 沒有被重新開啟過. 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-01-28 01:17:27 IP:219.93.xxx.xxx 未訂閱
抱歉,上面是我憑記憶寫出來的,下面才是真正的。    
 
//---------------------------------------------------------------------------    #include 
#pragma hdrstop    #include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
}
//---------------------------------------------------------------------------    void __fastcall TForm1::BitBtn1Click(TObject *Sender)
{
        AnsiString cmd;
        try
        {
                cmd = "select * from table_a";
                ADOQuery1->Close();
                ADOQuery1->SQL->Clear();
                ADOQuery1->SQL->Add(cmd);
                ADOQuery1->Open();
        }
        catch(Exception &e)
        {
                ShowMessage(cmd);
                ShowMessage(e.Message.c_str());
                return;
        }            try
        {
                cmd = "select * from table_b";
                ADOQuery2->Close();
                ADOQuery2->SQL->Clear();
                ADOQuery2->SQL->Add(cmd);
                ADOQuery2->Open();
        }
        catch(Exception &e)
        {
                ShowMessage(cmd);
                ShowMessage(e.Message.c_str());
                return;
        }            TLocateOptions Opts;
        Opts << loCaseInsensitive;            try
        {
                ADOTable1->First();
                for(int i = 0; i < ADOTable1->RecordCount; i  )
                {
                        bool Found1 = ADOQuery1->Locate("SN", ADOTable1->FieldByName("SN")->AsString, Opts);                            if(Found1)
                        {
                                ADOQuery1->Edit();
                                ADOQuery1->FieldByName("Date")->AsString = FormatDateTime("YYYY-MM-DD HH:MM:SS", Now());
                        }
                        else
                        {
                                ADOQuery1->Append();
                                ADOQuery1->FieldByName("SN")->AsString = ADOTable1->FieldByName("SN")->AsString;
                                ADOQuery1->FieldByName("Date")->AsString = FormatDateTime("YYYY-MM-DD HH:MM:SS", Now());
                        }                            ADOQuery2->Append();
                        ADOQuery2->FieldByName("SN")->AsString = ADOTable1->FieldByName("SN")->AsString;
                        ADOQuery2->FieldByName("ID")->AsString = ADOTable1->FieldByName("ID")->AsString;
                        ADOQuery2->FieldByName("NUM")->AsInteger = ADOTable1->FieldByName("NUM")->AsInteger;
                        ADOTable1->Next();
                }
        }
        catch(Exception &e)
        {
                ShowMessage(cmd);
                ShowMessage(e.Message.c_str());
                return;
        }            try
        {
                ADOConnection2->BeginTrans();
                ADOQuery1->UpdateBatch(arAll);
                ADOQuery2->UpdateBatch(arAll);
                ADOConnection2->CommitTrans();
        }
        catch(Exception &e)
        {
                ADOConnection2->RollbackTrans();
                ShowMessage(e.Message.c_str());
                return;
        }
}
//---------------------------------------------------------------------------    void __fastcall TForm1::BitBtn2Click(TObject *Sender)
{
        try
        {
                ADOTable1->First();
                ADOTable1->Edit();
                ADOTable1->FieldByName("SN")->AsString = "test";
                ADOTable1->FieldByName("ID")->AsString = "test";
                ADOTable1->FieldByName("NUM")->AsInteger = 1000;
                ADOTable1->Post();
        }
        catch(Exception &e)
        {
                ADOTable1->Cancel();
                ShowMessage(e.Message.c_str());
                return;
        }
}
//---------------------------------------------------------------------------
table_a: create table Table_A ( SN varchar(20) not null, Date varchar(20), primary key(SN) ); table_b: create table Table_B ( SN varchar(20) not null, ID varchar(20) not null, NUM int, primary key(SN, ID) ); table_c: create table Table_C ( SN varchar(20), ID varchar(20), NUM int ); insert into table_c (sn, id, num) values('123', 'abc', 10); insert into table_c (sn, id, num) values('123', 'def', 20); insert into table_c (sn, id, num) values('123', 'ghi', 30); insert into table_c (sn, id, num) values('456', 'abc', 40); insert into table_c (sn, id, num) values('456', 'def', 50); insert into table_c (sn, id, num) values('456', 'ghi', 60); insert into table_c (sn, id, num) values('789', 'abc', 70); insert into table_c (sn, id, num) values('789', 'def', 80); insert into table_c (sn, id, num) values('789', 'ghi', 90); insert into table_c (sn, id, num) values('789', 'jkl', 100); ADOConnection1 -> ADOTable1 ADOConnection2 -> ADOQuery1, ADOQuery2 ADOquery1, ADOQuery2的LockType為ltBatchOptimistic 執行步驟:BitBtn1 -> BitBtn2 -> BitBtn1 小弟故意利用此問題來查看table是否會恢復原狀。 但結果卻還是照樣更新了。
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-01-28 08:49:21 IP:211.22.xxx.xxx 未訂閱
引言: 執行步驟:BitBtn1 -> BitBtn2 -> BitBtn1 小弟故意利用此問題來查看table是否會恢復原狀。 但結果卻還是照樣更新了。
首先 ADOTable1 不知道你是設定連接 Table_b 還是 Table_c. 所以不確定你所說的故意利用此問題是想產生什麼樣的錯誤. 按下 BitBtn1 如果沒有發生錯誤就一定會更新回資料庫 因為已經 CommitTrans 既然更新了當然就無法回復. 按下 BitBtn2 也是直接更新回資料庫, 也不能回復. 感覺起來好像你對 Transation 的觀念還不夠清楚, 建議你再深入研究一下. 我是雪龍 發表人 - bestlong 於 2005/01/28 09:04:06
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-01-28 09:39:16 IP:202.174.xxx.xxx 未訂閱
您好。 按下第一次BitBtn1時,正常是不會出現錯誤,內容如下: mysql> select * from table_a; ----- --------------------- | SN | Date | ----- --------------------- | 123 | 2005-01-28 09:32:07 | | 456 | 2005-01-28 09:32:07 | | 789 | 2005-01-28 09:32:07 | ----- --------------------- 3 rows in set (0.13 sec) mysql> select * from table_b; ----- ----- ------ | SN | ID | NUM | ----- ----- ------ | 123 | abc | 10 | | 123 | def | 20 | | 123 | ghi | 30 | | 456 | abc | 40 | | 456 | def | 50 | | 456 | ghi | 60 | | 789 | abc | 70 | | 789 | def | 80 | | 789 | ghi | 90 | | 789 | jkl | 100 | ----- ----- ------ 10 rows in set (0.01 sec) mysql> select * from table_c; ------ ------ ------ | SN | ID | NUM | ------ ------ ------ | 123 | abc | 10 | | 123 | def | 20 | | 123 | ghi | 30 | | 456 | abc | 40 | | 456 | def | 50 | | 456 | ghi | 60 | | 789 | abc | 70 | | 789 | def | 80 | | 789 | ghi | 90 | | 789 | jkl | 100 | ------ ------ ------ 10 rows in set (0.00 sec) 按下第一次BitBtn2時,也是沒問題,內容如下: mysql> select * from table_a; ----- --------------------- | SN | Date | ----- --------------------- | 123 | 2005-01-28 09:32:07 | | 456 | 2005-01-28 09:32:07 | | 789 | 2005-01-28 09:32:07 | ----- --------------------- 3 rows in set (0.00 sec) mysql> select * from table_b; ----- ----- ------ | SN | ID | NUM | ----- ----- ------ | 123 | abc | 10 | | 123 | def | 20 | | 123 | ghi | 30 | | 456 | abc | 40 | | 456 | def | 50 | | 456 | ghi | 60 | | 789 | abc | 70 | | 789 | def | 80 | | 789 | ghi | 90 | | 789 | jkl | 100 | ----- ----- ------ 10 rows in set (0.00 sec) mysql> select * from table_c; ------ ------ ------ | SN | ID | NUM | ------ ------ ------ | test | test | 1000 | | 123 | def | 20 | | 123 | ghi | 30 | | 456 | abc | 40 | | 456 | def | 50 | | 456 | ghi | 60 | | 789 | abc | 70 | | 789 | def | 80 | | 789 | ghi | 90 | | 789 | jkl | 100 | ------ ------ ------ 10 rows in set (0.00 sec) 按下第二次BitBtn1時就出現問題了,內容如下: Warning: Some non-transaction changed tables coundn't be rolled back. mysql> select * from table_a; ------ --------------------- | SN | Date | ------ --------------------- | 123 | 2005-01-28 09:35:57 | <----- Date應該是2005-01-28 09:32:07 | 456 | 2005-01-28 09:35:57 | <----- Date應該是2005-01-28 09:32:07 | 789 | 2005-01-28 09:35:57 | <----- Date應該是2005-01-28 09:32:07 | test | 2005-01-28 09:35:57 | <----- 這裡記錄不應該出現的 ------ --------------------- 4 rows in set (0.00 sec) mysql> select * from table_b; ------ ------ ------ | SN | ID | NUM | ------ ------ ------ | 123 | abc | 10 | | 123 | def | 20 | | 123 | ghi | 30 | | 456 | abc | 40 | | 456 | def | 50 | | 456 | ghi | 60 | | 789 | abc | 70 | | 789 | def | 80 | | 789 | ghi | 90 | | 789 | jkl | 100 | | test | test | 1000 | <----- 這筆記錄不應該出現的 ------ ------ ------ 11 rows in set (0.00 sec) mysql> select * from table_c; ------ ------ ------ | SN | ID | NUM | ------ ------ ------ | test | test | 1000 | | 123 | def | 20 | | 123 | ghi | 30 | | 456 | abc | 40 | | 456 | def | 50 | | 456 | ghi | 60 | | 789 | abc | 70 | | 789 | def | 80 | | 789 | ghi | 90 | | 789 | jkl | 100 | ------ ------ ------ 10 rows in set (0.00 sec) 請幫我看看哪裡出錯了?
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-01-28 18:24:25 IP:219.93.xxx.xxx 未訂閱
小弟是用 BCB6 SP4 MySQL v3.2358 MyODBC 3.51.04 執行第二次BitBtn1時會出現以下錯誤: [MySQL][MyODBC 3.51Driver]Warning: Some non-transactional changed tables couldn't be rolled back. 請問是不是MyODBC不支援有關?還是MySQL不支援Transaction?還是ODBC不支援Transaction? 可不可以給小第一個簡單的範例參考一下?或是哪裡可以讓小弟學習Transaction機制?
irvinehing
初階會員


發表:77
回覆:79
積分:31
註冊:2003-11-12

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-01-29 09:31:25 IP:202.174.xxx.xxx 未訂閱
終於解決了。 MySQL 3.23-max的InnoDB才支援Transaction,所以只要把MySQL安裝成mysqld-max,再設定my.ini就好了。 步驟一: mysqld-max --install 步驟二: [mysqld] # You can write your other MySQL server options here # ... # Data files must be able to hold your data and indexes. # Make sure that you have enough free disk space. innodb_data_file_path = ibdata1:10M:autoextend # # Set buffer pool size to 50-80% of your computer's memory set-variable = innodb_buffer_pool_size=70M set-variable = innodb_additional_mem_pool_size=10M # # Set the log file size to about 25% of the buffer pool size set-variable = innodb_log_file_size=20M set-variable = innodb_log_buffer_size=8M # innodb_flush_log_at_trx_commit=1 步驟三: CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) ENGINE=InnoDB; 或 CREATE TABLE customers (a INT, b CHAR (20), INDEX (a)) TYPE=InnoDB;
bestlong
站務副站長


發表:126
回覆:734
積分:512
註冊:2002-10-19

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-01-31 09:18:51 IP:211.22.xxx.xxx 未訂閱
=_= 問題找到就好, 建議以後詢問問題要把整個環境交代好. 我是雪龍
------
http://blog.bestlong.idv.tw/
http://www.bestlong.idv.tw/
http://delphi-ktop.bestlong.idv.tw/
系統時間:2024-04-27 10:40:15
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!