一、存儲過程中使用事務的簡單語法
在存儲過程中使用事務時非常重要的,使用數據可以賀銷保持數據的關聯完整性,在Sql server存儲過程中使用事務也很簡單,用一個例子來說明它的語法格式:
Create Procere MyProcere
( @Param1 nvarchar(10),
@param2 nvarchar(10)
)
AS
Begin
Set NOCOUNT ON;
Set XACT_ABORT ON;
Begin Tran
Delete from table1 where name=』abc』;
Insert into table2 values(value1,value2,value3);
Commit Tran
End
說明:
1 、使用存儲過程執行事物,需要開啟XACT_ABORT參數(默認值為Off),將該參數設置為On,表示當執行事務時,如果出錯,會將transcation設置為uncommittable狀態,那麼在語句塊批處理結束後將回滾所有操作;如果該參數設置為Off,表示當執行事務時,如果出錯,出錯的語句將不會執行,其他正確的操作繼續執行。
2、當SET NOCOUNT 為 ON 時,不返回計數(計數表示受 Transact-SQL 語句影響的行數,例如在Sql server查詢分析器中執行一個delete操作後,下方窗口會提示(3)Rows Affected)。當 SET NOCOUNT 為 OFF 時,返回計數,我們應該在存儲過程的頭部加上SET NOCOUNT ON 這樣的話,在退出存儲過程的時候加上 SET NOCOUNT OFF這樣的話,以達到優化存儲過程的目的。
二、事務內設置保存點
用戶可以在事務內設置保存點或標記。保存點定義如果有條件地取消事務的一部分,事務可以返回的位置。如果將事務回滾到保存點,則必須(如果需要,使用更多的 Transact-SQL 語句和 COMMIT TRANSACTION 語句)繼續完成事務,或者必須(通過將事務回滾到其起始點)完全取消事務。若要取消整個事務,請使用 ROLLBACK TRANSACTION transaction_name 格式。這將撤消事務的所有語句和過程。如:
代碼
Create Procere MyProcere
AS
Begin
Set NOCOUNT ON;
Set XACT_ABORT ON;
begin tran ok --開始一個事務OK
delete from rxqz where qz= 'rx015 ' --刪除數據
save tran bcd --保存一個事務點命名凱肆為bcd
update sz set name='李麗s' where name= '李麗'--修改數據
if @@error<>0 --判斷修改數據有沒有出錯
begin --如果出錯
rollback tran bcd -- 回滾事務到BCD 的還原點
commit tran ok --提交事務
end
else --沒有出錯
commit tran ok --提交事務
End
說明:1、@@error判斷是否有錯誤,為0表示沒有盯拍轎錯誤,但是對那種重大錯誤無法捕捉,而且@@error只能前一句sql語句生效。
三、存儲過程使用try…catch捕獲錯誤
在存儲過程中可以使用try…catch語句來捕獲錯誤,如下:
Create Procere MyProcere
( @Param1 nvarchar(10),
@param2 nvarchar(10)
)
AS
Begin
Set NOCOUNT ON;
Begin try
Delete from table1 where name=』abc』;
Insert into table2 values(value1,value2,value3);
End try
Begin Catch
SELECT ERROR_NUMBER() AS ErrorNumber,
ERROR_MESSAGE() AS ErrorMessage;
End Catch
End
說明:1、捕獲錯誤的函數有很多,如下:
ERROR_NUMBER() 返回錯誤號。
ERROR_SEVERITY() 返回嚴重性。
ERROR_STATE() 返回錯誤狀態號。
ERROR_PROCEDURE() 返回出現錯誤的存儲過程或觸發器的名稱。
ERROR_LINE() 返回導致錯誤的常式中的行號。
ERROR_MESSAGE() 返回錯誤消息的完整文本。該文本可包括任何可替換參數所提供的值,如長度、對象名或時間。
2、有些錯誤,如sql語句中的表名稱輸入錯誤,這是資料庫引擎無法解析這個表名稱時,所發生的錯誤在當前的try…catch語句中無法捕獲,必須由外層調用該存儲過程的地方使用 try…catch來進行捕獲。
四、存儲過程中事務和try…catch聯合使用
在存儲過程中使用事務時,如果沒有try…catch語句,那麼當set xact_abort on時,如果有錯誤發生,在批處理語句結束後,系統會自動回滾所有的sql操作。當set xact_abort off時,如果有錯誤發生,在批處理語句結束後,系統會執行所有沒有發生錯誤的語句,發生錯誤的語句將不會被執行。
在存儲過程中使用事務時,如果存在try…catch語句塊,那麼當捕獲到錯誤時,需要在catch語句塊中手動進行Rollback操作,否則系統會給客戶端傳遞一條錯誤信息。如果在存儲過程開始處將set xact_abort on,那麼當有錯誤發生時,系統會將當前事務置為不可提交狀態,即會將xact_state()置為-1,此時只可以對事務進行Rollback操作,不可進行提交(commit)操作,那麼我們在catch語句塊中就可以根據xact_state()的值來判斷是否有事務處於不可提交狀態,如果有則可以進行rollback操作了。如果在存儲過程開始處將set xact_abort off,那麼當有錯誤發生時,系統不會講xact_state()置為-1,那麼我們在catch塊中就不可以根據該函數值來判斷是否需要進行rollback了,但是我們可以根據@@Trancount全局變數來判斷,如果在catch塊中判斷出@@Trancount數值大於0,代表還有未提交的事務,既然進入catch語句塊了,那麼還存在未提交的事務,該事務應該是需要rollback的,但是這種方法在某些情況下可能判斷的不準確。推薦的方法還是將set xact_abort on,然後在catch中判斷xact_state()的值來判斷是否需要Rollback操作。
下面我們來看看兩個例子:
一.使用Set xact_abort on
Create proc myProcere
As
begin
set xact_abort on;
begin try
begin tran
insert into TestStu values('Terry','boy',23);
insert into TestStu values('Mary','girl',21);
commit tran
end try
begin catch
--在此可以使用xact_state()來判斷是否有不可提交的事務,不可提交的事務
--表示在事務內部發生錯誤了。Xact_state()有三種值:-1.事務不可提交;
--1.事務可提交;0.表示沒有事務,此時commit或者rollback會報錯。
if xact_state()=-1
rollback tran;
end catch
end
二.使用Set xact_abort off
Create proc myProcere
As
begin
set xact_abort off;
begin try
begin tran
insert into TestStu values('Terry','boy',23);
insert into TestStu values('Mary','girl',21);
commit tran
end try
begin catch
--在此不可以使用xact_state來判斷是否有不可提交的事務
--只可以使用@@Trancount來判斷是否有還未提交的事務,未提交的事務未必
--就是不可提交的事務,所以使用@@TranCount>0後就RollBack是不準確的
if @@TranCount>0
rollback tran;
end catch
end
另外,對於@@Trancount需要說明的是,begin tran 語句將 @@Trancount加 1。Rollback tran將 @@Trancount遞減到 0,但 Rollback tran savepoint_name 除外,它不影響 @@Trancount。Commit tran 或 Commit work 將 @@Trancount 遞減 1。
② 如何判斷java的存儲過程是否成功執行
這個分兩種情況:
由於存儲過程是資料庫自身的東西,JAVA只是調用
所以,如果是語殲純法上的錯誤 sql直接不能執行 , JAVA確實能接收到異常
但是如果語法沒有錯誤, 只是你寫的陪拍條件錯了, sql能執行,氏亂咐只是沒有得到你想要的效果, 這個情況, 是判斷不了的, 都會視為成功執行
如果 sql = "select from aaa where id > 10" 這直接是語法 錯誤,肯定報錯
但 如果 sql = "update aaa set name = 'aaa' where id='123' "; 沒有語法 錯誤 ,能執行, 只是沒有id = 123的數據, 你要改124的,錯寫成123了, 就修改不了, 但也不會報任何錯
③ Sqlserver 8.0.2039 存儲過程怎樣寫try catch
sql2005 以下版本沒有 try catch語句辯遲塊;
通常滑灶輪信信採用 @@error 來判斷;
code:
declare @error int
set @error = 0
begin tran
--your sql here and exceut
set @error = @@error + @error
if(@error <> 0 ) --has error
begin
rollback ;
return;
end
--another sql code and excut it ..
set @error = @@error + @error
if(@error <> 0 ) --has error
begin
rollback ;
return;
end
commit
④ 如何將datatable傳入存儲過程中
一、測試環境
1、Windows Server 2008 R2 DataCenter
2、Visual Studio 2008 Team System With SP1
3、SQL Server 2008 Enterprise Edition With SP1
由於是SQL Server 2008新特性,所以只能用2008。
二、測試概述
測試項目很簡單,就是添加新用戶
三、准凳敏備數據
1、建立資料庫、表、類型、存儲過程
IF NOT EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('Users') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)
BEGIN
CREATE TABLE dbo.Users
(
UserID INT IDENTITY(-1, -1) NOT NULL,
UserName VARCHAR(20) NOT NULL,
UserPass VARCHAR(20) NOT NULL,
Sex BIT NULL,
Age SMALLINT NULL,
CONSTRAINT PK_Users_UserID PRIMARY KEY(UserID)
)
END
IF NOT EXISTS(SELECT * FROM sys.table_types WHERE name = 'UserTable' AND is_user_defined = 1)
BEGIN
CREATE TYPE UserTable AS TABLE
(
UserName VARCHAR(20) NOT NULL,
UserPass VARCHAR(20) NOT NULL,
Sex BIT NULL,
Age SMALLINT NULL
)
END
GO
IF EXISTS(SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('sp_InsertSingleUser') AND OBJECTPROPERTY(id, N'IsProcere') = 1)
BEGIN
DROP PROCEDURE dbo.sp_InsertSingleUser
END
GO
CREATE PROCEDURE dbo.sp_InsertSingleUser
(
@User UserTable READONLY
)
AS
SET XACT_ABORT ON
BEGIN TRANSACTION
INSERT INTO dbo.Users(UserName, UserPass, Sex, Age)
SELECT UserName, UserPass, Sex, Age FROM @User
COMMIT TRANSACTION
SET XACT_ABORT OFF
GO
前台搭建好表單,後台主要是一個函數:
publicvoidfnInsertSingleUser(DataTablev_dt)
{
try
{
SqlConnectioncn=newSqlConnection(CONN);
SqlCommandcmd=cn.CreateCommand();
cmd.CommandType=亮晌CommandType.StoredProcere;
cmd.CommandText=@"sp_InsertSingleUser";
SqlParameterp=cmd.Parameters.AddWithValue("@User",v_dt);
DataSetds=newDataSet();
SqlDataAdapterda=newSqlDataAdapter(cmd);
da.Fill(ds);
}敬粗鋒
catch(Exceptionex)
{
throwex;
}
}
⑤ SqlDataReader無法從資料庫中讀取多條記錄
while(dr.Read())
{
...
}
dr.Close();
這樣是沒有問題橡滲的,可以讀取渣輪多條數據.
dr.Read()方法讀取下一條數據成功就返回true,失敗,即讀取完畢時返回false.
至於只能讀取一條數據,可能是這個存儲過程只返回了一條數梁梁脊據,或者其他什麼原因,我沒有用過SQLServerHelper,不是很清楚.
可以在資料庫里調用那個存儲過程試試,看看返回了多少數據.
⑥ JDBC調用Sybase存儲過程,結果集總是無法返回,該怎麼處理
JDBC調用Sybase存儲過程,結果集總是無法返回!
java代碼部分如下:
String sproc = "{ call zhouxiaobotest2(?,?,?,?)} ";
CommonDAO = null;
try {
= new CommonDAO(jndi);
Connection connect = .getConn();
//得到總數
rowNum = PageDiv.getCount(countSql.toString(), );
//設置分頁信息
pageBean.setPageInfo(rowNum, pageSize);
// 獲取CallableStatement語句:
CallableStatement mStatement = connect.prepareCall(sproc,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
// 傳入輸入參數和注冊輸出參數
mStatement.setString(1,sql.toString());
mStatement.setInt(2, 10);
mStatement.setInt(3, 10);
mStatement.setInt(4, 5000);
// 執行存儲過程
ResultSet rs = null;
mStatement.execute();
rs = mStatement.getResultSet();
catch (Exception ex) {
ex.printStackTrace();
logger.warn(sql.toString());
} finally {
.destroy();
= null;
sproc = null;
}
存儲過程如下:
create procere zhouxiaobotest @qry varchar(16384),@ipage int, @num int,@maxpages int
as
/*@qry SQL語句, @ipage 頁數, @num 每頁記錄條數, @maxpages 最大查薯昌詢頁數 */
begin
declare @execsql varchar(16384)
set @execsql = " select USER_NAME from TBL_USER "
execute (@execsql)
end
create procere zhouxiaobotest2 @qry varchar(16384),@ipage int, @num int,@maxpages int
as
/*@qry SQL語句, @ipage 頁數, @num 每頁記錄條數, @maxpages 最大查詢頁橡手液數 */
begin
select USER_NAME from TBL_USER
end
現在我的問題是調用存梁物儲過程zhouxiaobotest,mStatement.execute()始終是false;而調用zhouxiaobotest2 mStatement.execute()就是true,能得到結果集。我想知道如何修改程序使我能夠調用zhouxiaobotest取得結果集(之前調試程序運行沒有拋出任何異常,而且控制台運行存儲過程也都正確)
⑦ 對象不能從 DBNull 轉換為其他類型。
prmSid.Value 返回的檔燃值是 DBNull,也就是說相當於數據岩蠢掘庫單元格中什麼值也沒有。
你需要事先判斷這種粗核情況。
⑧ 如何把sql語句查詢到的值賦值給變數
//多行
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("server=.;database=你的資料庫的名字;uid=sa;pwd=sa的密碼;");
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.Connection = conn;
cmd.CommandText="select 欄位A from 表B where years=2000 and months=2";
conn.Open();
System.Data.SqlDataAdapter sda=new System.Data.SqlDataAdapter(cmd);
DataSet ds=new DataSet();
sda.Fill(ds,"dtResult");
conn.Close();
//結果在ds的dtResult中。
foreach(DataRow dr in ds.Tables["dtResult"])
{
Response.Write(dr["欄位A"].ToString()+"<br>");
}
-------------------------------------------------------------
System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection("server=.;database=你的資料庫的名字;uid=sa;pwd=sa的密碼;");
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand();
cmd.Connection = conn;
cmd.CommandText="select 欄位A from 表B where years=2000 and months=2";
conn.Open();
int i=Convert.ToInt32(cmd.ExecuteScalar().ToString());
conn.Close();
⑨ 如何在JDBC里調用PLSQL創建的存儲過程
import oracle.jdbc.*;
import oracle.sql.*;
import java.sql.*;
public class ReturnIndexTable
{
Connection ociconn=null;
OracleCallableStatement stmt =null;
public String[] getTable(String in_param)
{
String[] reAry=null;
try
{
OracleDriver S_Driver=null;
if(S_Driver==null)
S_Driver=new oracle.jdbc.OracleDriver();
DriverManager.registerDriver(S_Driver);
String url="jdbc:oracle:oci8:@test";
String user="user";
String password=" password";
ociconn= DriverManager.getConnection(url,user,password);
stmt =(OracleCallableStatement)ociconn.prepareCall("begin yejf_count(?,?); end;");
// 返回的索引表最大長度(可以大於索引表實際長度)
int maxLen =31;
// 索引表元素類型
int elemSqlType = OracleTypes.VARCHAR;
//索引表元素長度(CHAR, VARCHAR or RAW),其它元素類型可忽略該項值,但該參數仍須定義
int elemMaxLen=50;
stmt.setString(1,in_param);
// 注冊返回參數
stmt.(2,maxLen,elemSqlType,elemMaxLen);
stmt.execute();
// 返回數組類型
reAry=(String[])stmt.getPlsqlIndexTable(2);
}
catch (Exception e)
{e.printStackTrace();
}
finally
{return reAry;
}
}
//關閉連接.............
}
⑩ C#代碼中要執行2個存儲過程,那麼是應該寫2個try2個catch還是1個try,1個catch
看你要怎麼執行了
第一種方式,如果存儲過程晌李1失敗或謹圓了, 不會影衫塌響到存儲過程2
第二種方式, 存儲過程2執行的前提,必須是存儲過程1執行成功