Trigger

Trigger được hiểu đơn giản là một thủ tục được thực thi từ phía máy chủ cơ sở dữ liệu (CSDL) khi có một sự kiện xãy ra như  Update, Insert hay Delete.

Trigger thường dùng để kiểm ra các ràng buộc toàn vẹn trên CSDL, và chúng được thực thi một cách tự động mà không cần sự can thiệp bằng các thao tác thủ công như kiểm tra dữ liệu, đồng bộ hóa dữ liệu,…

– Tạo Trigger

Cú pháp để tạo một Trigger cơ bản như sau:

1
2
3
4
5
CREATE TRIGGER trigger_name
ON { table | view } -- Chỉ định bảng hoặc view sử dụng Trigger
{ FOR | AFTER | INSTEAD OF }
{ [ INSERT ] [ , ] [ UPDATE ] [ , ] [ DELETE ] } -- Các biến cố tự động kích hoạt Trigger
AS { sql_statement,...}

+Về các tham số { FOR | AFTER | INSTEAD OF }

Khi thực hiện một Trigger thì SQL tự động tạo ra 2 bảng InsertedDeleted trong bộ nhớ chính và cục bộ cho mỗi Trigger, có nghĩa là khi áp dụng Trigger trên bảng nào thì bảng Inserted và Deleted sẽ được sử dụng riêng cho đó bảng đó.

Cấu trúc 2 bảng InsertedDeleted được tạo ra sẽ giống hệt cấu trúc của bảng mà Trigger đang thực thi và chúng chỉ tồn tại trong thời gian Trigger đó thực thi mà thôi.

Ví dụ trên: 2 bảng Inserted và Deleted có cấu trúc giống với bảng CTHD (Bảng mà Trigger đang thực thi) gồm các cột: SoHD, MaSP, SL

* Inserted là bảng chứa các dòng dữ liệu vừa được Insert hay Update vào bảng mà Trigger đang thực thi.
* Deleted là bảng  chứa các dòng dữ liệu mới được xóa khỏi bảng bằng thao tác Delete hay Update.
* Khi thực hiện thao tác Update, thì đồng nghĩa với việc sẽ xóa những dòng dữ liệu cũ và thêm những dòng dữ liệu mới, khi đó tác Update sẽ vừa đồng thời thêm dữ liệu là các dòng mới vào 2 bảng Inserted và Deleted

+ FOR | AFTER

Đối với tham số For | After thì Trigger sẽ được gọi sau khi có thao tác Insert hoặc Update.
Thứ tự thực hiện là từ Database rồi đến bảng Inserted/Deleted
+ Khi đó dữ liệu vừa mới Insert/Update vào sẽ nằm trong cả 2 bảng: bảng chính trong Database và bảng Inserted.
+ Khi thực hiện xóa  một dòng dữ liệu thì dòng dữ liệu trên Database sẽ bị xóa, sau đó dòng bị xóa sẽ được thêm vào bảng Deleted.

+ INSTEAD OF

Khi sử dụng tham số Instead of thì Trigger sẽ bỏ qua việc tác động tới CSDL, thay vào đó nó thực hiện việc lưu dữ liệu vào bảng Inserted khi có thao tác Insert, lưu dữ liệu vào bảng Deleted đối với thao tác Delete.

Vì vậy, khi một dòng dữ liệu được thêm vào nó chỉ chứa trong bảng Inserted, và khi xóa một dòng dữ liệu thì nó đồng thời chứa trong bảng Deleted và vẫn còn tồn tại trong Database.
Trigger Instead of thường được dùng để cập nhật khung nhìn (View).

SQL Statement: Nội dung Trigger bao gồm các câu lệnh dùng để thực thi Trigger

Sau đây chúng ta sẽ lấy ví dụ minh họa việc sử dụng Trigger trong SQL

Sử dụng lược đồ CSDL như sau:

KHACHHANG (MAKH, HOTEN, DCHI, SODT, NGSINH, DOANHSO, NGDK)
NHANVIEN (MANV,HOTEN, NGVL, SODT)
SANPHAM (MASP,TENSP, DVT, NUOCSX, GIA)
HOADON (SOHD, NGHD, MAKH, MANV, TRIGIA)
CTHD (SOHD,MASP,SL)

Ràng buộc: Ngày mua hàng (NGHD) của một khách hàng thành viên sẽ lớn hơn hoặc bằng ngày khách hàng đó đăng ký thành viên (NGDK).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TRIGGER CHECK_NGAYNV --Tên Trigger
ON HOADON
FOR UPDATE,INSERT
AS
    IF UPDATE(NGHD) --Kiểm tra việc cập nhật trên cột
    BEGIN
    DECLARE @NGHD SMALLDATETIME, @NGVL SMALLDATETIME
    SET @NGHD=(SELECT NGHD FROM INSERTED)
    SET @NGVL=(SELECT NGVL FROM NHANVIEN A,INSERTED B WHERE A.MANV=B.MANV)
    IF(@NGHD<@NGVL)
        BEGIN
        PRINT 'NGHD PHAI LON HON NGVL'
        ROLLBACK TRAN -- Câu lệnh quay lui khi thực hiện biến cố không thành công
        END
        END

