Giao dịch ORM hùng hồn trên Laravel


96

Eloquent ORM khá hay, mặc dù tôi đang tự hỏi liệu có cách nào dễ dàng để thiết lập các giao dịch MySQL bằng cách sử dụng innoDB theo cùng một kiểu như PDO hay không, hay liệu tôi có phải mở rộng ORM để làm điều này không?

Câu trả lời:


165

Bạn có thể làm được việc này:

DB::transaction(function() {
      //
});

Mọi thứ bên trong Closure thực hiện trong một giao dịch. Nếu một ngoại lệ xảy ra, nó sẽ tự động khôi phục.


1
Bên trong bao đóng, tôi có thể gọi các truy vấn trong một lớp? Nó sẽ hoạt động?
Rafael Soufraz

Đáng buồn là nó không hoạt động đối với tôi nếu tôi đang tạo phiên bản của các mô hình khác nhau đang lưu trữ bản ghi trong các phương pháp có liên quan của riêng họ.
Volatil3

Nếu tôi bắt gặp một ngoại lệ bên trong giao dịch của mình (để tạo thông báo lỗi, v.v.), tôi có cần phải gửi lại ngoại lệ để quá trình khôi phục diễn ra không?
alexw 19/02/16

3
Câu trả lời hay nhưng một vài điều khiến tôi không hiểu: 1. Bạn cần thêm "use DB;" để thực hiện việc này, ví dụ: ở đầu tệp mô hình của bạn 2. Không giống như JS, bạn không có quyền truy cập vào các biến cục bộ trong phạm vi mẹ trừ khi bạn chuyển chúng vào một cách rõ ràng, do đó bạn cần thêm cấu trúc "use" ... DB :: transaction (function () use ($ user) {... nội dung tham chiếu đến $ user ...});
Polsonby

Discussed in more detail hereliên kết đã chết.
tomloprod,

100

Nếu bạn không thích các chức năng ẩn danh:

try {
    DB::connection()->pdo->beginTransaction();
    // database queries here
    DB::connection()->pdo->commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::connection()->pdo->rollBack();
}

Cập nhật : Đối với laravel 4, pdođối tượng không còn công khai nữa nên:

try {
    DB::beginTransaction();
    // database queries here
    DB::commit();
} catch (\PDOException $e) {
    // Woopsy
    DB::rollBack();
}

15
Bạn cũng có thể sử dụng các phương pháp phím tắt DB::beginTransaction()& DB::commit()& DB::rollback(). Như vậy sẽ sạch hơn một chút.
Flori

2
Vui lòng cập nhật để sử dụng đề xuất @Flori. Nó sạch hơn. Ngoài ra, chuyển câu trả lời mới lên trên sẽ giúp câu trả lời của bạn bớt khó hiểu hơn. Tôi đã sử dụng phương pháp đầu tiên trước khi quay lại phương pháp thứ hai.
frostymarvelous

Đối với phiên bản cũ hơn của Laravel, bạn có thể cần:DB::connection()->getPdo()->beginTransaction();
thay vào đó,

Cá nhân tôi nghĩ rằng DB::transactionvới callback thậm chí còn sạch hơn nhưng nhược điểm là nếu bạn cần phải xác định xử lý khác nhau đối với trường hợp ngoại lệ khác nhau, bạn sẽ phải quay trở lại để cố gắng / catch kỹ thuật
OzzyTheGiant

33

Nếu bạn muốn sử dụng Eloquent, bạn cũng có thể sử dụng

Đây chỉ là mã mẫu từ dự án của tôi

        /* 
         * Saving Question
         */
        $question = new Question;
        $questionCategory = new QuestionCategory;

        /*
         * Insert new record for question
         */
        $question->title = $title;
        $question->user_id = Auth::user()->user_id;
        $question->description = $description;
        $question->time_post = date('Y-m-d H:i:s');

        if(Input::has('expiredtime'))
            $question->expired_time = Input::get('expiredtime');

        $questionCategory->category_id = $category;
        $questionCategory->time_added = date('Y-m-d H:i:s');

        DB::transaction(function() use ($question, $questionCategory) {

            $question->save();

            /*
             * insert new record for question category
             */
            $questionCategory->question_id = $question->id;
            $questionCategory->save();
        });

Các question->idbiểu hiện ở các callback giao dịch trả về zero.
Christos Papoulas

