Sie sind auf Seite 1von 19

Oracle and SQL Server 2000 Database Transactions using .

NET Framework
with C# and Sql Server and Oracle Data Provider

Introduction

Summary

Implementing a basic transaction using ADO.NET in an application can be fairly straightforward. The most
common sequence of steps that would be performed while developing a transactional application is as follows:

o Open a database connection using the Open method of the connection object.
o Begin a transaction using the BeginTransaction method of the connection object. This
method provides us with a transaction object that we will use later to commit or rollback the
transaction. Note that changes caused by any queries executed before calling the
BeginTransaction method will be committed to the database immediately after they execute.
o Set the Transaction property of the command object to the above mentioned transaction
object.
o Execute the SQL commands using the command object. We may use one or more
command objects for this purpose, as long as the Transaction property of all the objects is set to a
valid transaction object.
o Commit or roll back the transaction using the Commit or Rollback method of the
transaction object.
o Close the database connection.

A data provider in the .NET Framework serves as a bridge between an application and a data source. A .NET
Framework data provider enables you to return query results from a data source, execute commands at a data
source, and propagate changes in a DataSet to a data source. This article includes tips on which .NET Framework
data provider is best suited for your needs.

2. Available .NET Framework Data Providers

Which .NET Framework Data Provider to Use?

To achieve the best performance for your application, use the .NET Framework data provider that is most
appropriate for your data source. There are a number of data provider options for use in your applications. The
following table provides information about the available data providers and which data sources a data provider is
most appropriate for.

Provider Details
SQL Server .NET Data Found in the System.Data.SqlClient namespace.
Provider
Recommended for middle-tier applications using Microsoft SQL Server version
7.0 or later.

Recommended for single-tier applications using the Microsoft Data Engine


(MSDE) or Microsoft SQL Server 7.0 or later.
OLE DB .NET Data Provider Found in the System.Data.OleDb namespace.

Recommended for middle-tier applications using Microsoft SQL Server 6.5 or


earlier, or any OLE DB provider that supports the OLE DB interfaces listed in
OLE DB Interfaces Used by the OLE DB .NET Data Provider in the .NET
Framework SDK.

For Microsoft SQL Server 7.0 or later, the .NET Framework Data Provider for
SQL Server is recommended.
Recommended for single-tier applications using a Microsoft® Access database.
Use of an Access database for a middle-tier application is

not recommended.
ODBC .NET Data Provider Found in the Microsoft.Data.Odbc namespace.

The ODBC .NET Data Provider is available for download.

Provides access to data sources that are connected to using an ODBC driver.
Oracle .NET Data Provider Found in the System.Data.OracleClient namespace.

The .NET Framework Data Provider for Oracle, unlike the Microsoft OLE DB
provider for Oracle, also supports new Oracle 9i datatypes, as well as ref
cursors (useful for running Oracle stored procedures that return result sets).
This provider, System.Data.OracleClient, is similar to the .NET Framework
Data Provider for SQL Server, System.Data.SqlClient.

The Oracle .NET Data Provider is available for download


3. Setup of the .NET Framework

The Microsoft® .NET Framework is the infrastructure for the overall .NET Platform. The common language runtime
and class libraries (including Microsoft Windows® Forms, ADO.NET, and ASP.NET) combine to provide services
and solutions that can be easily integrated within and across a variety of systems.

The .NET Framework provides a fully managed, protected, and feature-rich application execution environment,
simplified development and deployment, and seamless integration with a wide variety of languages.

Microsoft .NET Framework Software Development Kit

The Microsoft® .NET Framework Software Development Kit (SDK) includes the .NET Framework, as well as
everything you need to write, build, test, and deploy .NET Framework applications - documentation, samples, and
command-line tools and compilers.

Download and Installation

Goto:

http://msdn.microsoft.com/downloads/

Select:

-> Software Development Kits


-> Microsoft .NET Framework SDK

You'll get the whole framework and a C# command line compiler. Run the downloaded setup.exe if you haven't
installed yet Microsoft .NET and follow the installation steps. You will be asked for Server Components which you
don't need. If the installation asks for Microsoft Data Access Components MDAC you may continue or quit the
installation. Anyway, you need to install MDAC 2.7 or higher prior ODBC data access is going to work.

