在没有使用EF的情况下,访问Oracle数据库可以引用微软提供的System.Data.OracleClient或者Oracle提供的Oracle.ManagedDataAccess.Client。因此对于OracleTransaction的使用方法也会有不同,需要注意的是,尽量使用Oracle.ManagedDataAccess.Client,因为微软在未来的版本不会再支持System.Data.OracleClient。
微软文档:https://docs.microsoft.com/en-us/dotnet/api/system.data.oracleclient.oracletransaction?view=netframework-4.8
Oracle文档:https://docs.oracle.com/database/121/ODPNT/OracleTransactionClass.htm#ODPNT2214
如果在数据插入分成多个部分,任何一部分的失败整个流程的数据都不应该插入到数据库,或者插入数据的步骤包括了代码的操作和存储过程的操作,这时就需要使用Transaction。
主要使用:BeginTransaction,Commit和Rollback
需要对command的Transaction进行赋值
public void RunOracleTransaction(string connectionString)
{
using (OracleConnection connection = new OracleConnection(connectionString))
{
connection.Open();
OracleCommand command = connection.CreateCommand();
OracleTransaction transaction;
// Start a local transaction
transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
// Assign transaction object for a pending local transaction
command.Transaction = transaction;
try
{
command.CommandText =
"INSERT INTO Dept (DeptNo, Dname, Loc) values (50, 'TECHNOLOGY', 'DENVER')";
command.ExecuteNonQuery();
command.CommandText =
"INSERT INTO Dept (DeptNo, Dname, Loc) values (60, 'ENGINEERING', 'KANSAS CITY')";
command.ExecuteNonQuery();
transaction.Commit();
Console.WriteLine("Both records are written to database.");
}
catch (Exception e)
{
transaction.Rollback();
Console.WriteLine(e.ToString());
Console.WriteLine("Neither record was written to database.");
}
}
}
Oracle.ManagedDataAccess.Client下的OracleTransaction
不需要对command的Transaction进行赋值,默认使用当前Connection中的Transaction.
using Oracle.ManagedDataAccess.Client;
class OracleTransactionSample
{
static void Main()
{
string constr = "User Id=scott;Password=tiger;Data Source=oracle";
OracleConnection con = new OracleConnection(constr);
con.Open();
OracleCommand cmd = con.CreateCommand();
// Check the number of rows in MyTable before transaction
cmd.CommandText = "SELECT COUNT(*) FROM MyTable";
int myTableCount = int.Parse(cmd.ExecuteScalar().ToString());
// Print the number of rows in MyTable
Console.WriteLine("myTableCount = " + myTableCount);
// Start a transaction
OracleTransaction txn = con.BeginTransaction(
IsolationLevel.ReadCommitted);
try
{
// Insert the same row twice into MyTable
cmd.CommandText = "INSERT INTO MyTable VALUES (1)";
cmd.ExecuteNonQuery();
cmd.ExecuteNonQuery(); // This may throw an exception
txn.Commit();
}
catch (Exception e)
{
// Print the exception message
Console.WriteLine("e.Message = " + e.Message);
// Rollback the transaction
txn.Rollback();
}
// Check the number of rows in MyTable after transaction
cmd.CommandText = "SELECT COUNT(*) FROM MyTable";
myTableCount = int.Parse(cmd.ExecuteScalar().ToString());
// Prints the number of rows
// If MyColumn is not a PRIMARY KEY, the value should increase by two.
// If MyColumn is a PRIMARY KEY, the value should remain same.
Console.WriteLine("myTableCount = " + myTableCount);
txn.Dispose();
cmd.Dispose();
con.Close();
con.Dispose();
}
}
如果在事务中包含了对存储过程的操作,那么在存储过程中不要使用commit,否则会导致所有数据的更新。如果一定在存储过程中使用commit,则应该使用自主事务:AUTONOMOUS_TRANSACTION
当调用自主事务时,主事务被挂起。 自主事务完全独立于主事务:它们不共享锁,资源或提交依赖项。 自主交易不影响主交易。
自主事务提交时,自主事务所做的更改对其他事务可见。 仅当主事务的隔离级别为READ COMMITTED(缺省)时,它们才对主事务恢复可见。
使用方法
CREATE PROCEDURE lower_salary (emp_id NUMBER, amount NUMBER) AS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
UPDATE employees SET salary =
salary - amount WHERE employee_id = emp_id;
COMMIT;
END lower_salary;
详细介绍参考Oracle官方文档:https://docs.oracle.com/cd/B28359_01/appdev.111/b28370/autotransaction_pragma.htm#LNPLS01302