Ý bạn là @ChristosPapoulas, chúng tôi không thể lấy id tăng tự động trong giao dịch?
hellojinjie,

26

Nếu bạn muốn tránh đóng cửa và thích sử dụng mặt tiền, những điều sau đây sẽ giữ cho mọi thứ luôn đẹp và sạch sẽ:

try {
    \DB::beginTransaction();

    $user = \Auth::user();
    $user->fill($request->all());
    $user->push();

    \DB::commit();

} catch (Throwable $e) {
    \DB::rollback();
}

Nếu bất kỳ câu lệnh nào không thành công, commit sẽ không bao giờ được thực hiện và giao dịch sẽ không được xử lý.


Nếu bất kỳ câu lệnh nào bị lỗi, các câu lệnh tiếp theo sẽ không chạy. Bạn vẫn cần khôi phục giao dịch một cách rõ ràng.
Jason

1
@Jason Tôi đã cập nhật câu trả lời. Tôi luôn nghĩ về việc liệu tôi có nên, đối với hầu hết (tất cả?) Các công cụ cơ sở dữ liệu, khi kết nối bị chấm dứt, bất kỳ truy vấn giao dịch nào không được cam kết sẽ không được cam kết. Tuy nhiên, tôi đồng ý với những gì bạn đang nói, và có lẽ tốt nhất là rõ ràng
Chris

18

Tôi Chắc chắn bạn không tìm kiếm giải pháp đóng cửa, hãy thử giải pháp này để có giải pháp nhỏ gọn hơn

 try{
    DB::beginTransaction();

    /*
     * Your DB code
     * */

    DB::commit();
}catch(\Exception $e){
    DB::rollback();
}

10

Vì một số lý do, rất khó tìm thấy thông tin này ở bất cứ đâu, vì vậy tôi quyết định đăng nó ở đây, vì vấn đề của tôi, trong khi liên quan đến các giao dịch Eloquent, đã chính xác thay đổi điều này.

Sau khi đọc NÀY câu trả lời stackoverflow , tôi nhận ra rằng các bảng cơ sở dữ liệu của mình đang sử dụng MyISAM thay vì InnoDB.

Để các giao dịch hoạt động trên Laravel (hoặc bất kỳ nơi nào khác có vẻ như), các bảng của bạn được đặt để sử dụng InnoDB

Tại sao?

Trích dẫn tài liệu về Giao dịch MySQL và Hoạt động nguyên tử ( tại đây ):

MySQL Server (phiên bản 3.23-max và tất cả các phiên bản 4.0 trở lên) hỗ trợ các giao dịch với các công cụ lưu trữ giao dịch InnoDB và BDB. InnoDB cung cấp sự tuân thủ ACID đầy đủ. Xem Chương 14, Động cơ lưu trữ. Để biết thông tin về sự khác biệt của InnoDB so với SQL tiêu chuẩn liên quan đến việc xử lý lỗi giao dịch, hãy xem Phần 14.2.11, “Xử lý lỗi InnoDB”.

Các công cụ lưu trữ không giao dịch khác trong MySQL Server (chẳng hạn như MyISAM) tuân theo một mô hình khác về tính toàn vẹn dữ liệu được gọi là “hoạt động nguyên tử”. Về mặt giao dịch, các bảng MyISAM luôn hoạt động hiệu quả ở chế độ autocommit = 1. Các hoạt động nguyên tử thường cung cấp tính toàn vẹn có thể so sánh được với hiệu suất cao hơn.

Vì MySQL Server hỗ trợ cả hai mô hình, bạn có thể quyết định xem các ứng dụng của mình có được phục vụ tốt nhất hay không nhờ tốc độ hoạt động nguyên tử hoặc việc sử dụng các tính năng giao dịch. Sự lựa chọn này có thể được thực hiện trên cơ sở từng bảng.


Điều này đúng với DML và không phải lúc nào cũng đúng với DDL.
Yevgeniy Afanasyev

4

Nếu có bất kỳ ngoại lệ nào xảy ra, giao dịch sẽ tự động khôi phục.

Định dạng giao dịch cơ bản của Laravel

    try{
    DB::beginTransaction();

    /* 
    * SQL operation one 
    * SQL operation two
    ..................     
    ..................     
    * SQL operation n */


    DB::commit();
   /* Transaction successful. */
}catch(\Exception $e){       

    DB::rollback();
    /* Transaction failed. */
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.