4. Transactions using SqlClient Data Provider to access SQL Server 2000

The SqlClient provider ships with ADO.NET and resides in the System.Data.SqlClient namespace. It should be
used to access SQL Server 2000. The classes within SqlClient provider all begin with "Sql", so the connection class
is SqlConnection, the command class is SqlCommand, and so on. Lets look at an example to update SQL Server
2000.

using System;
using System.Data;
using System.Data.SqlClient;

namespace TranDemoSqlClient
{
class TranDemoSqlClient
{
static void Main(string[] args)
{
// Declare database objects such as connection,
// command and transaction
string connectionString = "server=localhost;"
+ "database=Northwind;uid=sa;pwd=manager";
SqlConnection cnn;
SqlCommand cmd;
SqlTransaction tran;

// Open a connection to SQL Server 2000


cnn = new SqlConnection(connectionString);
cnn.Open();

// Begin the transaction


tran = cnn.BeginTransaction();

// Configure command object to use the transaction


cmd=new SqlCommand();
cmd.Connection=cnn;
cmd.Transaction=tran;

// Put transaction commands in a try ... catch block


try
{
// INSERT row in Orders Table
cmd.CommandText = "INSERT INTO Orders " +
"(CustomerID,OrderDate,RequiredDate) " +
"VALUES('ALFKI',GetDate(),DATEADD(d,15,GetDate()))";
long rows = cmd.ExecuteNonQuery();
Console.WriteLine("Rows inserted in Orders: {0} ", rows);

// Get and Store IDENTITY (Primary Key) for further


// INSERTS in child table [Order Details]
cmd.CommandText = "SELECT @@identity";
string id = cmd.ExecuteScalar().ToString();

// INSERT row in [Order Details]


cmd.CommandText = "INSERT INTO [Order Details] " +
"(OrderID,ProductID,UnitPrice,Quantity) " +
"VALUES(" + id + ",1,18,25)";
rows = cmd.ExecuteNonQuery();
Console.WriteLine("Rows inserted in [Order Details]: {0} ", rows);

// UPDATE Orders Table with values from commandline


string customerid = args[0];
decimal freight = decimal.Parse(args[1]);

string query="UPDATE Orders SET freight = "


+ freight + " WHERE customerid = '" + customerid + "'";
cmd.CommandText = query;
rows = cmd.ExecuteNonQuery();
Console.WriteLine("Rows updated in [Orders]: {0} ", rows);

// Commit the transaction ....


tran.Commit();
Console.WriteLine("Commit complete");
}
// ... or Rollback everything in case of an error
catch(Exception e)
{
tran.Rollback();
Console.WriteLine("Transaction failed - Rolled Back!");
Console.WriteLine(e.Message);
}
}
}
}

This file is called TranDemoSqlClient.cs, we can compile it from the command line simply by typing csc
TranDemoSqlClient.cs. There is no need to add any references.

7. Transactions using Oracle .NET Data Provider to access Oracle 9i

Introduction

If you are building applications using Microsoft® .NET against an Oracle backend database, you will want to take a
close look at the new .NET Framework Data Provider for Oracle released on MSDN in June 2002. The goal of the
provider is to boost the performance and scalability of .NET applications with Oracle databases by providing a
native .NET interface to Oracle databases that bypasses the need to use an OLE DB provider.

The .NET Framework Data Provider for Oracle, unlike the Microsoft OLE DB provider for Oracle, also supports new
Oracle 9i datatypes, as well as ref cursors (useful for running Oracle stored procedures that return result sets).
This provider, System.Data.OracleClient, is similar to the .NET Framework Data Provider for SQL Server,
System.Data.SqlClient.

Using ADO.NET with Oracle


Until recently, the primary mechanism developers used to access Oracle databases from .NET application was OLE
DB, channeling database requests through the System.Data.OleDb data classes. However, developers writing .NET
data-driven applications against SQL Server have been able to take advantage of the super-fast
System.Data.SqlClient data classes, which provide data access to SQL Server via a SQL Server provider written in
managed .NET code. This provider communicates to SQL Server via the native SQL Server client libraries, and
derives very fast speeds. While OLE DB provided an adequate data access mechanism for .NET applications to
communicate with Oracle backends, certainly developers have been asking for a faster, more scalable Oracle data
access mechanism to get better performance for the .NET applications. The new .NET Framework Data Provider
for Oracle, recently released on MSDN, provides just this.

