2012-03-21 20 views
6

Tôi đang suy nghĩ về việc thực hiện IUnitOfWork thực hiện của riêng mình cho lớp kiên trì NHibernate.bạn có thể có nhiều giao dịch xảy ra bên trong một phiên trong nhibernate? Và đó là một ý tưởng tồi?

Có vẻ như cách phù hợp để thực hiện điều này là để có ISession và số ITransaction khởi tạo trong hàm tạo và sau đó được xử lý trong hàm hủy hoặc phương thức Dispose().

Tất nhiên, nếu ai đó gọi phương thức Save() thì ISession sẽ được rửa và ITransaction sẽ được hoàn thành, vì vậy sau khi gọi Save(), sẽ không có một giao dịch mở hợp lệ để Save() một lần nữa ... trừ khi tôi phạm giao dịch đầu tiên và ngay lập tức mở một giao dịch mới. Nhưng đây có phải là một ý tưởng hay không?

Thiết kế khôn ngoan, nó có ý nghĩa để thực hiện một thao tác cam kết, nhưng tôi sẽ không nhất thiết phải kiểm soát mã và các nhà phát triển khác có thể bị kỷ luật ít hơn theo mẫu UnitOfWork.

Tôi có mất/đạt được bất kỳ thứ gì bằng cách cố gắng làm cho UnitOfWork khoan dung với nhiều giao dịch mỗi phiên không? Tôi có nên chỉ kiểm tra một giao dịch mở và ném một ngoại lệ nếu nó đã được cam kết, thay vì thực hiện một giao dịch mới?

+0

Ứng dụng web hoặc máy tính để bàn? – Phill

+0

Nó đang được thiết kế cho một ứng dụng web. –

Trả lời

11

Để trả lời câu hỏi đầu tiên: có thể có nhiều giao dịch trong một phiên.

Có phải là một ý tưởng hay không? Nó phụ thuộc.

Vấn đề là thay đổi dữ liệu trong giao dịch đầu tiên sẽ được cam kết, trong khi nó không chắc chắn nếu toàn bộ đơn vị công việc (phiên) được cam kết cuối cùng. Khi bạn nhận được, hãy nói, một StaleObjectException trong một giao dịch sau này, bạn đã có một số dữ liệu cam kết. Lưu ý rằng loại ngoại lệ này làm cho phiên của bạn không sử dụng được và bạn vẫn phải hủy nó. Sau đó, thật khó để bắt đầu lại và thử lại.

Tôi xin nói, nó hoạt động tốt trong những trường hợp:

  • Nó là một ứng dụng giao diện người dùng
  • Thay đổi chỉ đỏ ửng trong giao dịch cuối cùng.

UI Application

lỗi được xử lý bởi người dùng tương tác.Điều này có nghĩa là người dùng có thể xem những gì thực sự được lưu trữ trong trường hợp lỗi và lặp lại những thay đổi mà anh đã thực hiện.

Thay đổi chỉ đỏ ửng trong giao dịch cuối cùng

Phiên như thực hiện bởi NH chỉ xả thay đổi ở cuối hoặc "khi cần thiết". Vì vậy, nó sẽ có thể giữ những thay đổi trong bộ nhớ cho đến khi phiên được cam kết. Vấn đề là NH cần phải tuôn ra phiên trước mỗi truy vấn, khó kiểm soát. Nó có thể được tắt, dẫn đến tác dụng phụ. Khi viết các giao dịch đơn giản, bạn có thể kiểm soát nó. Trong một hệ thống phức tạp, hầu như không thể đảm bảo rằng không có gì xảy ra.

Các cách đơn giản (tm)

tôi đã viết các lớp kiên trì của một hệ thống client-server khá lớn. Trong một hệ thống như vậy, bạn không có lỗi xử lý trực tiếp người dùng. Bạn cần xử lý các lỗi trong hệ thống và trả lại quyền kiểm soát cho máy khách trong trạng thái nhất quán.

Tôi đã đơn giản hóa toàn bộ việc xử lý giao dịch ở mức tối thiểu tuyệt đối, để làm cho nó ổn định và "bằng chứng ngốc nghếch". Tôi luôn có một phiên giao dịch và một giao dịch được tạo cùng nhau và nó được cam kết hay không.

+0

Sự hiểu biết của tôi là lệnh gọi 'ITransaction.Commit()' sẽ xóa phiên. Khởi tạo một 'ITransaction' mới bằng cách sử dụng cùng phiên đó, và ngay lập tức theo' Commit() ', hoàn cảnh nào sẽ tạo ra' StaleObjectException'? –

