一篇文章教會你如何使用數(shù)據(jù)庫

一.SQLite的介紹

1.為什么要存儲數(shù)據(jù)?

1.1 手機(jī)數(shù)據(jù)大多都是從網(wǎng)絡(luò)加載的,不存儲,每次滾動界面都要從新發(fā)送網(wǎng)絡(luò)請求加載數(shù)據(jù),浪費(fèi)流量

1.2 當(dāng)用戶沒網(wǎng)的時候,就不能正常顯示界面了

1.3 將數(shù)據(jù)存儲到本地,不用每次加載,沒網(wǎng)的時候也可從本地存儲的數(shù)據(jù)拿來顯示

2.存儲數(shù)據(jù)的方式

  • Plist(NSArray\NSDictionary)
    特點(diǎn): 只能存儲系統(tǒng)自帶的數(shù)據(jù)類型, 比如NSDictory, NSArray等等. 自定義的對象無法存儲

  • Preference(偏好設(shè)置\NSUserDefaults)
    特點(diǎn): 本質(zhì)就是一個plist文件; 也是只能存儲系統(tǒng)自帶的數(shù)據(jù)類型, 自定義的對象無法存儲

  • NSCoding(NSKeyedArchiver\NSkeyedUnarchiver)
    特點(diǎn): 可以存儲自己定義的數(shù)據(jù)類型, 但是都是一次性的全數(shù)據(jù)操作

  • SQLite3
    特點(diǎn): 存儲一些大批量的數(shù)據(jù), 排序, 統(tǒng)計等操作

  • Core Data
    特點(diǎn): 對SQLite3的一層面向?qū)ο蟮陌b, 本質(zhì)還是要轉(zhuǎn)換成為對應(yīng)的SQL語句去執(zhí)行

在所有的存儲方式中,SQLite速度最快,效率最高.

3.什么是SQLite?

  • SQLite是一款輕型的嵌入式關(guān)系數(shù)據(jù)庫
  • 它占用資源非常的低,在嵌入式設(shè)備中,可能只需要幾百K的內(nèi)存就夠了
  • 目前廣泛應(yīng)用于移動設(shè)備中存儲數(shù)據(jù)(Android/iOS)
  • 處理數(shù)據(jù)的速度非常快,效率非常高

4.什么是數(shù)據(jù)庫?

  • 數(shù)據(jù)庫(Database)是按照數(shù)據(jù)結(jié)構(gòu)來組織、存儲和管理數(shù)據(jù)的倉庫(類似于excel表格)
  • 數(shù)據(jù)庫可以分為2大種類(了解)
    • 關(guān)系型數(shù)據(jù)庫(主流)
    • 對象型數(shù)據(jù)庫

5.關(guān)系型數(shù)據(jù)庫介紹

Paste_Image.png

二.Navicat軟件的破解

1.什么是Navicat?

Navicat是數(shù)據(jù)庫管理軟件,支持大部分主流數(shù)據(jù)庫(包括SQLite)(收費(fèi),要破解)
可以通過圖形化界面的方式來管理數(shù)據(jù)庫

2.有破解版,可以去網(wǎng)上搜索下載,自己安裝,這里不做介紹

.

三.Navicat軟件的使用

.

1.創(chuàng)建SQLite數(shù)據(jù)庫

Paste_Image.png
Paste_Image.png

2.創(chuàng)建表

2.1 雙擊打開數(shù)據(jù)庫,在tables中點(diǎn)擊右鍵,選中NewTable

2.2 創(chuàng)建表中對應(yīng)的字段,點(diǎn)擊”+”添加字段

2.3 保存,要設(shè)置表格名稱. 名稱規(guī)范: t_名稱 如: t_student

Paste_Image.png

3.設(shè)置主鍵,添加數(shù)據(jù)

.
3.1 什么是主鍵
主鍵就相當(dāng)于身份證一樣,用來區(qū)分每一條數(shù)據(jù)


Paste_Image.png

3.2 設(shè)置主鍵注意點(diǎn)

3.3 添加,刪除,修改數(shù)據(jù)