Basically, developers now have a much faster database access mechanism for ADO.NET in the form of new
System.Data.OracleClient framework classes that work in much the same way as the System.Data.SqlClient
classes. In both cases, the fastest database read mechanism will be ADO.NET Data Readers, as opposed to
Data Sets, although both are fully functional using the new Oracle Managed Provider. The good news is the new
OracleClient classes should provide significant performance improvements for .NET applications, and migrating
code between OLE DB data classes and OracleClient data classes is not very difficult, although some work is
required. However, the performance boost can be dramatic.

Where Is the Performance Boost Coming From?

The OLE DB client classes are designed to provide a database-independent layer for accessing generic databases.
While the value of a generic layer is nearly universal access, it is difficult to deliver database-specific optimizations
in this generic access layer. Also, the OLE DB layer is implemented as a COM library, so the System.Data.Oledb
namespace works through COM interop. To achieve the significant performance boost described here, the .NET
Framework Data Provider for Oracle avoids the cost of COM interop, and also employs Oracle-specific
optimizations.

Installation and Configuration

The Microsoft® .NET Framework Data Provider for Oracle is an add-on component to the Microsoft .NET
Framework that provides access to an Oracle database using the Oracle Call Interface (OCI) as provided by
Oracle Client software. Oracle 8i Release 3 (8.1.7) Client or later must be installed for this provider to function.

The Oracle .NET Data Provider is available for download

The following files are installed by Setup:

File name Description


Eula.rtf .NET Framework Data Provider for Oracle end-user license agreement.
Oracleref.chm .NET Framework Data Provider for Oracle documentation.
Oracleref.chi Index file that accompanies Oracleref.chm (.NET Framework Data Provider for
Oracle documentation).
Readme.txt Additional product information that is not contain in Oracleref.chm (.NET
Framework Data Provider for Oracle documentation).
System.Data.OracleClient.dll The .NET Framework Data Provider for Oracle.
Mtxoci8.dll DLL that provides distributed transaction support.

All of these files, except Mtxoci8.dll, are installed in C:\Program Files\Microsoft.NET\OracleClient.Net by default
(assuming that C:\Program Files is your default Program Files folder location). Mtxoci8.dll is installed in the
windows system directory (for example, C:\Windows\System32 on a Windows 2000 computer on which C: is the
system drive).

As part of Setup, the System.Data.OracleClient namespace is added to the global assembly cache.
The classes that compose the provider are in the System.Data.OracleClient namespace and all have the prefix
"Oracle". Lets look at an example to update Oracle 9.2.0.

using System;
using System.Data;
using System.Data.OracleClient;

namespace TranDemoOra
{
class TranDemoOra
{
static void Main(string[] args)
{
// Declare database objects such as connection,
// command and transaction
string connectionString = "Data Source=ARK2;"
+ "User ID=scott; Password=tiger";
OracleConnection cnn;
OracleCommand cmd;
OracleTransaction tran;

// Open a connection to Oracle 9i


cnn=new OracleConnection(connectionString);
cnn.Open();

// Begin the transaction


tran=cnn.BeginTransaction();

// Configure command object to use the transaction


cmd=new OracleCommand();
cmd.Connection=cnn;
cmd.Transaction=tran;

// Put transaction commands in a try ... catch block


try
{

// UPDATE EMP Table with values from commandline


int empno=int.Parse(args[0]);
string job=args[1];

string query="UPDATE emp SET job = '"


+ job + "' WHERE empno = " + empno;
cmd.CommandText=query;
long rows = cmd.ExecuteNonQuery();

// Commit the transaction ....


tran.Commit();
Console.WriteLine("Commit complete, {0} ", rows + " Rows updated");
}

// ... or Rollback everything in case of an error


catch(Exception e)
{
tran.Rollback();
Console.WriteLine("Transaction failed - Rolled Back!");
Console.WriteLine(e.Message);
}
}
}
}
This file is called TranDemoOra.cs, we can compile it from the command line by typing csc
/r:System.Data.OracleClient.dll TranDemoOra.cs. The reference to the System.Data.OracleClient.dll is needed.

