奇怪的问题。我有一个托管的OPD.Net应用程序,它调用存储过程来插入记录。当我正常调用该过程并回滚事务时,记录不会保存到表中(呃!)。当我使用带参数数组绑定的过程并仍然回滚事务时,记录将保存到表中。不知何故,即使我做回滚,记录也会被提交!
TEST Schema:
people loves ocean looks fire and enjoy forest
测试代码:
CREATE TABLE TEST
(
ID NUMBER(15,0),
VALUE VARCHAR2(50 CHAR)
)
/
CREATE SEQUENCE TEST_ID_SEQ
INCREMENT BY 1
START WITH 50
MINVALUE 1
MAXVALUE 999999999999999
NOCYCLE
NOORDER
CACHE 100
/
CREATE OR REPLACE PROCEDURE TEST_INSERT
(
iVALUE IN VARCHAR2,
oID OUT NUMBER
)
AS
BEGIN
oID := TEST_ID_SEQ.NEXTVAL;
INSERT INTO TEST
(
ID,
VALUE
)
VALUES
(
oID,
iVALUE
);
END;
/
首先运行控制台输出:
using Oracle.ManagedDataAccess.Client;
using Oracle.ManagedDataAccess.Types;
using System;
using System.Data;
namespace OdpTestArrayBinding
{
class Program
{
private const string cConnectioString = "Data Source=DB_DEV;User Id=TMP;Password=sqlsql";
static void Main(string[] args)
{
using (OracleConnection lConnectionA = new OracleConnection(cConnectioString))
{
lConnectionA.StateChange += ConnectionStateChanged;
lConnectionA.Open();
Console.WriteLine($"[Connection={lConnectionA.GetHashCode()}] Connection opened.");
int lStartCount = CountTestTableRows(lConnectionA);
Console.WriteLine($"[Connection={lConnectionA.GetHashCode()}] Number of rows in table at start is {lStartCount}.");
using (OracleTransaction lTransaction = lConnectionA.BeginTransaction())
{
Console.WriteLine($"[Connection={lConnectionA.GetHashCode()}] Transaction started.");
try
{
using (OracleCommand lCmd = new OracleCommand())
{
lCmd.Connection = lConnectionA;
lCmd.BindByName = true;
lCmd.CommandType = System.Data.CommandType.StoredProcedure;
lCmd.CommandText = "TEST_INSERT";
lCmd.Parameters.Add("iVALUE", OracleDbType.Varchar2, ParameterDirection.Input);
// The OracleDbType of the output does not seem to matter, the actual value is always OracleDecimal
lCmd.Parameters.Add("oID", OracleDbType.Int64, ParameterDirection.Output);
lCmd.ArrayBindCount = 3;
lCmd.Parameters["iVALUE"].Value = new string[] { "Foo", "Bar", "Boo" };
// Not required.
//lCmd.Parameters["oID"].Value = new long[] { -1, -1, -1 };
lCmd.ExecuteNonQuery();
OracleDecimal[] lOutIds = (OracleDecimal[])lCmd.Parameters["oID"].Value;
Console.WriteLine($"[Connection={lConnectionA.GetHashCode()}] Inserted 3 rows using stored procedure, out ID vales are {string.Join(",", lOutIds)}.");
}
ListRows(lConnectionA, lStartCount + 3);
using (OracleConnection lConnectionB = new OracleConnection(cConnectioString))
{
lConnectionB.StateChange += ConnectionStateChanged;
lConnectionB.Open();
Console.WriteLine($"[Connection={lConnectionB.GetHashCode()}] Connection opened.");
ListRows(lConnectionB, lStartCount);
}
}
finally
{
lTransaction.Rollback();
Console.WriteLine($"[Connection={lConnectionA.GetHashCode()}] Transaction rolled back.");
}
}
}
Console.WriteLine("Press the ENTER key to continue...");
Console.ReadLine();
}
private static void ConnectionStateChanged(object sender, StateChangeEventArgs e)
{
Console.WriteLine($"[Connection={sender.GetHashCode()}] State changed from {e.OriginalState} to {e.CurrentState}.");
}
private static int CountTestTableRows(OracleConnection aConnection)
{
using (OracleCommand lCmd = new OracleCommand())
{
lCmd.Connection = aConnection;
lCmd.BindByName = true;
lCmd.CommandType = System.Data.CommandType.Text;
lCmd.CommandText = "SELECT COUNT(*) FROM TEST";
return Convert.ToInt32(lCmd.ExecuteScalar());
}
}
private static void ListRows(OracleConnection aConnection, int aExpectedRowCount)
{
int lCount = CountTestTableRows(aConnection);
Console.Write($"[Connection={aConnection.GetHashCode()}] Number of rows in table {lCount}");
if (lCount == aExpectedRowCount)
Console.WriteLine(" (Test passed, actual and expected row count are the same).");
else
Console.WriteLine($" (Test FAILED!, expected {aExpectedRowCount} rows).");
}
}
}
我尝试过Oracle.ManagedDataAccess.dll 4.121.2.20141216(ODAC RELEASE 3)和4.121.2.20150926(ODAC RELEASE 4),两者都给出了相同的结果。任何想法或解决方法?
答案 0 :(得分:0)
请检查您的命令:您忘记在命令上分配事务了吗?
lCmd.Connection = lConnectionA;
// Assign transaction to your command
lCmd.Transaction = lTransaction;
答案 1 :(得分:0)
您是否可以尝试更改代码以使用此示例。 只打开一个使用块进行连接。
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.");
}
}
}
答案 2 :(得分:0)
您应该创建一个TransactionScope
来包装数据库连接,并在您的TransactionScope
内,尝试加入环境事务:
<your connection object>.EnlistTransaction(Transaction.Current);