3.31 直接點(diǎn)擊”+” 添加數(shù)據(jù)
注意:主鍵的值不要修改

3.32 刪除,選中一行,點(diǎn)擊”-“ 直接刪除
注意:刪除一組數(shù)據(jù)后,主鍵值就不會再被回收使用. 一個主鍵值只對應(yīng)一條數(shù)據(jù),無論數(shù)據(jù)是否存在

3.33 修改數(shù)據(jù)
雙擊想要修改的數(shù)據(jù),直接修改

四.SQLite的使用步驟

1.創(chuàng)建數(shù)據(jù)庫(一個用于存儲數(shù)據(jù)的文件)
通常后綴名為: .db 或 .sqlite

2.創(chuàng)建表用于存儲數(shù)據(jù)

  • 創(chuàng)建表時需要指定該表有哪些字段
  • 比如學(xué)生表有:學(xué)號/姓名/年齡/身高等

3.對表進(jìn)行增刪改查操作

  • 比如添加一條學(xué)生數(shù)據(jù):型號:1/姓名:why/年齡:18/身高:1.88

五.SQL簡介

1.怎么在程序中使用SQLite?

 真實(shí)使用SQLite時用代碼來操作的

2.怎么用代碼操作SQLite?

 使用SQL語句來操作

3.SQL介紹 不做過多介紹,直接看下定義就行了

Paste_Image.png

六.在代碼中使用DDL(數(shù)據(jù)定義語句)

1.先導(dǎo)入libsqlite3.tba框架(c語言)

2.創(chuàng)建橋接文件,配置橋接文件(不會的話,看之前筆記)

3.創(chuàng)建數(shù)據(jù)庫

   // 創(chuàng)建數(shù)據(jù)庫
    // 文件路徑 :
    // 1.獲取數(shù)據(jù)庫的存放路徑(沙盒中)
    let filePath = "/Users/xiaomage/Desktop/123.sqlite"
    let cString = filePath.cStringUsingEncoding(NSUTF8StringEncoding)!

    // 2.定義數(shù)據(jù)庫對象(后面還要用,定義一個屬性替代)
    // var db : COpaquePointer = nil

    // 3.打開/創(chuàng)建 數(shù)據(jù)庫對象
    if sqlite3_open(cString, &db) == SQLITE_OK {
        print("創(chuàng)建/打開數(shù)據(jù)庫成功")
    } else {
        print("失敗")
    }
}

4.創(chuàng)建表

4.1 創(chuàng)建SQL語句

4.2 執(zhí)行語句(要對語句進(jìn)行判斷) if 語句 == SQLITE_OK

4.3 創(chuàng)建表格式

        CREATE TABLE IF NOT EXISTS '表名' (
    '字段名' 類型(INTEGER, REAL, TEXT, BLOB)
            NOT NULL    不允許為空
            PRIMARY KEY    主鍵
            AUTOINCREMENT 自增長,
    '字段名2' 類型,
    ...
)

4.4 語句說明

  • CREATE TABLE:創(chuàng)建一張表
  • IF NOT EXISTS:不存在則創(chuàng)建
  • 't_student':表的名稱
  • NOT NULL:不允許為空
  • PRIMARY KEY:主鍵
  • AUTOINCREMENT:自動增加
  • 'id' INTEGER:有一個ID字段,類型是INTEGER
Paste_Image.png

5.刪除表

5.1刪除表的格式

 DROP TABLE IF EXISTS '表名';

5.2 語句說明

 DROP TABLE:刪除表
 IF EXISTS:存在則刪除
 '表名':要刪除的表的名稱

   // 1.獲取要執(zhí)行的SQL語句
    let createTableSQL = "DROP TABLE IF EXISTS t_student;"

    // 2.執(zhí)行語句
    if sqlite3_exec(db, createTableSQL.cStringUsingEncoding(NSUTF8StringEncoding)!, nil, nil, nil) == SQLITE_OK {
        print("刪除表成功")
    } else {
        print("刪除表失敗")
    }
}

6.封裝SQL語句