Introduction

The examples used in this article uses the Pubs database that comes as a sample database when you install SQL
Server. If you need to rebuild the Pubs database, follow the steps to install a fresh copy :

a. Run the osql command prompt utility and detach the Pubs database from SQL Server by using the
sp_detach_db system stored procedure.

osql -U sa -P "" -Q "exec sp_detach_db 'Pubs'"

b. Delete the database files for pubs database (pubs.mdf, pubs_log.ldf). These files are located in the \Data
directory.

c. Re-creating the Pubs database requires the Instpubs.sql script to be executed. Run the script from the
command line (if the .sql files are in a different directory, adjust the path accordingly). You can also run
this script file from the Query Analyzer.
d. osql -U sa -P "" -i
"C:\Program Files\Microsoft SQL Server\MSSQL\Install\InstPubs.sql"

(The osql utility uses case-sensitive options. If neither the -U or -P options are used, SQL Server 2000
attempts to connect using Windows Authentication Mode. More information about the osql Utility can be
found in the Sql Server Books Online)

Transactions

Transactions group a set of tasks into a single execution unit. Each transaction begins with a specific task and
ends when all the tasks in the group successfully complete. If any of the tasks fails, the transaction fails.
Therefore, a transaction has only two results: success or failure. Incomplete steps result in the failure of the
transaction.

Users can group two or more Transact-SQL statements into a single transaction using the following statements:
• Begin Transaction
• Rollback Transaction
• Commit Transaction

If anything goes wrong with any of the grouped statements, all changes need to be aborted. The process of
reversing changes is called rollback in SQL Server terminology. If everything is in order with all statements
within a single transaction, all changes are recorded together in the database. In SQL Server terminology, we say
that these changes are committed to the database.

Here is an example of a transaction :

USE pubs

DECLARE @intErrorCode INT

BEGIN TRAN
UPDATE Authors
SET Phone = '415 354-9866'
WHERE au_id = '724-80-9391'

SELECT @intErrorCode = @@ERROR


IF (@intErrorCode <> 0) GOTO PROBLEM

UPDATE Publishers
SET city = 'Calcutta', country = 'India'
WHERE pub_id = '9999'

SELECT @intErrorCode = @@ERROR


IF (@intErrorCode <> 0) GOTO PROBLEM
COMMIT TRAN

PROBLEM:
IF (@intErrorCode <> 0) BEGIN
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
END

Before the real processing starts, the BEGIN TRAN statement notifies SQL Server to treat all of the following
actions as a single transaction. It is followed by two UPDATE statements. If no errors occur during the updates, all
changes are committed to the database when SQL Server processes the COMMIT TRAN statement, and finally the
stored procedure finishes. If an error occurs during the updates, it is detected by if statements and execution is
continued from the PROBLEM label. After displaying a message to the user, SQL Server rolls back any changes
that occurred during processing. Note: Be sure to match BEGIN TRAN with either COMMIT or ROLLBACK.

Nested Transactions

SQL Server allows you to nest transactions. Basically, this feature means that a new transaction can start even
though the previous one is not complete. Transact-SQL allows you to nest transaction operations by issuing
nested BEGIN TRAN commands. The @@TRANCOUNT automatic variable can be queried to determine the level of
nesting - 0 indicates no nesting , 1 indicates nesting one level deep, and so fourth.

A COMMIT issued against any transaction except the outermost one doesn't commit any changes to disk - it
merely decrements the@@TRANCOUNT automatic variable. A ROLLBACK, on the other hand, works regardless of
the level at which it is issued, but rolls back all transactions, regardless of the nesting level. Though this is
counterintuitive, there's a very good reason for it. If a nested COMMIT actually wrote changes permanently to
disk, an outer ROLLBACK wouldn't be able to reverse those changes since they would already be recorded
permanently.
When you explicitly begin a transaction, the @@TRANCOUNT automatic variable count increases from 0 to 1;
when you COMMIT, the count decreases by one; when you ROLLBACK, the count is reduced to 0. As you see, the
behavior of COMMIT and ROLLBACK is not symmetric. If you nest transactions, COMMIT always decreases the
nesting level by 1, as you can see illustrated in Figure 1. The ROLLBACK command, on the other hand, rolls back
the entire transaction, illustrated in Figure 2. This asymmetry between COMMIT and ROLLBACK is the key to
handling errors in nested transactions.