+ Sử dụng cú pháp IF UPDATE để kiểm tra sự thay đổi trên cột, Trigger sẽ tự động thực hiện khi có thay đổi trên cột nhất định nào đó, thay vì chỉ định Trigger kích hoạt trên cả bảng.

1
IF UPDATE(Column_List) --Có thể kiểm tra trên một hay nhiều cột

+ Khai báo một biến cùng kiểu dữ liệu ta thực hiện câu lệnh:

1
DECLARE @Tên_biến Kiểu dữ liệu
1
DECLARE @NGHD SMALLDATETIME

+ Thiết lập giá trị cho một biến

1
SET @NGHD=(SELECT NGHD FROM INSERTED)

Thiết lập giá trị cho một biến có thể là một biểu thức hoặc một câu truy vấn.
Ở đây tôi sử dụng tham số FOR vì thế tôi có thể dễ dàng Select cột NGHD từ bảng Inserted mà không phải là bảng HOADON, như thế việc truy suất sẽ nhanh hơn vì ở đây bảng Inserted chỉ chứa dòng dữ liệu mới thêm vào, mà ta chỉ quan tâm đến những dòng dữ liệu mới thêm vào mà thôi.

+ Câu lệnh PRINT dùng để in thông báo lỗi ra màn hình.

1
PRINT 'THONG BAO LOI'

Hoặc sử dụng câu lệnh RAISERROR:

1
RAISERROR ('THONG BAO LOI')

Khi thực hiện một giao tác(transaction) không thành công thì sẽ tự động quay lui (Rolled Back) bằng cách chèn thêm câu lệnh:

1
ROLLBACK TRAN

Câu lệnh RollBack Tran còn thực hiện trong việc định nghĩa một Trigger cho biến cố Delete không cho xóa một dòng dữ liệu.
VD: Tạo Trigger cho biến cố Delete như sau

1
2
3
4
5
CREATE TRIGGER CANNOT_DELETE
ON HOADON
FOR DELETE
AS
   ROLLBACK TRAN

Khi thực hiện xóa một dòng dữ liệu sẽ có thông báo lỗi

1
DELETE FROM HOADON WHERE MANV='NV01'

Sau khi cài đặt Trigger CHECK_NGAYNV, thử thêm một dòng dữ liệu có NGHD<NGDK:

1
INSERT INTO HOADON VALUES(1001,'23/07/2006','KH01','NV01',320000) -- Giả sử ngày DK là 27/07/2006

Ở đây NGHD=23/07/2006<27/07/2006
Kết quả :

Promise – Async

Delay 5s rồi log ra console chữ HELLO WORLD ??

setTimeout(function() {
    console.log('HELLO WORLD');
}, 5000);

Nhẹ nhàng hơn cả đẩy xe hàng, ok?

Quiz nhỡ:

Delay 5s rồi log ra console chữ HELLO
Rồi 3s sau đó log ra chữ WORLD
Rồi 1s sau đó log ra chữ Rikky Handsome?

setTimeout(function() {
    console.log('HELLO');
    setTimeout(function() {
        console.log("WORLD");
        setTimeout(function(){
            console.log('Rikky Handsome');
        }, 1000)
    }, 3000)
}, 5000);

Quiz to: LÀM THẾ NÀO VIẾT ASYNC CHO ĐẸP ?

Async là một tác vụ của máy tính mà nó sẽ được hoàn thành trong TƯƠNG LAI GẦN. Async có thể giản lược về 3 trạng thái cơ bản: PENDING, SUCCESS, FAILED.

Khi một async task bắt đầu được thực hiện, nó PHẢI ở trạng thái PENDING.
Sau khi thực hiện xong task, async PHẢI chuyển về 1 trong 2 trạng thái: SUCCESS hoặc là FAILED.
Sau khi đã chuyển về trạng thái SUCCESS hoặc là FAILED, async đó KHÔNG ĐƯỢC PHÉP thay đổi trạng thái nữa.

Async KHÁC Event, nhưng có thể dùng event để phát sự kiện chuyển trạng thái của async. Khi đó, event chuyển trạng thái chỉ được trigger 1 lần.

Đây là bộ nguyên tắc bất di bất dịch mà theo như HIỂU BIẾT của mình về async. OK không?

OKAY, BÂY GIỜ QUAY LẠI VẤN ĐỀ ASYNC XẤU XÍ CỦA JAVASCRIPT

