/**************************************************************************
@author : Jagriti
@version : 1.0
Development
Environment : Microsoft Visual Studio .Net
Name of the
File : SavepointSample.cs
Creation/Modification
History :
Jagriti 22-Oct-2002
Created
Sample Overview:
This sample aims
at demostrating how Nested Transactions can be done using
Savepoints in
ODP.NET. Savepoints can be used to identify the point in a
transaction to
which the user can later rollback.
In this sample,
firstly a set of Savepoints viz. a, b and c with
Data
Manipulation Language(DML) operations is created.
Then the user is
given option to select a Savepoint to which he wishes to
rollback. Hence
demostrating how transactions can be rolled back to
intermediate
points by maintaining Savepoints. If more Savepoints exists,
then user can
further rollback or commit or rollback the transaction
completely.
After commit or rollback, the transaction enters a
completed state.
For more information on Savepoints refer Readme.html file
available with
this sample.
NOTE: The
insert, update, delete operations made to a database table data
are referred to DML(Data Manipulation
Language) operations.
**************************************************************************/
// Include
standard namespaces used in this sample
using System;
using System.Data;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
namespace SavepointSample
{
public class
SavepointSample
{
// For Database connection
OracleConnection
conn;
// Transaction object
OracleTransaction
myTransaction;
// Savepoint name
string saveptName;
/**************************************************************
*
This method is the entry point to this sample application.
*
Following tasks are done in this method:
*
1. A connection to database is established.
*
2. Deletes the existing data from products table, if any.
*
3. Starts transaction
*
4. Creates multiple Savepoints within DML Operations.
*
5. Provides user the option to rollback the transaction to a
* particular Savepoint. And then transaction
is rolled back
* upto the selected savepoint.
***************************************************************/
public static void Main()
{
// Instantiating this class
SavepointSample
savepointsample = new SavepointSample();
// Get database connection
if (savepointsample.getDBConnection())
{
// Deletes existing Products records, if any
savepointsample.deleteExistingProducts();
// Create Savepoints and perform DML operations
if (savepointsample.createSavepoints())
{
// Provides user
the option to rollback the transaction to a
// particular
Savepoint. Transaction is rolled back
// upto the
selected savepoint.
savepointsample.chooseSavepoint();
}
}
}
/***********************************************************
* The purpose of this method is to perform DML operations
* on database table and create intermediate Savepoints.
**********************************************************/
private Boolean createSavepoints()
{
try
{
// Calling BeginTransaction
on OracleConnection object
// creates an OracleTransaction object
myTransaction = conn.BeginTransaction();
Console.WriteLine("Transaction Started");
OracleCommand
cmd = new OracleCommand();
cmd.Connection = conn;
// DML operation #
1: without any Savepoint
string
cmdText1 = " INSERT INTO Products (Product_id, Product_name)" +
" VALUES (1,'Product
1')";
cmd.CommandText
= cmdText1;
cmd.ExecuteNonQuery();
Console.WriteLine("Inserted data for
Product 1");
Console.WriteLine("");
// Create Savepoint
'a'
myTransaction.Save("a");
Console.WriteLine("Created Savepoint
a");
// DML operation #
2: In Savepoint 'a'
string
cmdText2 = " INSERT INTO Products (Product_id, Product_name) " +
" VALUES (2,'Product 2
')";
cmd.CommandText = cmdText2;
cmd.ExecuteNonQuery();
Console.WriteLine("Inserted data for
Product 2");
Console.WriteLine("");
// Create Savepoint
'b'
myTransaction.Save("b");
Console.WriteLine("Created Savepoint
b");
// DML operation #
3: In Savepoint 'b'
string
cmdText3 = " INSERT INTO Products (Product_id, Product_name) " +
" VALUES (3,'Product
3')";
cmd.CommandText = cmdText3;
cmd.ExecuteNonQuery();
Console.WriteLine("Inserted data for
Product 3");
Console.WriteLine("");
// Create Savepoint
'c'
myTransaction.Save("c");
Console.WriteLine("Created Savepoint
c");
// DML operation #
4: In Savepoint 'c'
string
cmdText4 = " INSERT INTO Products (Product_id, Product_name) " +
" VALUES (4,'Product
4')";
cmd.CommandText = cmdText4;
cmd.ExecuteNonQuery();
Console.WriteLine("Inserted data for
Product 4");
Console.WriteLine("");
// Release all
resources held by OracleCommand Object
cmd.Dispose();
return true;
}
catch (Exception ex)
{
Console.WriteLine("Execution
Failed" + ex);
conn.Close();
conn.Dispose();
return false;
}
}
/*********************************************************************
* The purpose of this method is to provide user to choose option
of
* selecting the Savepoint to which he wishes to rollback.
*/
private void
chooseSavepoint()
{
try
{
// Display message to user to type a Savepoint name upto
which he wishes to rollback
Console.WriteLine("");
Console.WriteLine("Type
the Savepoint name (a or b or c) upto which you wish to rollback the
transaction :");
Console.WriteLine("");
// Save user's input to a temporary variable
saveptName =
Console.ReadLine().ToLower();
// Accept user's input if given as 'a', 'b', 'c'. Else
display error
// message
if (saveptName ==
"a" || saveptName == "b" || saveptName ==
"c")
{
// Call
'rollbackSavepoint' method to rollback
// to a particular
Savepoint.
// Note: Savepoint
name name is case insensitive
rollbackSavepoint(saveptName.ToLower()) ;
}
else
{
// If Savepoint
does not exists
Console.WriteLine("Invalid Savepoint name");
chooseSavepoint();
}
}
catch (Exception ex)
{
Console.WriteLine("Execution Failed:
"+ ex);
conn.Close();
conn.Dispose();
}
}
/********************************************************************************
* Following is the purpose of this method
* 1. Perform rollback to a particular Savepoint.
* 2. After rollback, provide option for further commit or rollback
for completing
* the transaction.
********************************************************************************/
private void
rollbackSavepoint(string saveptName)
{
try
{
// Rollback to
the Savepoint, given by user
myTransaction.Rollback(saveptName);
Console.WriteLine("The transaction
has been rolled back upto Savepoint '" + saveptName + "'");
Console.WriteLine("-----------------------------------------------------------------");
// Prompt user
if he wishes to further commit or rollback
if
(saveptName == "c")
{
Console.WriteLine("Savepoints 'a',
'b' exists, type Savepoint name (a or b) if you wish to further rollback
!");
}
else if (saveptName == "b")
{
Console.WriteLine("Savepoint 'a'
exists, type Savepoint name (a) if you wish to further rollback !");
}
Console.WriteLine("Type 'commit' if
you wish to commit changes");
Console.WriteLine("Else all changes
will be rolled back");
String input =
Console.ReadLine().ToLower();
// If user
wishes to further rollback to a particular Savepoint or
// wishes to
commit data to Products table,
// or wishes to
rollback the transaction completely
if ((input
== "b" && saveptName != "b") || (input ==
"a" && saveptName != "a"))
{
saveptName = input;
rollbackSavepoint(saveptName.ToLower());
}
else if (input.ToLower() == "commit" )
{
myTransaction.Commit();
Console.WriteLine("Transaction has
been committed !");
}
else
{
myTransaction.Rollback();
Console.WriteLine("Transaction has
been rolled back !");
}
}
catch (Exception ex)
{
Console.WriteLine("Execution
Failed" + ex);
}
finally
{
// Release
resources held by connection object
conn.Close();
conn.Dispose();
}
}
/**************************************************************************
* The purpose of this method is to delete any existing records
from
* Products table.
*************************************************************************/
void deleteExistingProducts()
{
try
{
// Perform initial
cleanup for Products table.
Console.WriteLine("Deleting existing
records from Products table...");
OracleCommand cmd = new
OracleCommand(" DELETE FROM products", conn);
cmd.ExecuteNonQuery();
Console.WriteLine("Initial cleanup
done!");
Console.WriteLine("");
cmd.Dispose();
}
catch (Exception ex)
{
Console.WriteLine("Execution failed :
" + ex);
conn.Close();
conn.Dispose();