Figure 1: A COMMIT always balances a BEGIN TRANSACTION by reducing the transaction count by one.

Figure 2: A single ROLLBACK always rolls back the entire transaction.

As you can see from Figure 1 and Figure 2, you can nest transactions and use the @@TRANCOUNT automatic
variable to detect the level. You also learned that COMMIT and ROLLBACK do not behave symmetrically; COMMIT
just decreases the value of @@TRANCOUNT, while ROLLBACK resets it to 0. The implication is that a transaction is
never fully committed until the last COMMIT is issued. No matter how deeply you nest a set of transactions, only
the last COMMIT has any effect.

Here is an example of a nested transaction :

USE pubs
SELECT 'Before BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 0
BEGIN TRAN
SELECT 'After BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 1
DELETE sales
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 2
DELETE titleauthor
COMMIT TRAN nested
-- Does nothing except decrement the value of @@TRANCOUNT

SELECT 'After COMMIT TRAN nested', @@TRANCOUNT


-- The value of @@TRANCOUNT is 1
ROLLBACK TRAN

SELECT 'After ROLLBACK TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 0


-- because ROLLBACK TRAN always rolls back all transactions and sets
-- @@TRANCOUNT to 0.

SELECT TOP 5 au_id FROM titleauthor

In this example we see that despite the nested COMMIT TRAN, the outer ROLLBACK still reverses the effects of
the DELETE titleauthor command.

Here is another similar example of nested transaction :

USE pubs
SELECT 'Before BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 0
BEGIN TRAN
SELECT 'After BEGIN TRAN', @@TRANCOUNT -- The value of @@TRANCOUNT is 1
DELETE sales
BEGIN TRAN nested
SELECT 'After BEGIN TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 2
DELETE titleauthor
ROLLBACK TRAN

SELECT 'After COMMIT TRAN nested', @@TRANCOUNT


-- The value of @@TRANCOUNT is 0 because
-- ROLLBACK TRAN always rolls back all transactions and sets @@TRANCOUNT
-- to 0.

IF (@@TRANCOUNT > 0) BEGIN


COMMIT TRAN -- Never makes it here cause of the ROLLBACK
SELECT 'After COMMIT TRAN', @@TRANCOUNT
END

SELECT TOP 5 au_id FROM titleauthor

In this example, execution never reaches the out COMMIT TRAN because the ROLLBACK TRAN reverses all
transactions currently in progress and sets @@TRANCOUNT to 0. Unless ROLLBACK TRAN is called with a save
point, ROLLBACK TRAN always rolls back all transactions and sets @@TRANCOUNT to 0, regardless of the context
in which it's called.

SAVE TRAN and Save Points

Savepoints offer a mechanism to roll back portions of transactions. A user can set a savepoint, or marker, within a
transaction. The savepoint defines a location to which a transaction can return if part of the transaction is
conditionally canceled. SQL Server allows you to use savepoints via the SAVE TRAN statement, which doesn't
affect the @@TRANCOUNT value. A rollback to a savepoint (not a transaction) doesn't affect the value returned by
@@TRANCOUNT, either. However, the rollback must explicitly name the savepoint: using ROLLBACK TRAN
without a specific name will always roll back the entire transaction.

The following script demonstrates how savepoints can be used :

Collapse
USE pubs
SELECT 'Before BEGIN TRAN main', @@TRANCOUNT
-- The value of @@TRANCOUNT is 0

BEGIN TRAN main


SELECT 'After BEGIN TRAN main', @@TRANCOUNT
-- The value of @@TRANCOUNT is 1
DELETE sales
SAVE TRAN sales -- Mark a save point
SELECT 'After SAVE TRAN sales', @@TRANCOUNT
-- The value of @@TRANCOUNT is still 1

BEGIN TRAN nested


SELECT 'After BEGIN TRAN nested', @@TRANCOUNT
-- The value of @@TRANCOUNT is 2
DELETE titleauthor
SAVE TRAN titleauthor -- Mark a save point
SELECT 'After SAVE TRAN titleauthor', @@TRANCOUNT
-- The value of @@TRANCOUNT is still 2
ROLLBACK TRAN sales