Cách Javascript xử lý các tác vụ async có một vấn đề: Sự ràng buộc giữa task handler và task. Ờ thì nôm na ra là:

setTimeout Là task

function() { console.log(‘Hello World’); } là task handler.

Hai cái này vẫn đang phải viết chung vào 1 chỗ:

setTimeout(function() {
    console.log('Hello World');
}, 5000);

Vấn đề sẽ ngay lập tức bị phát sinh, nếu bản thân task handler lại là 1 task khác:

setTimeout(function() {
    console.log('HELLO');
    setTimeout(function() {
        console.log("WORLD");
        setTimeout(function(){
            console.log('Rikky Handsome');
        }, 1000)
    }, 3000)
}, 5000);

Code, nhìn từ góc độ thẩm mỹ thôi nhé, đã xấu bỏ xừ. Các callback function lồng nhau được gọi là hiện tượng: Callback Hell hay Pyramid of Doom.

Nhìn từ góc độ thiết kế, cách viết này sẽ có nguy cơ dẫn đến sự vi phạm những design-pattern căn bản.
Cụ thể nhé:
Nếu mình muốn viết một đoạn mã lấy dữ liệu từ db và trả ra http response:

exports.showData = function(request, response) {
    db.getData(function(data) {
        response.json(data);
    });
}

Điểm mấu chốt nằm ở chỗ, db là object làm việc với database, response là object của http-server. Nhưng bây giờ, db đã phải phụ thuộc hoàn toàn vào response. Điều này vi phạm tư tưởng single response trong thiết kế hệ thống.

Chưa kể đến, rất có thể db là một thư viện do một nhóm deverloper phát triển độc lập với nhóm xây dựng http server. Để nhóm xây dựng http-server sử dụng được db cần có tài liệu mô tả về hàmgetData xem callback function sau đó sẽ nhận được những parameter nào, thậm chí là structure của chúng. Điều này làm giảm đáng kể tốc độ phát triển dự án.

ASYNC INTERFACE – PROMISE

PROMISE – chính xác hơn là Promise/A+ là một bản đặc tả về kết quả của một tác vụ ASYNC, nó đã trở thành một tiêu chuẩn, một INTERFACE để xây dựng những tác vụ Async. Nó giúp bóc tách async task và task handler ra khỏi nhau, những async task như vậy được gọi là những deferred, và kết quả của deferred là promise.

Sau đây là một số đặc tả quan trọng:

Một thenable là một Javascript object có chứa method then(), method then() này nhận 2 tham số fullfill và reject theo đúng thứ tự. Cả 2 tham số này đều là những callback function.

Ví dụ:

aThenable.then(function(value){
     // onFullfill
}, function(error){
    // onReject
})

Một promise là một thenable thoả mãn:

Có chỉ có thể có 1 trong 3 trạng thái sau tại một thời điểm: pending, fullfill, reject

NGAY tại thời điểm được khởi tạo, promise phải mang trạng thái pending

Khi async task được thực hiện thành công, promise phải chuyển từ trạng thái pending sang trạng thái fullfill, tại thời điểm đó, callback onFullfill phải được thực hiện, onFullfillchỉ nhận 1 và chỉ một tham số, đại diện cho kết quả của async task.

Khi async task được THỰC HIỆN XONG, NHƯNG KHÔNG THÀNH CÔNG, promise phải chuyển từ trạng thái pending sang trạng thái reject, tại thời điểm đó, callback onReject phải được thực hiện, onReject chỉ nhận 1 và chỉ 1 tham số, đại diện cho thông báo lỗi do async task trả về.

Khi promise đã ở trại thái fullfill hoặc reject, promise đó KHÔNG thay đổi trạng thái.

Khi một promise có onFullfill hoặc onReject trả về một thenable, thì hàm then của promise đó sẽ trả ra một promise mới – (Promise Chaining)

Khi một promise có onFullfill hoặc onReject trả về một value không phải thenable, thì hàm then của promise đó sẽ trả ra một promise mới mà nó sẽ có luôn trạng tháifullfill với value chính là value không phải thenable – (Promise Pipelining)

Chú ý:

Hàm then() có thể gọi được nhiều lần.

aPromise.then(onFullfill1, onReject1);
aPromise.then(onFullfill2, onReject2);
...
aPromise.then(onFullfillN, onRejectN);

Khi đó, nếu aPromise chuyển về fullfill hoặc reject, TẤT CẢ các callback tương ứng đều được thực hiện;

Promise có thể chaining (Liên hoàn) – Chú ý 2 cái đặc tả cuối cùng:

chainingPromise.then(function() {
    /// asyncTask fullfill
    /// start running a new async task
    return aNewPromise
}, function() {
    ///
})

.then(function () {
    // The new async task done.
}, function() {
    ///
});

Promise KHÔNG PHẢI là async task, mà là đại diện của KẾT QUẢ khi async task được thực hiện xong. Nó nên được hiểu là Value, chứ không phải Action

