Tạo một bảng dữ liệu mới để truy vấn : phải chuột vào Table, chọn create Table Ta sẽ xuất hiện hộp thoại sau:... => Đầu tiên, chúng ta đã có file Sqlite bao gồm một bảng:”ThongTin” gồm c
Trang 1HƯỚNG DẪN SỬ DỤNG SQLITE TRONG IOS
Sqlite là gì? Công cụ hỗ trợ tạo ra một file Sqlite ? Truy vấn sqlite trong lập trình IOS… Tất cả những câu hỏi trên mình sẽ trả lời cho các bạn trong hướng dẫn này
SQLite là một thư viện phần mềm mà triển khai một SQL Database Engine truyền thống, không cần Server, không cần cấu hình và nhỏ gọn SQLite là một trong những Database Engine phát triển nhanh nhất, nhưng sự phát triển của nó
là về mặt tính phổ biến, không phải là về mặt kích cỡ SQLite là mã nguồn mở
SQLite là gì?
Nói một cách đơn giản SQLite là phần mềm quản lý cơ sở dữ liệu (DBMS) tương tự như Mysql, PostgreSQL… Đặc điểm của SQLite là gọn, nhẹ, đơn giản Chương trình gồm 1 file duy nhất vỏn vẹn chưa đến 400kB, không cần cài đặt, không cần cấu hình hay khởi động mà có thể sử dụng ngay Dữ liệu Database cũng được lưu ở một file duy nhất Không có khái niệm user, password hay quyền hạn trong SQLite Database
SQLite không thích hợp với những hệ thống lớn nhưng ở quy mô vừa tầm thì SQLite phát huy uy lực và không hề yếu kém về mặt chức năng hay tốc độ Với các đặc điểm trên SQLite được sử dụng nhiều trong việc phát triển, thử nghiệm … và là sự lưa chọn phù hợp cho những người bắt đầu học Database
SQLite Engine không là một Standalone Process giống như các cơ sở dữ liệu khác, bạn có thể liên kết nó một cách tĩnh hoặc một cách động tùy theo yêu cầu với ứng dụng của bạn SQLite truy cập các file lưu giữ của nó một cách trực tiếp
Trang 2Tại sao nên sử dụng SQLite?
SQLite không yêu cầu một tiến trình Server riêng rẽ để hoạt động
đặt
đơn
đủ hoặc nhỏ hơn 250kB khi đã bỏ qua các tính năng tùy ý
vi
ACID, đảm bảo truy cập an toàn từ nhiều tiến trình hoặc thread
SQLite hỗ trợ hầu hết các tính năng của một ngôn ngữ truy vấn trong chuẩn SQL92
dễ dàng sử dụng
và Windows (Win32, WinCE, WinRT)
Công cụ tạo file sqlite:
Tải về firefox và cài đặt:
1 https ://www.mozilla.org/vi/firefox/new/
Sau khi cài đặt xong mở fireFox: Chọn vào biểu tượng 4 gạch như hình vẽ, Chọn Add- ons, Vào ô search tìm kiếm “sqlite manager” và Thêm nó vào fireFox
Trang 3
Sau khi cài đặt xong chọn vào customize thêm app sqlite Manager kéo vào menu Ok như thế chúng ta đã có công cụ sqlite manager!!!
Tạo một File sqlite :
Mở ứng dụng : Chọn vào Database-> New Database-> đặt tên “infor” chọn Ok sau đó chọn vị trí lưu.! Như thế chúng ta đã tao file thành công
Trang 4Tạo một bảng dữ liệu mới để truy vấn : phải chuột vào Table, chọn create Table
Ta sẽ xuất hiện hộp thoại sau:
Trang 5
Đặt tên cho bảng dữ liệu ở ” Table Name” :
Column Name: Tên các trường
Data type: Kiểu dữ liệu của trường
Primary Key: Khoá chính
Autoinc: Tự động tăng
Allow Null: không được phép Null
Unique: Giá trị không được phép trùng nhau
Trang 6
Bảng trên đặt tên là: “ThongTin” với các trường mẫu như ví dụ trên Đây là bảng mẫu mình sẽ truy vấn trong bài này
Sau khi tạo xong như trên chúng ta chọn vào Nút OK -> sau đó nhấn vào YES thế là chúng ta đã tạo bảng “ThongTin” thành công
Chọn vào table “ThongTin”, chọn menu Browse & search Nhấn vào nút Add để thêm dữ liệu cho bảng: Ở Đây mình đã thêm dữ liệu như trong bảng
Trang 7Add thêm dữ liệu rồi nhấn Ok sau đó chọn YES: dữ liệu tuỳ các bạn thêm vào, Ở đây mình lấy mẫu dữ liệu ở bảng trên
Trang 8
=> Đầu tiên, chúng ta đã có file Sqlite bao gồm một bảng:”ThongTin” gồm các trường
id, Name, Age, và các dữ liệu mẫu truyền vào
Thêm Framework sqlite3, và thêm file sqlite vào dự án:
Tạo một dự án mới và đặt tên “sqlite”
Trang 10Kéo file sqlite vừa tạo ra vào trong Project, chọn các dấu tick như hình vẽ!
– Thêm frameWork sqlite:
click vào file sqlite-> chọn built phases-> Chọn link binary như hình vẽ-> nhấn vào nút +
để thêm thư viện hỗ trợ,
Trang 11
sau đó tìm đến sqlite3.tbd nhấn vào Add để thêm framwork
Như vậy chúng ta đã thêm được file sqlite, và framework sqlite3.dtb Sau khi thực hiện xong nó sẽ trông như thế này:
Trang 12
Kết nối đến sqlite 3:
Chúng ta tạo ra một class chuyên sử lý kết nối đến CSDL, và các chuẩn truy vấn và lấy
dữ liệu
Vào New file->chọn source-> Chọn Cocoa Touch next,
Đặt tên class quản lý là “DBManager”, kiểu kế thừa là NSObject:
Trang 13sau đó chọn next ,vị trí lưu!
Như thế chúng ta đã tạo được class quản lý:
Nhiệm vụ của chúng ta khai báo và thực thi chuẩn sqlite
Đầu tiên là sao chép file “infor.sql” vào trong thư mục document đây là thư mục lưu lại các file dùng cho tất cả ứng dụng có thể truy cập, Ta không làm việc trực tiếp với
“infor.sql” trong source code Bởi vì khi ta truy vấn dữ liệu trong file bị thay đổi, ảnh hưởng đến dữ liệu ban đầu chúng ta truyền vào!
Sao chép như thế nào? Để sao chép được chúng ta phải xác định được đường dẫn file file trong source code, và đường dẫn đích trong thư mục docments
Trong DBManager.h:
1 #import <Foundation/Foundation.h>
2
3 @interface DBManager : NSObjec t// class quản lý vào ra truy vấn CSDL
4 - instancetype ) initWithDatabaseFilename: ( NSString * ) dbFilename ;// hàm khởi tạo có tham số.
5
Trang 146 @end
Hàm khởi tạo có tham số: tham số truyền vào là tên file
Trong file DBManager.m: Ta khai báo thêm 2 biến, đường dẫn đến file
documents, và tên file sqlite
7 // đường dẫn đến thư mục documents
8 @property( nonatomic, strong ) NSString *documentsDirectory;
9 // tên file + đuôi file
10 @property( nonatomic, strong ) NSString *databaseFilename;
Thực thi hàm khởi tạo có tham số: Mình đã comment rất cụ thể từng dòng lệnh trong code, Ở đây thực thi lấy đường dẫn đến thư mục document, và tên file, gán vào 2 biến chúng ta khai báo phía trên:
11 - instancetype ) initWithDatabaseFilename: ( NSString * ) dbFilename {
12 self = [ super init ] ;
13 if( self ) {
14 // Lấy đường dẫn đến thư mục documents, Kết quả trả về mảng có một phần tử!
15 NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES ) ;
16 // đường dẫn gán vào property documentsDirectory
17 self.documentsDirectory = [ paths objectAtIndex: 0 ] ;
18
19 // Tên file được gán vào property databaseFilename
20 self.databaseFilename = dbFilename;
21
22 // sao chép file ở source code vào trong Thư mục documents
23 [ self copyDatabaseIntoDocumentsDirectory ] ;
24 }
25 return self;
26 }
Hàm cho phép sao chép: Các bạn đọc kỹ phần comment code :
27 - void ) copyDatabaseIntoDocumentsDirectory {
28 // Lấy đường dẫn cụ thể đến file đích bao gồm đường dẫn documents+ tên file + đuôi file
29 NSString *destinationPath = [ self.documentsDirectory
stringByAppendingPathComponent:self.databaseFilename ] ;
30 // Kiểm tra nếu file chưa tồn tại thì cho phép sao chép
31 if( [[ NSFileManager defaultManager ] fileExistsAtPath:destinationPath ]) {
32 NSLog( @ "file chưa tồn tại! Thực hiện sao chép" ) ;
33 // Đường dẫn file ở trong source code
34 NSString *sourcePath = [[[ NSBundle mainBundle ] resourcePath ]
stringByAppendingPathComponent:self.databaseFilename ] ;
35 NSError *error ;// tạo một đối tượng error kiểm tra khi đang sao chép có sinh ra lỗi không
36 // sao chép file từ sourcePath -> documents
37 [[ NSFileManager defaultManager ] copyItemAtPath:sourcePath toPath:destinationPath error:&error ] ;
Trang 1538
39 // Nếu có lỗi sao chép đưa ra thông báo!
40 if( error != nil ) {
41 NSLog( @ "%@" , [ error localizedDescription ]) ;
42 }
43 } else { // ngược lại file đã tồn tại và không cần sao chép gì cả!
44 NSLog( @ "file đã tồn tại" ) ;
45 }
46 }
Như vậy trong hàm khởi tạo có tham số chúng ta đã thực hiện sao chép file sqlite vào trong thư mục docments
Mình sẽ giới thiệu cho các bạn khái quát một số hàm trong Sqlite:
sqlite3_open : Chức năng này được sử dụng để tạo ra và mở một tập tin cơ sở dữ
liệu Nếu file không tồn tại nó sẽ tạo ra và sau đó mở file, nếu tồn tại sẽ mở file
sqlite3_prepare_v2 : Mục đích của chức năng này là để có được một câu lệnh SQL
(truy vấn) ở định dạng chuỗi, và chuyển nó sang một định dạng thực thi được nhận biết bởi SQLite 3
sqlite3_step : Chức năng này thực sự thực hiện một câu lệnh SQL (query) được
chuẩn bị đúng chuẩn sqlite
sqlite3_column_count : Nó trả về tổng số cột (trường) trong một bảng
sqlite3_column_text : Phương pháp này trả về nội dung của một Ô trong mẫu giá
trị của cột đó , trả về định dạng chuỗi C ( char * )
sqlite3_column_name : Nó trả về tên của một cột(trường)
sqlite3_changes : Nó thực sự trả về số lượng các hàng bị ảnh hưởng, sau khi thực
hiện một truy vấn
sqlite3_last_insert_rowid : Nó trả về ID được chèn vào hàng cuối cùng của bảng
sqlite3_errmsg : Nó trả về lỗi mô tả trong SQLite
sqlite3_finalize : Nó xóa một câu truy vấn chuẩn bị trước đó
sqlite3_close : Đóng CLDL
DBManager.h
0 @property( nonatomic, strong ) NSMutableArray *arrColumnNames ;// lưu lại tổng số cột trong một bảng
1
2 @property( nonatomic ) int affectedRows ;// trả về số lượng hàng bị ảnh hưởng.
3
4 @property( nonatomic ) long long lastInsertedRowID ;// trả vê ID
Kết nối: trong file DBManager.m:
Mình đã comment rất cụ thể từng dòng lệnh bên trong đoạn mã sau:
Mình khái quát lại nguyên lý của đoạn mã sau:
Hàm truyền vào tham số : câu lệnh truy vấn, và một biến trạng thái truy vấn:
– Chuẩn bị đường dẫn đích đến file, Ban đầu mở file, nếu không thành công thì nó tạo file và không làm gì cả, Nếu mở file thành công:
Trang 16-> Chuẩn bị một câu truy vấn đúng chuẩn nhận dạng của Sqlite3, Nếu câu truy vấn sai thông báo lỗi mô tả sqlite3, Nếu đúng chuẩn:
Ở đây ta tách ra hai hướng:
Hướng 1 :(Nếu tham số truyền queryExecutable==NO) Truy vấn và có lấy thông tin bản ghi, như trích lọc dữ liệu, lấy danh sách bản ghi(select)…
Và ta thực hiện truy vấn để lấy ra bản ghi
Hướng 2: (Nếu ta truyền tam số queryExecutable==YES) chỉ truy vấn nhưng không lấy
ra bản ghi (UPDATE,DELETE,INSERT,CREATE TABLE);
Cụ thể từng dòng code trong đoạn mã :
1 // Chuẩn mở file sqlite và truy vấn sqlite
2 // truyền vào 2 tham số : câu truy vấn và đối tượng bool để kiểm tra: update,delete, insert, create không lấy dữ liệu ra,chỉ truy vấn: Trích lọc lấy dữ liệu truy vấn và lấy ra bảng dữ liệu.
3 // ở đây mình truyền vào kiểu char bởi vì Sqlite không biết NSString là gì, chỉ cho phép làm việc với char
4
5 - void ) runQuery: ( const char * ) query isQueryExecutable: ( BOOL ) queryExecutable {
6 // Khởi tạo một đối tượng của class sqlite.
7 sqlite3 *sqlite3Database;
8 // Lấy đường dẫn đích đến file.sqlite
9 NSString *databasePath = [ self.documentsDirectory stringByAppendingPathComponent:self.databaseFilename ] ;
10
11 // Khởi tạo mảng kết quả
12 if( self.arrResults != nil ) {// nếu mảng tồn tại(lưu) đối tượng
13 [ self.arrResults removeAllObjects ] ;//xoá tất cả đối tượng
14 self.arrResults = nil ;// set về nil
15 }
16 self.arrResults = [[ NSMutableArray alloc ] init ] ;// khởi tạo lại vùng nhớ cho mảng
17
18 // Tương tự đối với mảng chứa các trường tên cột
19 if( self.arrColumnNames != nil ) {
20 [ self.arrColumnNames removeAllObjects ] ;
21 self.arrColumnNames = nil;
22 }
23 self.arrColumnNames = [[ NSMutableArray alloc ] init ] ;
24
25
26 // Mở cơ sở dữ liệu
27 // truyền vào 2 tham số đường dẫn đích đến file định dạng UTF8, Đối tượng sqlite
28 BOOL openDatabaseResult = sqlite3_open([ databasePath UTF8String ] , &sqlite3Database ) ;
29 if( openDatabaseResult == SQLITE_OK ) {// nếu mở csdl thành công
30 // Đối tượng lưu trữ các truy vấn prepare statement
31 sqlite3_stmt *compiledStatement;
32
33 // Chuyển đổi câu truy vấn ở định dạng chuỗi sang câu truy vấn mà sqlite3 có thể nhận dạng được!
Trang 1734 // các tham số truyền vào đối tượng sqlite3, câu truy vấn,Lấy độ dài câu truy vấn, ở đây -1 độ dài tuỳ ý, đối tượng sqlite3_stmt lưu trữ truy vấn, Con trỏ trỏ tới phần chưa sử dụng của câu truy vấn Sql.
35 // sau khi chuyển đổi câu truy vấn được lưu lại trong compiledStatement
36 BOOL prepareStatementResult = sqlite3_prepare_v2( sqlite3Database, query, - 1 , &compiledStatement, NULL ) ;
37 // Nếu câu truy vấn được chuyển đổi thành công sang dạng sqlite nhận dạng đc.
38 if( prepareStatementResult == SQLITE_OK ) {
39 // Kiểm tra nếu truyền vào QueryExecutable NO thì ta cần trích lọc dữ liệu , đọc dữ liệu ra.
40 if( !queryExecutable ){
41 // Tạo một mảng lưu lại thông tin truy vấn!
42 NSMutableArray *arrDataRow;
43
44 // Thực thi truy vấn cho phép đọc thành công!
45 while(sqlite3_step( compiledStatement ) == SQLITE_ROW ) {
46 // Khởi tạo mảng.
47 arrDataRow = [[ NSMutableArray alloc ] init ] ;
48
49 // trả về tổng số cột
50 int totalColumns = sqlite3_column_count( compiledStatement ) ;
51
52 //lặp hết các cột
53 for( int i= 0 ; i<totalColumns; i++ ){
54 // Trả về nội dung một cột kiểu char
55 char *dbDataAsChars = ( char * )sqlite3_column_text( compiledStatement, i ) ;
56
57 // If there are contents in the currenct column (field) then add them to the current row array.
58 if( dbDataAsChars != NULL ) {
59 // chuyển đổi định sang kiểu string
60 [ arrDataRow addObject: [ NSString stringWithUTF8String:dbDataAsChars ]] ;
61 }
62
63 // Lưu tên của các cột !
64 if( self.arrColumnNames.count != totalColumns ) {
65 dbDataAsChars = ( char * )sqlite3_column_name( compiledStatement, i ) ;
66 [ self.arrColumnNames addObject: [ NSString stringWithUTF8String:dbDataAsChars ]] ;
67 }
68 }
69
70 // Store each fetched data row in the results array, but first check if there is actually data.
71 if( arrDataRow.count > 0 ) { // môt đối tượng trong arrResults là một mảng!
72 [ self.arrResults addObject:arrDataRow ] ;
73 }
74 }
75 }
76 else {
77 // Nếu chỉ truy vấn Update , Delete, insert không cần đưa ra dữ liệu
78
79 // Execute the query.
80 int executeQueryResults = sqlite3_step( compiledStatement ) ;
81 if( executeQueryResults == SQLITE_DONE ) {// Nếu truy vấn thành công "chỉ truy vấn không đọc dữ liệu".
82 // // Trả về số lượng hàng bị ảnh hưởng.
83 // self.affectedRows = sqlite3_changes(sqlite3Database);
84 //
85 // // trả về số đối tượng được chèn vào ở dòng cuối cùng.
Trang 1886 // self.lastInsertedRowID = sqlite3_last_insert_rowid(sqlite3Database);
87 }
88 else {
89 // Lỗi mô tả sqlite.
90 NSLog( @ "DB Error: %s" , sqlite3_errmsg( sqlite3Database )) ;
91 }
92 }
93 }
94 else {
95 // In the database cannot be opened then show the error message on the debugger.
96 // Nếu xảy ra lỗi mô tả sqlite.
97 NSLog( @ "%s" , sqlite3_errmsg( sqlite3Database )) ;
98 }
99
100 // Giải phóng một truy vấn được chuẩn bị
101 sqlite3_finalize( compiledStatement ) ;
102
103 }
104
105 // Đóng lại CSDL
106 sqlite3_close( sqlite3Database ) ;
107 }
Như thế chúng ta có thể truy vấn sqlite, Tuy nhiên để cụ thể cọn gàng mình thêm hai hàm sau trong DBManager.h:
2 hàm giúp ta thực hiện đúng 2 loại truy vấn đã tách thành hướng 2 ở phía trên:
1 - NSArray * ) loadDataFromDB: ( NSString * ) query ;// Truy vấn có đọc dữ liệu ra
2
3 - void ) executeQuery: ( NSString * ) query ;// chỉ truy vấn không đọc dữ liệu
DBManager.m để thực thi :
– Đối với hàm cần trích lọc bản ghi: Ta sẽ trả về một mảng lưu lại bản ghi truy vấn được, truyền vào tham số: câu truy vấn ,và queryExecutable==NO;
– Đối với hàm chỉ truy vấn: ta chỉ cần truyền vào Câu truy vấn ,queryExecutable==YES, không cần trả về bản ghi!
1 - NSArray * ) loadDataFromDB: ( NSString * ) query {
2
3 [ self runQuery: [ query UTF8String ] isQueryExecutable:NO ] ;
4
5 return( NSArray * ) self.arrResults;
6 }
7
8
9 - void ) executeQuery: ( NSString * ) query {