SELECT 'After ROLLBACK TRAN sales', @@TRANCOUNT


-- The value of @@TRANCOUNT is still 2

SELECT TOP 5 au_id FROM titleauthor

IF (@@TRANCOUNT > 0) BEGIN


ROLLBACK TRAN
SELECT 'AFTER ROLLBACK TRAN', @@TRANCOUNT
-- The value of @@TRANCOUNT is 0 because
-- ROLLBACK TRAN always rolls back all transactions and sets @@TRANCOUNT
-- to 0.
END

SELECT TOP 5 au_id FROM titleauthor

Error Handling

The examples presented here are specific to stored procedures as they are the desired method of interacting with
a database. When an error is encountered within a stored procedure, the best you can do is halt the sequential
processing of the code and either branch to another code segment in the procedure or return processing to the
calling application. The @@ERROR automatic variable is used to implement error handling code. It contains the
error ID produced by the last SQL statement executed during a client’s connection. When a statement executes
successfully, @@ERROR contains 0. To determine if a statement executes successfully, an IF statement is used to
check the value of @@ERROR immediately after the target statement executes. It is imperative that @@ERROR
be checked immediately after the target statement, because its value is reset to 0 when the next statement
executes successfully. If a trappable error occurs, @@ERROR will have a value greater than 0. SQL Server resets
the @@ERROR value after every successful command, so you must immediately capture the @@ERROR value.
Most of the time, you'll want to test for changes in @@ERROR right after any INSERT, UPDATE, or DELETE
statement.

CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11),


@title VARCHAR(20), @title_type CHAR(12))
AS

BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)

IF (@@ERROR <> 0) BEGIN


PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
END

INSERT titleauthor(au_id, title_id)


VALUES (@au_id, @title_id)

IF (@@ERROR <> 0) BEGIN


PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1
END

COMMIT TRAN

RETURN 0

This kind of solution contains substantial repetition especially if your business logic requires more than two
Transact-SQL statements to be implemented. A more elegant solution is to group codes into a generic error
handling procedure:

CREATE PROCEDURE addTitle(@title_id VARCHAR(6), @au_id VARCHAR(11),


@title VARCHAR(20), @title_type CHAR(12))
AS

BEGIN TRAN
INSERT titles(title_id, title, type)
VALUES (@title_id, @title, @title_type)

IF (@@ERROR <> 0) GOTO ERR_HANDLER

INSERT titleauthor(au_id, title_id)


VALUES (@au_id, @title_id)

IF (@@ERROR <> 0) GOTO ERR_HANDLER

COMMIT TRAN

RETURN 0

ERR_HANDLER:
PRINT 'Unexpected error occurred!'
ROLLBACK TRAN
RETURN 1

COMMIT
Default Behavior COMMIT WORK WRITE IMMEDIATE WAIT;
Alter commit behavior for the ALTER SYSTEM SET COMMIT_WRITE = NOWAIT;
system ALTER SESSION SET COMMIT_WRITE = NOWAIT;
Alter commit behavior for the ALTER SYSTEM SET COMMIT_WRITE = NOWAIT;
session ALTER SESSION SET COMMIT_WRITE = NOWAIT;
COMMIT [WORK]
Complete a transaction
show autocommit

CREATE TABLE t0 (
testcol NUMBER);
INSERT INTO t0 (testcol) VALUES (1);

COMMIT;

INSERT INTO t0 (testcol) VALUES (2);

COMMIT WORK;
COMMIT COMMENT <comment_string_255_char>;
Comment Commit
CREATE TABLE t (
testcol NUMBER(2));

INSERT INTO t (testcol) VALUES (1);

COMMIT COMMENT 'Committing a test record';

-- if in-doubt distributed transaction


desc dba_2pc_pending

set linesize 121

SELECT local_tran_id, global_tran_id, state, mixed, advice, tran_comment


FROM dba_2pc_pending;

Write Force COMMIT WRITE FORCE <string>, <integer>;