6.1 創(chuàng)建/打開數(shù)據(jù)庫的代碼全部一樣,可以封裝起來

6.2 創(chuàng)建語句,執(zhí)行語句步驟都一樣,只有 語句的內(nèi)容不一樣,可以把語句當(dāng)做參數(shù),封裝起來

6.3 封裝工具類,最好把實(shí)例對象設(shè)計為單例

class SQLiteManager {

// 設(shè)計單例對象
static let shareInstance : SQLiteManager = SQLiteManager()

// 數(shù)據(jù)庫對象
var db : COpaquePointer = nil
}

// MARK:- 打開數(shù)據(jù)庫的操作
extension SQLiteManager {
    func openDB(filePath : String) -> Bool {
    // 1.將Swift字符串轉(zhuǎn)成C語言的字符串
    let cString = filePath.cStringUsingEncoding(NSUTF8StringEncoding)!

    // 3.打開/創(chuàng)建數(shù)據(jù)庫對象
    return sqlite3_open(cString, &db) == SQLITE_OK
}
}

// MARK:- 執(zhí)行SQL語句
extension SQLiteManager {
func execSQL(sqlString : String) -> Bool {
    // 1.將Swift字符串轉(zhuǎn)成C語言的字符串
    let cSQLString = sqlString.cStringUsingEncoding(NSUTF8StringEncoding)!

    // 2.執(zhí)行語句
    return sqlite3_exec(db, cSQLString, nil, nil, nil) == SQLITE_OK
}
}

七.在代碼中使用DML(數(shù)據(jù)操作語句)

1.插入數(shù)據(jù)

1.1 插入數(shù)據(jù)格式

INSERT INTO 't_student' (name, age, height) VALUES ('why', 18, 1.88);

1.2 語句說明

  • INSERT INTO: 插入數(shù)據(jù)

  • 't_student': 在哪一個表中插入數(shù)據(jù)

  • (數(shù)據(jù)的字段): 給哪些字段插入數(shù)據(jù)

  • VALUES ('why', 18, 1.88): 插入的具體值

     // 1.插入數(shù)據(jù)(獲取插入語句)
      let insertSQL = "INSERT INTO t_student (name, age, height) VALUES ('why', 18, 1.88);"
      // 2.執(zhí)行語句
      SQLiteManager.shareInstance.execSQL(insertSQL)
    

2.更新數(shù)據(jù)

1.1 更新數(shù)據(jù)格式

UPDATE 't_student' SET 字段 = '值' WHERE 條件判斷;

1.2 語句說明

  • UPDATE: 跟新數(shù)據(jù)

  • 't_student': 在哪一個表中更新數(shù)據(jù)

  • SET 字段 = '值': 更新怎樣的數(shù)據(jù)

  • WHERE 條件判斷: 更新哪些數(shù)據(jù)

     // 1.獲取更新語句
      let updateSQL = "UPDATE t_student SET name = 'yz';"
      // 2.執(zhí)行語句
      SQLiteManager.shareInstance.execSQL(updateSQL)
    

3.刪除數(shù)據(jù)

3.1 刪除數(shù)據(jù)格式

DELETE FROM t_student;
DELETE FROM t_student WHERE age < 50;

3.2 語句說明

  • DELETE FROM: 從表中刪除數(shù)據(jù)

  • t_student : 表名

  • 可以跟條件也可以不跟:不跟表示刪除所有的數(shù)據(jù)

       // 1.獲取刪除語句
      let deleteSQL = "DELETE FROM t_student;"
      // 2.執(zhí)行語句
      SQLiteManager.shareInstance.execSQL(deleteSQL)
    

4.真實(shí)開發(fā)如何插入數(shù)據(jù)

4.1 真實(shí)開發(fā)插入數(shù)據(jù),不可能一條一條去寫
4.2 一般來說,我們開發(fā)都是面向模型的
4.3 可以把要插入的數(shù)據(jù)包裝成模型
4.4 在模型中提供方法,快速插入數(shù)據(jù)
4.5 遍歷模型數(shù)組,利用模型中快速插入數(shù)據(jù)的方法插入數(shù)據(jù)