var promise = asyncTask(); //  promise  -carries result; asyncTask() -performs task

// Get the value that the promise is carrying
promise.then(function(result) {
     console.log('Oh! The result is: %', result.toString());
});

Phù phù! Nhức đầu chưa??? Đấy mới chỉ là những đặc tả cơ bản :))))
Cơ mà, chỉ cần bạn giữ 1 tư tưởng duy nhất trong đầu:

Promise là kết quả của Async

Như thế là ok thôi.

Nào, thử quay lại cái Quiz nhỡ:

deferredTimeout(500)

.then(function(){
    console.log('Hello');
})

.then(function() {
    return deferredTimeout(300);
})

.then(function() {
    console.log('World');
})

.then(function() {
    return deferredTimeout(100);
})


.then(function() {
    console.log('Rikky Handsome');
});

Xinh chưa :relaxed:

Vâng, đây chính là một ví dụ về ASYNC WATERFALL hay Consequence Async ạ

PROMISE IMPLEMENTATIONS

Bạn sẽ hỏi:

Mày lôi ở đâu ra hàm deferredTimeout() thế?
Trả lời luôn: Bịa ra đấy, không có đâu =)))

Bạn nên chú ý, Promise/A+ chỉ là đặc tả, nó mô tả một mô hình, một khuôn mẫu. Còn việc implement nó? Đã có rất nhiều thư viện :D. Và bây giờ là một vài gương mặt sáng giá.

JQUERY

Từ bản 1.7.0, jQuery đã implement mô hình promise.

Không tin hả? Thử cái này xem:

$.get('/my/url').then(function(data) {
     console.log(data);
});

Công việc async duy nhất của jQuery phải làm chính là ajax. Và toàn bộ ajax của jQuery 1.7 đã được viết lại theo cách này.

Ngoài ra, jQuery cũng hỗ trợ bạn tự xây dựng ra các promise của riêng mình thông qua object jQuery.Deferred() – check it out: http://api.jquery.com/category/deferred-object/

Ví dụ nhé:

var wait = function(milisec) {
     var deferred = $.Deferred();
     setTimeout(deferred.resolve, milisec);
     return deferred.promise();
};

wait(500).then(function() {
     console.log('Rikky is F**king awesome!');
});

Nhá, deferredTimeout() đây nhá.

Q

Q là một thư viện có thể dùng cho cả Client/Node.JS;
Q được nhiều người biết đến vì nó chính là 1 built-in service của AngularJS ($q);
Q implement rất tốt spec của Promise/A+
Q hỗ trợ xây dựng một deferred khá dễ dàng:

var wait = function(milisec){
    var defer = Q.defer();
    setTimeout(defer.resolve, milisec);
    return defer.promise;
};

Ngoài ra, ta còn có when cũng rất đáng chú ý.
Parse.com – một PaaS và IaaS rất nổi tiếng hiện nay, SDK của nó cũng support Promise để viết JavascriptClient và CloudCode.
Với ES6 spec, tương lai, promise sẽ được native support cho javascript. Cool!

Q? Vậy Async library của NodeJS là gì?
A: Chỉ là một cách tiếp cận khác đến xử lý async task. Được phát triển bởi developer tên là Caolan. Nó không phải là tiêu chuẩn, càng không phải là Cách lập trình Async. Tuy vậy, Caolan là một developer xuất sắc, anh cũng chính là cha đẻ của nodeunit. Mình tôn trọng thư viện và cách tiếp cận vấn đề của anh. Nhưng mình sẽ chỉ quan tâm đến Promise, vì nó là cách tiếp cận chính thống, được cộng đồng công nhận từ lâu.

ỨNG DỤNG PROMISE TRONG THỰC TẾ

Promise như là contract cho các tác vụ async:

Design by Contract là một phương pháp phát triển phần mềm theo nguyên tắc: Sử dụng một hệ thống Interface/Đặc tả để định nghĩa (Bằng Lập Trình) các điểm ghép nối giữa các thành phần của phần mềm. Nó được xây dựng khi coi một thành phần sẽ là:

Nhà cung cấp, sẽ cung cấp thư viện, các API để có thể thực hiện một công việc nào đó nếu như nó được chia sẻ đủ thông tin. Và nó CAM KẾT thực hiện công việc đó.

Một thành phần khác là Khách hàng sử dụng thư viện và API của Nhà cung cấp để thực hiện công việc của mình. Khách hàng đồng thời CAM KẾT việc chia sẻ đủ thông tin cho Nhà cung cấp.

Contract là sự cam kết giữa Nhà cung cấp và Khách Hàng.

Thông thường, Khách hàng và Nhà cung cấp không cần biết đối tác của mình là ai, chỉ cần biết đối tác sẽ thực hiện cam kết của mình, nhờ thế, Nhà cung cấp và Khách hàng có thể được xây dựng độc lập, không phụ thuộc lẫn nhau.