INSERT INTO t (testcol) VALUES (2);
Manually force commitment of in-
doubt distributed transactions COMMIT WRITE FORCE;
COMMIT WRITE <WAIT | NOWAIT> BATCH;
Write Batch
INSERT INTO t (testcol) VALUES (3);
Buffer redo
COMMIT WRITE WAIT BATCH;
COMMIT WRITE <WAIT | NOWAIT> IMMEDIATE;
Write Immediate
INSERT INTO t (testcol) VALUES (4);
Initiate immediate LWGR action
COMMIT WRITE WAIT IMMEDIATE;

Write NoWait COMMIT WRITE NOWAIT


INSERT INTO t (testcol) VALUES (5);
Commit to return before the redo
is persistent in the redo log COMMIT WRITE NOWAIT;
Write Wait COMMIT WRITE WAIT

Commit will not return until the INSERT INTO t (testcol) VALUES (6);
corresponding redo is persistent
in the online redo log COMMIT WRITE WAIT;

ROLLBACK
ROLLBACK [WORK] [TO SAVEPOINT <savepoint_name>]
Undo a transaction
SELECT * FROM t0;

INSERT INTO t0 (testcol) VALUES (3);

SELECT * FROM t0;

ROLLBACK;

SELECT * FROM t0;


INSERT INTO t0 (testcol) VALUES (4);

SELECT * FROM t0;

ROLLBACK WORK;

SELECT * FROM t0;


SAVEPOINT
SAVEPOINT <savepoint id>
Return to a previous point in the
transaction The rollback short-cut 'roll' does not work with savepoint
CREATE TABLE t1 (
testcol NUMBER);

DECLARE
i INTEGER := 3;
BEGIN
INSERT INTO t1 (testcol) VALUES (10/i);

SAVEPOINT A;

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);
/*
i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);
*/
COMMIT;
EXCEPTION
WHEN ZERO_DIVIDE THEN
ROLLBACK TO SAVEPOINT A;
COMMIT;
END testblock;
/

SELECT * FROM t1;

TRUNCATE TABLE t1;

DECLARE
i INTEGER := 3;
BEGIN
INSERT INTO t1 (testcol) VALUES (10/i);

SAVEPOINT A;

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);

i := i-1;
INSERT INTO t1 (testcol) VALUES (10/i);

COMMIT;
EXCEPTION
WHEN ZERO_DIVIDE THEN
ROLLBACK TO SAVEPOINT A;
COMMIT;
END testblock;
/

SELECT * FROM t1;


SET TRANSACTION
SET TRANSACTION ISOLATION LEVEL <SERIALIZABLE | READ [COMMITED]>
Isolation Levels [NAME <string>];
TBD
SET TRANSACTION NAME <string>;
Naming Transactions
set transaction name 'UW_TRANS';
SET TRANSACTION READ <ONLY | WRITE>
Read Only Transactions
set transaction read only;

commit;

set transaction read only;

UPDATE servers
SET srvr_id = 501
WHERE srvr_id = 900;

rollback;

set transaction read write;

UPDATE servers
SET srvr_id = 501
WHERE srvr_id = 900;

commit;
Inconsistent States
The following refers to use of the DBMS_TRANSACTION built-in package:

Before automatic recovery runs, the transaction may show up in DBA_2PC_PENDING as state "collecting",
"committed", or "prepared". If the DBA has forced an in-doubt transaction to have a particular result by using
"commit force" or "rollback force", then states "forced commit" or "forced rollback" may also appear. Automatic
recovery will normally delete entries in any of these states. The only exception is when recovery finds a forced
transaction which is in a state inconsistent with other sites in the transaction; in this case, the entry will be left in
the table and the MIXED column will have a value 'yes'.

However, under certain conditions, it may not be possible for automatic recovery to run. For example, a remote
database may have been permanently lost. Even if it is recreated, it will get a new database id, so that recovery
cannot identify it (a possible symptom is ORA-02062). In this case, the DBA may use the procedure
purge_lost_db_entry to clean up the entries in any state other than "prepared". The DBA does not need to be in
any particular hurry to resolve these entries, since they will not be holding any database resources.

-- The following table indicates what the various states indicate about
-- the transaction and what the DBA actions should be:

Global Transaction Local Transaction Alternative DBA