5.怎么把數(shù)據(jù)包裝成模型?

遍歷數(shù)據(jù),把數(shù)據(jù)的每一個字段作為模型的屬性保存起來

 // 模擬從網(wǎng)絡(luò)服務(wù)器中請求到很多數(shù)據(jù)(實(shí)際中數(shù)據(jù)是網(wǎng)絡(luò)來的,這里自己寫模擬)
    for _ in 0..<100 {
        let name = "zs\(arc4random_uniform(100))"
        let age = Int(10 + arc4random_uniform(10))
        let height = 1 + Double(arc4random_uniform(10)) / 10.0

        let stu = Student(name: name, age: age, height: height)

        stus.append(stu)
    }

模型中代碼:

 class Student: NSObject {
     var name : String = ""
     var age : Int = 0
     var height : Double = 0.0

     init(name : String, age : Int, height : Double) {
         self.name = name
         self.age = age
         self.height = height
     }
 }

 extension Student {
     func insertDB() {
         // 1.插入數(shù)據(jù)(獲取插入語句)
         let insertSQL = "INSERT INTO t_student (name, age, height) VALUES ('\(name)', \(age), \(height));"
         // 2.執(zhí)行語句
         SQLiteManager.shareInstance.execSQL(insertSQL)
     }
 }

控制器中快速插入

   for stu in stus {
             stu.insertDB()
         }

6.插入數(shù)據(jù)的優(yōu)化

6.1 如果有大量數(shù)據(jù)插入,在主線程執(zhí)行,會阻塞ui

6.2 插入大量數(shù)據(jù)怎么優(yōu)化?

6.21 在子線程進(jìn)行數(shù)據(jù)插入

6.22 手動開啟事務(wù)
如果一條條數(shù)據(jù)進(jìn)行插入時,那么每插入一條數(shù)據(jù)就會開啟一次事務(wù).(開啟事務(wù)耗時)
但是如果有明確的開啟事務(wù),那么系統(tǒng)就不會在插入每條數(shù)據(jù)時,再開啟事務(wù)

 dispatch_async(dispatch_get_global_queue(0, 0)) {
      //獲取插入數(shù)據(jù)開始時間
        let startTime = CACurrentMediaTime()
        // 開啟事務(wù)
        let startSQL = "BEGIN TRANSACTION;"
        SQLiteManager.shareInstance.execSQL(startSQL)

        for stu in self.stus {
            stu.insertDB()
        }
        //關(guān)閉事務(wù)
        let commitSQL = "COMMIT TRANSACTION;"
        SQLiteManager.shareInstance.execSQL(commitSQL)
          //獲取插入數(shù)據(jù)結(jié)束時間
        let endTime = CACurrentMediaTime()
          //獲取插入數(shù)據(jù)耗時
        print(endTime - startTime)
    }
}

八.在代碼中使用DQL(數(shù)據(jù)查詢語句)

.

1.查詢語句

Paste_Image.png

2.查詢數(shù)據(jù)代碼實(shí)現(xiàn)步驟

2.1 獲取查詢語句
2.2 執(zhí)行查詢語句(得到的結(jié)果保存到數(shù)組中,最好是字典數(shù)組)
2.3 遍歷數(shù)組,字典轉(zhuǎn)模型
2.4 從模型中讀取數(shù)據(jù)