RẤT LÀ AGILE =))

Trong quá trình phát triển dự án bằng Javascript, rất nhiều trường hợp, bên Nhà cung cấp là sẽ phải thực hiện một công việc async. Khi đó, ta thường sử dụng promise như là contract.

Ví dụ:
Bạn đang viết một module xử lý Authenticate, khi đó, code của controller/middleware của bạn chính là Khách Hàng. Nó sử dụng Nhà Cung Cấp là một dịch vụ Authenticator thông quausername và password và trả lại một userIdentity nào đó:

module.exports = function(request, response) {
    ///
   Authenticator.check(request.body.username, response.body.password);
   /// 
}

Vấn đề là việc check này, trong hầu hết các trường hợp là tác vụ async (như query đến database chẳng hạn); Nên ta cần có 1 promise để define contract – Authenticator.check(username, password) Phải return 1 promise đại diện cho kết quả login.
Và thế là ta đã có đoạn code sau:

module.exports = function(request, response) {
   ///
   Authenticator.check(request.body.username, response.body.password)
   // Interesting things here:
   .then(function(userIdentity) {
       response.send('Hello ' + userIdentity); // Kiểu kiểu thế
   }, function(authErrorMessage) {
      response.status(401).send(authErrorMessage);
   });
   /// 
}

Okay, thế có gì hot?
HOT là bạn thực sự không cần biết Authenticator thực chất là object nào.

var InnerSystemAuthenticator = function () {
     /// 
     this.check = function(u, p) {
           var loginDefer = Q.defer;
           db.find({username: u, password: p}, function(error, found) {
               if(error) {
                    defer.reject(error);
               }
               if (!found) {
                    defer.reject('Authentication Failed');
               } else {
                    defer.resolve(found.id);
               }
           });
           return loginDefer.promise;
     };
};
var FacebookAuthenticator = function() {
      this.check = function (u, p) {
            // ... blah
            return fbAuthPromise;
      };
};
var GoogleAuthenticator = function() {
    this.check = function (u, p) {
            // ... blah
            return googleAuthPromise;
      };
};

Và bây giờ, với chỉ một promise contract đơn giản, bạn đã có thể cùng một lúc tích hợp cả 3 service Authenticate: DB, Facebook, Google.

Và 100 năm nữa, khi tập đoàn Rikky phát triển dịch vụ xác thực thông qua username là DNA và password là vân tay của user. Bạn vẫn tích hợp được nó vào dự án của bạn. Cheer!

Promise như là tầng abstract của async

Quay lại vụ Authenticate, nếu bạn đang chỉ muốn viết unittest cho controller/middleware xem Nếu user authenticate failed có đúng http status 401 được bắn ra hay không? bạn làm như nào:

var AlwaysFailedMockAuthenticator = {
    check: function(u, p) {
         var failedAuthDefer = Q.defer();
         failedAuthDefer.reject('Just Kidding! Test for fun!');
         return failedAuthDefer.promise;
    }
};

**RẤT LÀ TDD :kissing_closed_eyes: **

Promise như là KẾT QUẢ của async

Nếu 1 ngày đẹp trời, bạn phát hiện ra, việc gì mình phải thực hiện nhiều lần query đến cái data dở hơi, 100 năm mới thay đổi 1 lần.

    db.findCurrentCentury().then( // blah blah);

Thì hãy làm như sau:

var CurrentCenturyProvider = function() {
    //
    var cached = null;

    this.get = function() {
        if (!cached) {
            return db.findCurrentCentury().then(function(currentCentury) {
                cached = currentCentury;
                return currentCentury;
            });
        } else {
            var cachedPromise = Q.defer();
            q.resolve(cached);
            return q.promise;
        }
    };
}


var centuryProvider = new CurrentCenturyProvider();

centuryProvider.get().then( // blah blah);

RẤT LÀ PERFORMANCE :blush:

Promise như là kết quả của một cái gì đó – có thể là Async

Một ngày đẹp trời, bạn sẽ nhận ra rằng Sync cũng là Async, một trường hợp đặc biệt của Async thì đúng hơn. Nếu thế, hãy cứ coi như task của bạn sẽ chấp nhận 1 promise đi. Nó rất hữu ích khi bạn xây dựng 1 thư viện mà bạn không biết chính xác input của bạn có phải Async hay không.

// Nào thì jQuery 1 tý nào:
var inputTextAutoComplete = function (listOfSuggestion) {
     // Wrap luôn listOfSuggestion bởi 1 promise:
     var suggestionPromise = jQuery.when(listOfSuggestion);

     suggestionPromise.then(function() {
         /// Show the AutoComplete
     });
};

inputTextAutoComplete(['Rikky', 'Is', 'Awesome']);
inputTextAutoComplete($.get('/keywords'));

RẤT LÀ TINH TẾ =)))))))