State Column Normal DBA Action
State State Action
purge_lost_db_entry
collecting rolled back rolled back none
(1)
purge_lost_db_entry
committed committed committed none
(1)
force commit or
prepared unknown prepared none
rollback
purge_lost_db_entry
forced commit unknown committed none
(1)
purge_lost_db_entry
forced rollback unknown rolled back none
(1)
forced commit mixed mixed committed (2)
forced rollback mixed mixed rolled back (2)
(1) Use only if significant reconfiguration has occurred so that automatic recovery cannot resolve the transaction.
Examples are total loss of the remote database, reconfiguration in software resulting in loss of two-phase commit
capability, or loss of information from an external transaction coordinator such as a TP Monitor.
(2) Examine and take any manual action to remove inconsistencies, then use the procedure purge_mixed.

Demos
CREATE TABLE t2 (
testcol NUMBER);

CREATE OR REPLACE PROCEDURE spdemo (sp_in VARCHAR2) IS

BEGIN
INSERT INTO t2 (testcol) VALUES (1);
SAVEPOINT A;
INSERT INTO t2 (testcol) VALUES (2);
SAVEPOINT B;
INSERT INTO t2 (testcol) VALUES (3);
SAVEPOINT C;
INSERT INTO t2 (testcol) VALUES (4);
Dynamic Savepoints
EXECUTE IMMEDIATE 'ROLLBACK TO SAVEPOINT ' || sp_in;
COMMIT;
END spdemo;
/

exec spdemo('B');

SELECT * FROM t2;

TRUNCATE TABLE t2;

exec spdemo('C');

SELECT * FROM t2;


SELECT sequence#, first_change#, next_change#,
next_change#-first_change# AS chg_cnt,
first_time, next_time, (next_time-first_time)*1440 AS chg_min,
Estimate Transaction Rates
(next_change#-first_change#)/((next_time-first_time)*1440) AS chgs_per_min
FROM gv$archived_log
ORDER BY sequence#;

what is automonous tranction


An autonomous transaction is an independent transaction which can be committed independent of other
transactions. An autonomous transaction will be committed with out committing the other non-autonomous
transactions are committed.

The following exercise will help you to understand the difference between autonomous and normal transactions.

Create a table for the exercise.

create table test_table (a varchar2(50));

Create a non-autonomous procedure which will insert one row to this table.

CREATE OR REPLACE PROCEDURE non_autonomous_proc


IS
BEGIN
INSERT INTO test_table
VALUES ('Non Autnomous Insert');

COMMIT;
END;

Now execute the following code

DECLARE
BEGIN
INSERT INTO test_table
VALUES ('Before Non Autnomous Insert');

non_autonomous_proc;

INSERT INTO test_table


VALUES ('After Non Autnomous Insert');

ROLLBACK;
END;

Now query the table

select * from test_table;

As expected 2 rows will be retrieved

A
--------------------------------------------------
Before Non Autnomous Insert
Non Autnomous Insert

Now we will see the case of autonomous transaction.

Clear the test_table

delete from test_table;


commit;

Create an autonomous procedure which will insert one row to this table.
CREATE OR REPLACE PROCEDURE autonomous_proc
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO test_table
VALUES ('Autnomous Insert');

COMMIT;
END;

Now Execute the following code

DECLARE
BEGIN
INSERT INTO test_table
VALUES ('Before Autnomous Insert');

autonomous_proc;

INSERT INTO test_table


VALUES ('After Autnomous Insert');

ROLLBACK;
END;

And query the table

select * from test_table;

This will show only one row

A
--------------------------------------------------
Autnomous Insert

Conclusion

1) The commit statement in the autonomous procedure will commit the DML operations in the autonomous
procedure without commiting the transactions before that.

2) The rollback statement caused both the inserts before and after the autonomous transaction to be rolled back,
but not the autonomous transaction

we can use commit or rolback in trigger without error by using "PRAGMA AUTONOMOUS_TRANSACTION;" on
declaration section

CREATE TRIGGER anniversary_trigger


BEFORE INSERT ON employees FOR EACH ROW
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO anniversaries VALUES(TRUNC(:new.hire_date));
-- Only commits the preceding INSERT, not the INSERT that fired
-- the trigger.
COMMIT;
EXCEPTION
-- If someone else was hired on the same day, we get an exception
-- because of duplicate values. That's OK, no action needed.
WHEN OTHERS THEN NULL;
END;
/

Das könnte Ihnen auch gefallen