You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#三层架构中为两个方法实现Oracle事务

在三层架构中实现跨方法的Oracle事务

我来帮你搞定这个跨方法的Oracle事务问题,刚好之前在三层架构里处理过类似的场景!核心思路是让整个Cancel和Confirm操作共享同一个数据库连接和事务对象,把事务从UI层往下传递到BAL、DAL,确保所有数据库操作都在同一个事务范围内。

具体实现步骤

咱们一步步来拆解:

  1. 在UI层(Aspx.cs)初始化事务
    你需要在按钮点击事件里创建Oracle连接和事务,因为事务是绑定在连接上的,整个流程必须复用同一个连接。同时用using语句确保资源能正确释放。

  2. 将事务对象逐层传递
    把创建好的OracleTransaction对象作为参数,传递给BAL的Cancel、Confirm方法,再由BAL传递给对应的DAL方法。

  3. DAL层复用事务执行操作
    DAL里的数据库操作不再单独创建连接,而是使用事务关联的连接,并且把Command的Transaction属性设置为传入的事务对象。

  4. 统一处理事务的提交/回滚
    如果Cancel和Confirm都执行成功,就提交事务;只要其中任何一步抛出异常,就回滚事务,保证数据一致性。


代码示例

1. UI层(Aspx.cs的按钮点击事件)

protected void On_Cancel_Button_Click(object sender, EventArgs e)
{
    // 替换成你的Oracle连接字符串
    string connectionString = "Data Source=ORCL;User Id=yourUser;Password=yourPass;";
    
    using (OracleConnection conn = new OracleConnection(connectionString))
    {
        try
        {
            conn.Open();
            // 开始事务
            using (OracleTransaction transaction = conn.BeginTransaction())
            {
                // 实例化BAL类
                TicketBAL ticketBAL = new TicketBAL();
                
                // 调用Cancel方法,传入事务
                bool cancelSuccess = ticketBAL.CancelBooking(transaction, yourBookingId);
                
                if (cancelSuccess)
                {
                    // 检查是否有候补票,如果有调用Confirm方法
                    if (HasWaitingList())
                    {
                        bool confirmSuccess = ticketBAL.ConfirmWaitingBooking(transaction, yourWaitingId);
                        if (!confirmSuccess)
                        {
                            throw new Exception("候补票确认失败");
                        }
                    }
                }
                else
                {
                    throw new Exception("订票取消失败");
                }
                
                // 所有操作成功,提交事务
                transaction.Commit();
                ClientScript.RegisterStartupScript(this.GetType(), "alert", "alert('操作成功');", true);
            }
        }
        catch (Exception ex)
        {
            // 任何异常都回滚事务
            if (conn.State == ConnectionState.Open && conn.Transaction != null)
            {
                conn.Transaction.Rollback();
            }
            ClientScript.RegisterStartupScript(this.GetType(), "alert", $"alert('操作失败:{ex.Message}');", true);
        }
    }
}

// 模拟检查是否有候补票的方法
private bool HasWaitingList()
{
    // 这里实现你的逻辑,比如查询数据库是否存在候补记录
    return true;
}

2. BAL层(TicketBAL.cs)

public class TicketBAL
{
    private TicketDAL ticketDAL = new TicketDAL();
    
    public bool CancelBooking(OracleTransaction transaction, int bookingId)
    {
        // 可以在这里做业务逻辑校验,比如检查订票状态是否允许取消
        if (!IsBookingCancelable(bookingId))
        {
            return false;
        }
        
        // 将事务传递给DAL方法
        return ticketDAL.CancelBooking(transaction, bookingId);
    }
    
    public bool ConfirmWaitingBooking(OracleTransaction transaction, int waitingId)
    {
        // 业务逻辑校验,比如检查候补状态
        if (!IsWaitingConfirmable(waitingId))
        {
            return false;
        }
        
        return ticketDAL.ConfirmWaitingBooking(transaction, waitingId);
    }
    
    // 模拟业务校验方法
    private bool IsBookingCancelable(int bookingId)
    {
        return true;
    }
    
    private bool IsWaitingConfirmable(int waitingId)
    {
        return true;
    }
}

3. DAL层(TicketDAL.cs)

public class TicketDAL
{
    public bool CancelBooking(OracleTransaction transaction, int bookingId)
    {
        // 使用事务关联的连接,不要自己新建连接
        using (OracleCommand cmd = transaction.Connection.CreateCommand())
        {
            cmd.Transaction = transaction; // 绑定事务
            cmd.CommandText = "UPDATE BOOKINGS SET STATUS = 'CANCELED' WHERE BOOKING_ID = :BookingId";
            cmd.Parameters.Add(":BookingId", OracleDbType.Int32).Value = bookingId;
            
            int rowsAffected = cmd.ExecuteNonQuery();
            return rowsAffected > 0;
        }
    }
    
    public bool ConfirmWaitingBooking(OracleTransaction transaction, int waitingId)
    {
        using (OracleCommand cmd = transaction.Connection.CreateCommand())
        {
            cmd.Transaction = transaction;
            cmd.CommandText = @"UPDATE WAITING_LIST SET STATUS = 'CONFIRMED' WHERE WAITING_ID = :WaitingId;
                                INSERT INTO BOOKINGS (USER_ID, FLIGHT_ID) SELECT USER_ID, FLIGHT_ID FROM WAITING_LIST WHERE WAITING_ID = :WaitingId";
            
            cmd.Parameters.Add(":WaitingId", OracleDbType.Int32).Value = waitingId;
            
            // 执行多语句
            int rowsAffected = cmd.ExecuteNonQuery();
            return rowsAffected > 0;
        }
    }
}

关键注意事项

  • 不要在DAL中单独打开新连接:所有数据库操作必须复用UI层创建的连接,否则事务无法覆盖。
  • 事务范围要尽量小:不要在事务中做耗时操作(比如调用外部接口、大量计算),避免长时间持有数据库锁,影响性能。
  • 异常处理要全面:确保任何异常都能触发回滚,包括业务逻辑校验失败的情况(可以主动抛出异常来触发回滚)。
  • 使用using管理资源:连接、事务、Command都用using包裹,确保即使出错也能释放资源。

内容的提问来源于stack exchange,提问作者Shahnawaz Ahmad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:10:02