Promise thay thế cho những event chỉ được trigger 1 lần:

Như mình đã nói, promise và những event chỉ được trigger 1 lần có thể hoán đổi cho nhau, ví dụ như onload/ready event của jQuery:

var whenLoaded = function() {
    var deferred = $.Deferred();
    $(document).ready(function(event) {
        deferred.resolve(event);
    });
    return deferred.promise();
};
///
var pageLoadedPromise = whenLoaded();
pageLoadedPromise.then(function(event) {
    console.log('Woo hoo! Page Loaded');
});

pageLoadedPromise.then(function(){
    // whatever!
});

Hay thậm chí bạn có thể viết lazy load cho Javascript:

var lazyLoadJavascript = function(uri) {
       var deferred = $.Deffered();
       $.getScript(uri, function() {
            deferred.resolve();
      });
      return deferred.promise();
};

var myScriptPromise = lazyLoadJavascript('path/to/my/script.js');
myScriptPromise.then(function() {
     console.log('Woo hoo! Script loaded');
});

hay thậm chí là:

var myModulePromise = loadModule('path/to/file.html', 'path/to/file.js', 'path/to/file.css');

myModule.then(function() {
     /// whatever 😀
});

KẾT

Có rất nhiều cách để bạn sử dụng promise, nó gúp Async chẳng gì là phức tạp, hết cả callback lồng nhau. Code của bạn sẽ trở nên hay ho và nguy hiểm hơn nhiều.
Ngoài các cách implement trên, bạn còn có thể dùng nó để điều khiển chuyển động. Kiểu: moveLeft().then(moveUp).then(moveDown).then(moveRight) –> Rất là chóng mặt s-(
Nào? Bây giờ hiểu biết của mình như thế OK chưa?
–> Rất là hiểu biết

Source : https://nodejs.vn/topic/15/promise-async-th%C3%AC-sao-n%C3%A0o/2

DELETE và TRUNCATE

SQL Server cung cấp 2 phương pháp để xóa dữ liệu, DELETE và TRUNCATE. Cú pháp của hai lệnh này như sau:

DELETE

DELETE dbo.Tblxxx WHERE...

hoặc

DELETE a FROM dbo.Tblxxx a WHERE...

Khi cần xóa dữ liệu với điều kiện liên quan đến bảng khác:

DELETE a
FROM dbo.Tblxxx a
JOIN dbo.Tblyyy b ON a.Col1 = b.Col1

hoặc:

DELETE a
FROM dbo.Tblxxx a
WHERE EXISTS(SELECT 1 FROM dbo.Tblyyy b WHERE a.Col1 = b.Col1)

TRUNCATE không có tùy biến nào

TRUNCATE TABLE dbo.Tblxxx

 

Tuy cùng để xóa dữ liệu, nhưng hai lệnh này có những khác nhau cơ bản:

  • DELETE cung cấp các lựa chọn để xóa những dòng dữ liệu thỏa mãn các điều kiện nhất định, như WHERE hoặc JOIN với các bảng khác.
    TRUNCATE không có lựa chọn nào, mà luôn cắt bỏ toàn bộ dữ liệu của bảng. Nói cách khác, ta không thể TRUNCATE 1 nửa hay 1 phần của bảng.
  • DELETE hỗ trợ transaction. Khi lệnh DELETE nằm trong 1 transaction và trong một tình huống nào đó transaction được ROLLBACK thì các bản ghi bị xóa bởi lệnh DELETE sẽ trở lại bảng không có gì suy xuyển.
    TRUNCATE thì ngược lại, không hỗ trợ transaction. Một khi đã thực hiện thì không thể lấy lại dữ liệu được nữa.
  • DELETE khi thực hiện bao gồm quá trình tìm các bản ghi thỏa mãn điều kiện của câu lệnh, và xóa các bản ghi này. Việc tìm các bản ghi cần xóa được thực hiện giống hệt như một câu lệnh SELECT, cũng tối ưu hóa, lựa chọn giữa các phương án thực hiện khác nhau và chọn ra phương án tối ưu (dựa vào index, statistics…).
    TRUNCATE thì chỉ có một phương án thực hiện duy nhất, đó là cắt bỏ tất cả các dòng dữ liệu của bảng.
  • Với DELETE, các bản ghi bị xóa sẽ được kiểm tra xem có vi phạm ràng buộc FOREIGN KEY không. Ví dụ ta có hai bảng MAT_HANG và BAN_HANG là quan hệ 1-n thông qua MA_MH; nếu MA_MH=1 đã có giao dịch, nghĩa là bảng BAN_HANG đã có bản ghi với MA_MH=1, thì khi DELETE bản ghi với MA_MH=1 từ bảng MAT_HANG (bảng cha) SQL SERVER sẽ báo lỗi và không cho xóa.
    Nếu trước đó, khi ta định nghĩa ràng buộc FOREIGN KEY mà có lựa chọn CASCADE DELETE, thì thay vì báo lỗi SQL Server sẽ đồng thời xóa hết các bản ghi trong cả bảng BAN_HANG với MA_MH=1.
  • TRUNCATE thì không có những đoạn kiểm tra dài dòng như thế. Nếu bảng có ràng buộc FOREIGN KEY, SQL Server sẽ báo lỗi và không cho thực hiện (nhớ là lựa chọn CASCADE DELETE trong khai báo FOREIGN KEY chỉ ảnh hưởng đến lệnh DELETE chứ không tác dụng đối với TRUNCATE).
  • Vì DELETE hỗ trợ transaction và dùng transaction log, nó có thể dùng với bảng nằm trong một replication hoặc database có dùng log shipping.
    TRUNCATE thì vì không ghi gì vào transaction log nên khi gặp một trong các tình huống trên sẽ bị từ chối ngay.
  • Với DELETE, nếu bảng có index thì các index cũng sẽ được cập nhật để xóa đi các node tương ứng với các bản ghi bị xóa.
    TRUNCATE thì rất đơn giản, các index của bảng cũng bị cắt cụt theo.
  • DELETE không ảnh hưởng đến giá trị IDENTITY. Nếu bảng có 100 bản ghi và cột IDENTITY có giá trị từ 1-100; nay ta DELETE bản ghi có cột IDENTITY=100 rồi INSERT một bản ghi mới; bản ghi mới sẽ có cột IDENTITY=101.
    TRUNCATE luôn đặt lại IDENTITY trở về 1. Bản ghi đầu tiên được INSERT sau khi TRUNCATE sẽ có cột IDENTITY=1.
  • DELETE thực ra chỉ đánh dấu xóa các bản ghi chứ ngay sau đó dữ liệu của các bản ghi bị xóa vẫn nằm nguyên tại chỗ. Dần dần khi ta INSERT thêm dữ liệu vào bảng thì các bản ghi mới sẽ ghi đè lên các vùng lưu trữ đó. Ta có thể kiểm tra để thấy kích thước bảng không thay đổi ngay cả sau khi chạy DELETE FROM TblName (xóa hết các bản ghi).
    TRUNCATE thì xóa hết dữ liệu đồng thời giải phóng vùng lưu trữ giành cho bảng, trả lại cho SQL Server. Ta có thể so sánh DELETE như là xóa file, còn TRUNCATE thì như format lại ổ cứng.
  • DELETE cho phép áp dụng đối với bảng ở server khác được nối qua linked server.
    TRUNCATE không cho phép điều này, bạn chỉ có thể TRUNCATE bảng nằm trên cùng server.

Vì những lý do trên, DELETE luôn luôn chậm hơn TRUNCATE. Càng có nhiều bản ghi DELETE càng chậm, còn TRUNCATE thì không phụ thuộc vào lượng dữ liệu. DELETE có phạm vi ứng dụng rộng hơn; còn TRUNCATE chỉ dùng được mỗi một việc, nhưng nó lại làm rất nhanh. Vì vậy, hãy nhớ dùng TRUNCATE khi có thể được.

How To Fix Time Difference Between Ubuntu And Windows

Recently LinuxAndUbuntu reader raised an issue that he was having with his dual boot. When he restarts from Ubuntu to Windows, the time in Windows changes. Here is why it happens and how you can fix it easily from Ubuntu.

Why There Is Time Difference Between Ubuntu And Windows ?

The time in Windows changes due to the ways both systems differently stores the time in the hardware clock. Ubuntu stores the time in UTC while Windows in Local time  so when user restarts Windows any number of time, the time does not change but when the user restarts from Windows into Ubuntu and then restarts back into Windows, the hardware clock has stored the time in UTC and now Windows changes it into Local time which cause the issue.

Here Is How Time Difference Between Ubuntu And Windows Can Be Fixed

Time difference can easily be resolved by changing the time from UTC to Local in Ubuntu. To do this simply edit the “/etc/default/rcS” file and change “UTC=no” to “UTC=yes” (without quotes). Now Ubuntu will store time in hardware clock in Local time instead of UTC so there won’t be any conflictions between Ubuntu and Windows. To do this automatically, use the following command in terminal –

$ sudo sed -i ‘s/UTC=yes/UTC=no/’ /etc/default/rcS
Although setting up time in UTC is beneficial because you don’t need to change the hardware clock when moving between timezones.

Fixing Time Difference From Windows

The above was the solution to time difference from Ubuntu, now let’s see how to fix it from Windows –

First of all download the below registry file and double click it to install.

windowstimefixutc.reg

Download File


After extracting registry, run command prompt as an administrator and enter the following command –
sc config w32time start= disabled
You are done! Now reboot the system for changes to take effects.

Oracle Java JDK 9

Webupd8 Team is maintaining a PPA repository with installer scripts for the latest Java 8 and 9, that automatically downloads the Java archive from Oracle website and sets up everything for you.

1. Add the PPA.

Open terminal (Ctrl+Alt+T) and run the command:

sudo add-apt-repository ppa:webupd8team/java

Type in your password when it asks and hit Enter.

java-installer-ppa

2. Update and install the installer script:

Run commands to update system package index and install Java installer script:

sudo apt update; sudo apt install oracle-java8-installer

You may replace oracle-java8-installer with oracle-java9-installer to install Java 9.

While the install process, you have to accept Java license to continue downloading & installing Java binaries.

Oracle Java License

3. Check the Java version

To check the Java version after installing the package, run command:

javac -version

check out java version

4. Set Java environment variables

The PPA also contains a package to automatically set Java environment variables, just run command:

sudo apt install oracle-java8-set-default

For Java 9, install the package oracle-java9-set-default instead.

System log files can be easily managed using logrotate to archive old entries, but when logging to a database table you will typically need to write your own script.

In the following example we’ve created a TRIGGER that is called automatically by PostgreSQL that has the effect of deleting ‘stale’ records.

The obvious advantage being that it’s always associated with the database and will be included in any backups. It also doesn’t require any CRON script.

1. The situation

In this simple example we’ve created a log of the ip address of visitors to a certain part of a website, and the timestamp of each visit:

CREATE TABLE limiter ( ip varchar NOT NULL, timestamp timestamp NOT NULL DEFAULT NOW() );

Data is added using a simple INSERT statement called from PHP:

This logs thousands of entries each day, but for our purposes the data only needs to be kept for up to 48 hours, so at regular intervals we call a DELETE function:

Simple enough, and it works, but lets see how we can better automate this using a trigger.

2. Creating the TRIGGER function

The following code creates a basic trigger that deletes old rows from the table as before:

CREATE FUNCTION delete_old_rows() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN DELETE FROM limiter WHERE timestamp < NOW() - INTERVAL '2 days'; RETURN NULL; END; $$;

We plan to call this using AFTER INSERT so the RETURN value is not used can can be ‘NULL’.

3. Calling the TRIGGER

Finally, we set the trigger to be called every time a new record is inserted into the table:

CREATE TRIGGER trigger_delete_old_rows AFTER INSERT ON limiter EXECUTE PROCEDURE delete_old_rows();

And we’re done. Every time a new row is inserted into this table, our trigger function is called and deletes any records older than 48 hours.

4. Adding DIAGNOSTICS

As a final step we’re going to modify the trigger so that it also reports the number of rows that have been deleted:

CREATE FUNCTION delete_old_rows() RETURNS trigger LANGUAGE plpgsql AS $$ DECLARE row_count int; BEGIN DELETE FROM limiter WHERE timestamp < NOW() - INTERVAL '2 days'; IF found THEN GET DIAGNOSTICS row_count = ROW_COUNT; RAISE NOTICE 'DELETEd % row(s) FROM limiter', row_count; END IF; RETURN NULL; END; $$;

Now when any rows are deleted a NOTICE is raised:

postgres=# INSERT INTO limiter VALUES ('1.2.3.4'); NOTICE: DELETEd 136 row(s) FROM limiter INSERT 0 1

For those paying attention, note that we’re not actually making use of the NOTICE text in our PHP code, but it could be logged for debugging purposes in the PostgreSQL log file.

5. VIEWing TRIGGER details

From the command-line interface you can view the TABLE details as follows:

# \d limiter Table "public.limiter" Column | Type | Modifiers -----------+-----------------------------+------------------------ ip | character varying | not null timestamp | timestamp without time zone | not null default now() Triggers: trigger_delete_old_rows AFTER INSERT ON limiter FOR EACH STATEMENT EXECUTE PROCEDURE delete_old_rows()

And to see the TRIGGER definition and code:

# \x Expanded display is on. # \df+ delete_old_rows List of functions -[ RECORD 1 ]-------+------------------------------------------------------------------- Schema | public Name | delete_old_rows Result data type | trigger Argument data types | Type | trigger Security | invoker Volatility | volatile Owner | postgres Language | plpgsql Source code | | DECLARE | row_count int; | BEGIN | DELETE FROM limiter WHERE timestamp < NOW() - INTERVAL '2 days'; | IF found THEN | GET DIAGNOSTICS row_count = ROW_COUNT; | RAISE NOTICE 'DELETEd % row(s) FROM limiter', row_count; | END IF; | RETURN NULL; | END;

Using just \df instead of \df+ you will only see the Scheme, Name, Result and Argument data types, and Type. Not particularly useful.

Blog at WordPress.com.

Up ↑