代碼實(shí)現(xiàn):

   // 1.獲取查詢語句
    let querySQL = "SELECT * FROM t_student LIMIT 30, 30;";

    // 2.執(zhí)行語句  (執(zhí)行語句封裝到了一個方法里面)
    guard let dictArray = SQLiteManager.shareInstance.querySQL(querySQL) else {
        return
    }

    // 3.遍歷數(shù)組
    var tempArray = [Student]()
    for dict in dictArray {
        // 字典轉(zhuǎn)模型
        tempArray.append(Student(dict: dict))
    }

    for stu in tempArray {
        print(stu.name, stu.age)
    }

 //執(zhí)行語句代碼實(shí)現(xiàn)
 func querySQL(querySQL : String) -> [[String : NSObject]]? {
    // 0.將Swift字符串轉(zhuǎn)成C語言字符串
    let cString = querySQL.cStringUsingEncoding(NSUTF8StringEncoding)!

    // 1.定義游標(biāo)(指針)
    var stmt : COpaquePointer = nil

    // 2.給游標(biāo)賦值
    // 1> 參數(shù)一: 數(shù)據(jù)庫對象
    // 2> 參數(shù)二: SQL語句
    // 3> 參數(shù)三: 該SQL語句的長度 -1 --> 系統(tǒng)自動計算
    // 4> 參數(shù)四: 游標(biāo)的地址
    guard sqlite3_prepare_v2(db, cString, -1, &stmt, nil) == SQLITE_OK else {
        return nil
    }

    // 3.取出所有的數(shù)據(jù)
    // 3.1.定義字典數(shù)組
    var dictArray = [[String : NSObject]]()

    // 3.2.判斷是否有該條數(shù)據(jù)
    while sqlite3_step(stmt) == SQLITE_ROW {
        // 3.3.獲取字段的個數(shù)
        let count = sqlite3_column_count(stmt)
        // 3.4.定義字典
        var dict = [String : NSObject]()
        // 3.5.遍歷每一個字典
        for i in 0..<count {
            // 3.6.取出該列的鍵
            let ckey = sqlite3_column_name(stmt, i)
            guard let key = String(UTF8String : ckey) else {
                continue
            }
            // 3.7.取出該列的值
            let cvalue = UnsafePointer<Int8>(sqlite3_column_text(stmt, i))
            //將c語言字符串轉(zhuǎn)成swift字符串
            let value = String(UTF8String : cvalue)

            // 3.8.將鍵值對放入到字典中
            dict[key] = value
        }
        // 3.9.將字典放入到數(shù)組中
        dictArray.append(dict)
    }
    return dictArray
}
}

九.FMDB框架的使用

.
1.FMDB框架的作用?
FMDB是用來簡化操作數(shù)據(jù)庫的框架

2.FDMB的基本使用

2.1 創(chuàng)建數(shù)據(jù)庫

private lazy var db : FMDatabase = FMDatabase(path: "/Users/xiaomage/Desktop/321.sqlite")
    // 創(chuàng)建FMDatabase對象
    // 打開/創(chuàng)建數(shù)據(jù)
    if db.open() {
        print("打開成功")
    } else  {
        print("失敗")
    }

2.2 創(chuàng)建/刪除 表 插入/更新/刪除 數(shù)據(jù)
本質(zhì)都是一樣的只有語句的內(nèi)容不一樣
將語句內(nèi)容換成對應(yīng)的操作,就能執(zhí)行該項(xiàng)操作(和SQLite語句一樣)

       // 1.獲取創(chuàng)建表的語句
    let createSQL = "INSERT INTO t_person (name, age, height) VALUES ('why', 18, 1.88);"
    // 2.執(zhí)行語句
    db.executeUpdate(createSQL, withArgumentsInArray: nil)

2.3 查詢數(shù)據(jù)

 var db : FMDatabase?

func querySQL(querySQL : String) -> [[String : NSObject]]? {
    // 0.判斷db是否有值  db定義為屬性
    guard let db = db else {
        return nil
    }
    // 1.執(zhí)行查詢語句   結(jié)果為集合
    let results = db.executeQuery(querySQL, withArgumentsInArray: nil)

    // 2.獲取數(shù)據(jù)
    // 2.0.定義數(shù)據(jù)
    var dictArray = [[String : NSObject]]()

    // 2.1.判斷結(jié)果集中是否有內(nèi)容
    while results.next() {

        let count = results.columnCount()

        var dict = [String : NSObject]()

        for i in 0..<count {
            let key = results.columnNameForIndex(i)
            let value = results.stringForColumnIndex(i)

            dict[key] = value
        }
        dictArray.append(dict)
    }
    return dictArray
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容