+0

Cam kết khóa phát hành giao dịch. Điều này làm cho nó có nhiều khả năng để có được StaleObjectExceptions. Nhưng bạn vẫn có thể lấy chúng, bởi vì dữ liệu có thể thay đổi trong db trong khi bạn đang thay đổi nó trong bộ nhớ. Khóa tối ưu của NH làm cho ít nhất có thể phát hiện các xung đột này. –

+1

Cảm ơn câu trả lời chi tiết. –

2

Có nhiều tùy chọn có sẵn để triển khai giao dịch lồng nhau nhibernate với đơn vị công việc.

Ở đây tôi đang sử dụng mẫu Lệnh cho đơn vị công việc.

public interface IAction 
{  
    void Execute(); 
} 

public abstract class Action<T> : IAction, IDisposable where T : Action<T> 
{ 
    public void Execute() 
    { 
     try 
     { 
      //Start unit of work by your unit of work pattern or 
      transaction.Begin(); 
      OnExecute(); 
      //End Unit of work 
      transaction.Commit(); 
     } 
     catch (Exception e) 
     { 
      transaction.Rollback(); 
      throw e; 
     } 
    } 

    protected abstract void OnExecute(); 

    public void Dispose() 
    { 

    } 
} 

public class MyBusinessLogic : Action<MyBusinessLogic> 
{ 
    protected override void OnExecute() 
    { 
     //Implementation 
    } 
} 

public class MyAnotherBusinessLogic : Action<MyAnotherBusinessLogic> 
{ 
    protected override void OnExecute() 
    { 
     //Nested transaction 
     MyBusinessLogic logic = new MyBusinessLogic(); 
     logic.Execute(); 
    } 
} 
+0

Chỉ để chỉ ra một số điều sau: 1) Đã có một System.Action để có thể gây nhầm lẫn về tên. 2) Hành động của bạn lớp không xác định nơi giao dịch đến từ đâu. 3) Điều này vẫn sẽ gây ra các lỗi tương tự như giao dịch lồng nhau gây ra trong NHibernate đã (cam kết giao dịch nội bộ sẽ làm cho giao dịch bên ngoài ném một ObjectDisposedException). – rossisdead

0

Tôi nghĩ rằng giải pháp với một giao dịch trên mỗi đơn vị công việc quá hạn chế. Trong một số môi trường, người ta có thể cần khả năng thực hiện một số giao dịch mỗi phiên. Bản thân tôi quản lý các giao dịch một cách rõ ràng và nó có vẻ là một giải pháp linh hoạt.

public interface IUnitOfWork: IDisposable 
{ 
    IGenericTransaction BeginTransaction(); 
} 

public interface IGenericTransaction: IDisposable 
{ 
    void Commit(); 

    void Rollback(); 
} 

public class NhUnitOfWork: IUnitOfWork 
{ 
    private readonly ISession _session; 

    public ISession Session 
    { 
     get { return _session; } 
    } 

    public NhUnitOfWork(ISession session) 
    { 
     _session = session; 
    } 

    public IGenericTransaction BeginTransaction() 
    { 
     return new NhTransaction(_session.BeginTransaction()); 
    } 

    public void Dispose() 
    { 
     _session.Dispose(); 
    } 
} 

public class NhTransaction: IGenericTransaction 
{ 
    private readonly ITransaction _transaction; 

    public NhTransaction(ITransaction transaction) 
    { 
     _transaction = transaction; 
    } 

    public void Commit() 
    { 
     _transaction.Commit(); 
    } 

    public void Rollback() 
    { 
     _transaction.Rollback(); 
    } 

    public void Dispose() 
    { 
     _transaction.Dispose(); 
    } 
} 

Cách sử dụng trông như thế này. Nó có thể dễ dàng kết hợp vào bất kỳ mẫu nào.

public void Do(IUnitOfWork uow) 
{ 
    using (var tx = uow.BeginTransaction()) { 
    // DAL calls 
    tx.Commit(); 
    } 
} 
+0

Đó là chính xác những gì chúng tôi làm quá nhưng nó không hoạt động trong trường hợp này: không thể chỉnh sửa mã trong một nhận xét ... Nhưng nếu bạn có một giao dịch khác bên trong nó không hoạt động. Nhưng nó nên. Các giao dịch lồng nhau được thực hiện trong cơ sở dữ liệu vì lý do chính đáng. – user2415376

Các vấn đề liên quan