1. 程式人生 > >10分鐘理解Android數據庫的創建與使用(附具體解釋和演示樣例代碼)

10分鐘理解Android數據庫的創建與使用(附具體解釋和演示樣例代碼)

fault 大小 help double 查詢過濾 rem d+ tof red

1.Android數據庫簡單介紹.
Android系統的framework層集成了Sqlite3數據庫。我們知道Sqlite3是一種輕量級的高效存儲的數據庫。
Sqlite數據庫具有以下長處:
(1)零配置,無需安裝和配置;
(2)儲存在單一磁盤文件裏的一個完整的數據庫。
(3)數據庫文件能夠在不同字節順序的機器間自由共享;
(4)支持數據大小至2TB;
(5)足夠小。全部源碼大致3萬行C代碼。250KB;
(6)比眼下流行的大多數數據庫的操作要快。
(7)開源。

2.Sqlite 基本操作語句和重要概念

(1)創建數據庫

創建數據庫實際上並不是通過SQL語句來創建。創建數據庫能夠通過sqlite3 新數據庫名 來創建,比方創建一個名為school.db的數據庫,在命令行下輸入“sqlite3 school.db;”就可以。

(2)創建表

創建表的SQL語法為:
create table 表名(字段1 數據約束類型,…,字段n 數據約束類型)。
註意:每一條SQL語句都以分號結尾
Sqlite數據庫支持的數據庫類型大致分為5種。各自是:

NUll 數據值為空
INTEGER 整型
REAL 浮點型數據
TEXT 字符類型,使用數據庫編碼(UTF-8等)存放
BLOB 僅僅是一個數據塊,全然依照輸入存放

註意:SQLite3數據庫中不論什麽列,除了整形主鍵列,能夠用於存儲不論什麽一個存儲列的值,SQLite沒有單獨的布爾存儲類型,你能夠使用INTEGER的0和1表示true和false,另外。SQLite也沒有代表時間和日期的數據類型。能夠轉化為TEXT或者INTEGER來存儲


經常使用的數據庫約束包括以下幾種:

PRIMARY KEY 主鍵 它是非空且唯一的
NOT NULL 非空
UNIQUE 唯一
FOREIGN KEY 外鍵
CHECK 條件檢查
DEFAULT 字段的默認值

以下舉例說明創建一個班級表,表中有3個字段,各自是自增的主鍵id、專業、年份。

創建表的SQL語句例如以下圖所看到的

技術分享

(3)插入數據

SQL語句插入數據的關鍵字為insert。完整的格式例如以下圖所看到的

技術分享

比如在classes表中插入一條數據,這裏我僅僅插入了一條數據中的2個字段,寫法例如以下圖

技術分享
註意:插入的這些數據在表中一定要有相應的字段。不然就會報錯!

insert語句支持批量插入數據,比方我要把students表中的數據都導入表stu中。SQL語句為

insert into stu select * from students;

(4)查詢語句
Select語句的通用格式例如以下:

技術分享

這段語句簡單解釋一下,columns是要查詢的字段,tables表示從哪張表裏面查詢,where是查詢過濾的條件,group by是指依照某個字段分組查詢。order by是排序,limit是限制數量語句,以下我會一一解釋每一個語句須要註意的地方。

1.字段與表的別名
多表查詢時查詢條件相對復雜,表之間可能會產生同樣的字段,這個時候字段前面能夠加上表名以區分。別名就是我們能夠將classes的表名設置為cls。將classes表中的major字段顯示為cmj字段以簡化SQL語句。

2.where條件過濾

where語句中經常使用的邏輯操作符有and、or、not,分別代表與、或、非。

註意where中有一個較為重要的關系操作符叫做like。它是模糊匹配。比如要找到students表中以t開頭的全部學生,那麽相應的SQL為:

select * from students where name like “t%”;

3.Group by 分組

    聚合中有一個重要的功能就是分組。分組就是將得到的結果集依照一定的規則劃分為多個組。

因為該功能不常使用,想要了解的朋友自行查閱資料。

4.排序
select結果集的排序使用的是order by字句。排序有升序和降序兩種。分別相應asc和desc,order by後面緊跟一個或者多個字段。多個字段間用逗號隔開。

5.數量限定
數量限定須要使用limit語句。數量限定的標準格式例如以下:

    limit 返回的數量 offset 偏移量

比如我們希望從students中索引為3的記錄開始索引而且僅僅返回一條語句,SQL例如以下:

select * from students limit 1 offset 2;

6.distinct去重

    distinct用於去除select語句中反復的行。它緊跟在select之後。

(5)update 語句

update 語句用於更新表中的數據,它的格式為:

update table set update_list where predicate;
    update_list是要改動的字段以及值。事實上就是一個字段賦值語句,形式為:字段名 = 字段值,每一個字段賦值語句通過逗號分隔開。興許我會在具體的演示樣例代碼中舉例,在這就只是多闡述。

(6)delete語句
delete語句的格式例如以下:

//當滿足where的條件時。刪除表table中的數據。table是表名
delete from table where predicate;

(7)改動表

    我們知道。隨著項目的演化,最初建立的表可能會面臨改動的情況。

改動表的SQL語句命令為alter。SQLite中的alter命令並沒有實現標準SQL中的全部功能,**它僅僅有改動表名和加入字段兩個功能**,**刪除字段等功能僅僅能通過又一次創建表來實現**。

alter的語法格式為:

alter table tableName {rename to newName | add column 新的字段};
    上述的語法表示alter table之後要操作先跟表名,然後rename to newName 和add column 新的字段兩者2選1。rename to 是重命名。add column是加入新的字段。

(8)drop 命令

    drop命令用於刪除物理存儲介質。

比如刪除表、視圖、索引、觸發器等。

drop的語法格式為:

drop {table | view |index |trigger} name;

(9)數據庫事務的介紹

    事務是一個數據庫操作的運行單元。它定義了一條或多條SQL語句,這些語句要麽被全部運行。要麽全部不運行。它保證了SQL語句的原子性。

事務有begin、commit、rollback3個命令。begin表示開始一個事務,commit表示整個事務操作成功,rollback表示回滾到begin之前。

格式為:

begin。
//SQL語句
[commit | rollback];

註意:事務提供了一種保證多條SQL語句能夠被運行或者不運行。非常大程度上保證了數據庫操作的安全性。而在Android中使用事務。也會提升SQL的運行效率。

    事務的運用簡單舉個樣例,張三給李四轉賬400元。銀行的數據庫中張三的存款金額要減400,李四的存款金額要加400,我們要保證張三扣錢的通過李四收到錢。這個時候就須要用到數據庫事務,要麽兩條SQL語句同一時候成功,要麽同一時候失敗。

(10)Android中封裝的數據庫幫助接口

    我們知道Android的SQLite數據庫是由C和C++實現,因此Android在FrameWork層封裝了一層Java接口,使得開發者能夠更方便的操作數據庫。

基本的類型為SQLiteOpenHelper、SQLiteDatabase以及Cusor。無論怎樣封裝。本質上都是通過構建SQL語句而且提交到SQLite中運行。以下具體介紹。Android中創建數據庫創建表的全部方法。

3.使用Android的接口創建和操作數據庫

一般來說,在Android中創建數據庫僅僅須要以下幾步:

(1)創建一個Java類繼承SQLiteOpenHelper
(2)實現SQLiteOpenHelper的onCreate和onUpdate方法以及構造方法。


(3)通過構造方法創建數據庫,須要傳入數據庫的名稱。Context和數據庫的版本。
(4)在onCreate中完畢創建表和字段的操作,onUpdate中完畢升級操作
(5)通過幫助類的openOrCreateDatabase()方法或者getReadableDatabase()或者getWriteableDatabase()獲取到數據庫完畢數據的操作。

以下附上我的寫的一個演示樣例代碼,當中封裝了推斷數據庫是否存在某個表,是否存在某個字段的方法

數據庫的幫助類,完畢了創建數據庫,創建表

package com.geocompass.gisdatacollection.database;

import android.content.Context;
import android.database.Cursor;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Environment;

import com.geocompass.gisdatacollection.CollectionApplication;

import java.io.File;

/**
 * Created by liuxu on 2017/4/7.
 * 數據庫的操作的幫助類
 */

public class ComplexDatabaseSqlHelper extends SQLiteOpenHelper {
    private static final String TAG = "ComplexDatabaseSqlHelper";
    //數據庫的版本
    private static final int DB_VERSION = 1;

    public SQLiteDatabase getDb() {
        return db;
    }

    private SQLiteDatabase db;
    //數據庫db文件的路徑,由調用者傳入
    private static String mDBPath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "giscoll.db";

    private static ComplexDatabaseSqlHelper mDBSqlHelper;

    public ComplexDatabaseSqlHelper(Context context, String DBpath) {
        super(context, DBpath, null, DB_VERSION);
        mDBPath = DBpath;
        if (db == null) {
            db = SQLiteDatabase.openOrCreateDatabase(DBpath, null);
        }
        onCreate(db);
    }

    public ComplexDatabaseSqlHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    public ComplexDatabaseSqlHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
        super(context, name, factory, version, errorHandler);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String CREATE_POINT = "create table tab_point ("
                + "id integer primary key autoincrement,"
                + "lon double, "
                + "lat double, "
                + "type integer) ";
        String CREATE_INTERSECTION = "create table tab_intersection ("
                + "inter_id integer primary key autoincrement,"
                + "interLon double, "
                + "interLat double, "
                + "interRouteID text) ";
        String CREATE_ROUTE = "create table tab_route ("
                + "route_name text,"
                + "startPointID integer, "
                + "endPointID integer, "
                + "geometryID text, "
                + "Geometry text) ";
        ;
        //假設不存在該表。則創建該表
        if (!tableIsExist("tab_point")) {
            db.execSQL(CREATE_POINT);
        }
        if (!tableIsExist("tab_intersection")) {
            db.execSQL(CREATE_INTERSECTION);
        }
        if (!tableIsExist("tab_route")) {
            db.execSQL(CREATE_ROUTE);
        }

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

    /**
     * 獲取數據庫的幫助類
     *
     * @return
     */
    public static ComplexDatabaseSqlHelper getDBSqlHelper() {
        if (mDBSqlHelper == null) {
            synchronized (ComplexDatabaseSqlHelper.class) {
                if (mDBSqlHelper == null) {
                    mDBSqlHelper = new ComplexDatabaseSqlHelper(CollectionApplication.getmContext(), mDBPath);
                }
            }
        }
        return mDBSqlHelper;
    }

    /**
     * 依據sql查詢數據庫的方法
     *
     * @param sql
     * @return
     */
    public Cursor query(String sql) {
        return db.rawQuery(sql, null);
    }

    /**
     * 運行Sql語句
     *
     * @param sql
     */
    public void execSQL(String sql) {
        db.execSQL(sql);
    }

    /**
     * 推斷表格是否存在
     *
     * @param tableName
     * @return
     */
    public boolean tableIsExist(String tableName) {
        boolean result = false;
        if (tableName == null) {
            return false;
        }
        Cursor cursor = null;
        try {
            //db = SQLiteDatabase.openDatabase(this.mDBPath,null,SQLiteDatabase.OPEN_READONLY);
            String sql = "select count(*) as c from Sqlite_master where type =‘table‘ and name =‘" + tableName.trim() + "‘ ";
            cursor = db.rawQuery(sql, null);
            if (cursor.moveToNext()) {
                int count = cursor.getInt(0);
                if (count > 0) {
                    result = true;
                }
            }
            cursor.close();
        } catch (Exception e) {
            // TODO: handle exception
            result = false;
        }
        return result;
    }

    /**
     * 推斷表中是否包括某個字段
     *
     * @param tableName
     * @param columnName
     * @return
     */
    public boolean columnIsExistsInTable(String tableName, String columnName) {
        boolean result = false;
        Cursor cursor = null;
        try {
            //  db = SQLiteDatabase.openDatabase(this.mDBPath, null, SQLiteDatabase.OPEN_READONLY);
            cursor = db.rawQuery("select * from sqlite_master where name = ? and sql like ?

" , new String[]{tableName, "%" + columnName + "%"}); result = null != cursor && cursor.moveToFirst(); } catch (Exception ignored) { } finally { if (null != cursor && !cursor.isClosed()) { cursor.close(); } } return result; } private void open() { if (db != null && !db.isOpen()) db = SQLiteDatabase.openOrCreateDatabase(mDBPath, null); } }

數據庫的操作類,完畢了對數據庫表中數據的插入和查詢

package com.geocompass.gisdatacollection.database.manage;

import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;

import com.geocompass.gisdatacollection.model.Intersection;
import com.geocompass.gisdatacollection.model.Point;
import com.geocompass.gisdatacollection.model.Route;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by liuxu on 2017/4/10.
 * 封裝了對數據庫表的增刪改查方法
 */

public class ComplexDBDao {
    private SQLiteDatabase db;
    public ComplexDBDao(SQLiteDatabase db) {
        this.db = db;
    }

    /**
     * 插入一個點到tab_point表
     * @param point
     * @return
     */
    public boolean insert(Point point){
        String INSERT_POINT = "INSERT INTO tab_point(lon,lat,type) VALUES (" + point.lon + "," + point.lat + "," + point.point_type + ")";
        try{
            db.execSQL(INSERT_POINT);
        }catch(SQLException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 插入一個節點到tab_intersection表中
     * @param intersection
     * @return
     */
    public boolean insert(Intersection intersection){
        String INSERT_INTERSECTION = "insert into tab_intersection(interLon,interLat,interRouteID) values ("+intersection.interLon+","+intersection.interLat+",‘"+
                intersection.inter_route_id+"‘)";
        try{
            db.execSQL(INSERT_INTERSECTION);
        }catch(SQLException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 插入一條Route到tab_route表中
     * @param route
     * @return
     */
    public boolean insert(Route route){
        String  INSERT_ROUTE = "insert into tab_route (route_name,startPointID,endPointID,geometryID,Geometry) values(‘"+route.route_name+
                "‘,"+route.startPointID+","+route.endPointID+",‘"+route.geometryID+"‘,‘"+route.Geometry+"‘)";
        try{
            db.execSQL(INSERT_ROUTE);
        }catch(SQLException e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 查詢出數據庫中全部的Points
     * @return
     */
    public List<Point> findAllTabPoint(){
        String sql_select = "select * from tab_point order by id";
        //請補充sql運行語句
        Cursor cursor = db.rawQuery(sql_select,null);
        int IDIndex = cursor.getColumnIndex("id");
        int lonIndex = cursor.getColumnIndex("lon");
        int latIndex = cursor.getColumnIndex("lat");
        int typeIndex = cursor.getColumnIndex("type");
        List<Point> list = new ArrayList<>();
        while (cursor.moveToNext()) {
            Point point = new Point();
            point.id = cursor.getInt(IDIndex);
            point.lon = cursor.getDouble(lonIndex);
            point.lat = cursor.getDouble(latIndex);
            point.point_type = cursor.getInt(typeIndex);
            list.add(point);
        }
        return list;
    }

    /**
     * 查詢出數據庫中全部的Intersection
     * @return
     */
    public List<Intersection> findAllTabIntersection(){
        String sql_select = "select * from tab_intersection order by inter_id";
        //請補充sql運行語句
        Cursor cursor = db.rawQuery(sql_select,null);
        int interIdIndex = cursor.getColumnIndex("inter_id");
        int interLonIndex = cursor.getColumnIndex("interLon");
        int interLatIndex = cursor.getColumnIndex("interLat");
        int interRouteIDIndex = cursor.getColumnIndex("interRouteID");
        List<Intersection> list = new ArrayList<>();
        while (cursor.moveToNext()) {
            Intersection intersection = new Intersection();
            intersection.inter_id = cursor.getInt(interIdIndex);
            intersection.interLon = cursor.getDouble(interLonIndex);
            intersection.interLat = cursor.getDouble(interLatIndex);
            intersection.inter_route_id = cursor.getString(interRouteIDIndex);
            list.add(intersection);
        }
        return list;
    }

    /**
     * 查詢出數據庫中全部的Route
     * @return
     */
    public List<Route> findAllTabRoute(){
        String sql_select = "select * from tab_route ";
        //請補充sql運行語句
        Cursor cursor = db.rawQuery(sql_select,null);
        int routeNameIndex = cursor.getColumnIndex("route_name");
        int startPointIDIndex = cursor.getColumnIndex("startPointID");
        int endPointIDIndex = cursor.getColumnIndex("endPointID");
        int geometryIDIndex = cursor.getColumnIndex("geometryID");
        int geometryIndex = cursor.getColumnIndex("Geometry");
        List<Route> list = new ArrayList<>();
        while (cursor.moveToNext()) {
            Route route = new Route();
            route.route_name = cursor.getString(routeNameIndex);
            route.startPointID = cursor.getInt(startPointIDIndex);
            route.endPointID = cursor.getInt(endPointIDIndex);
            route.geometryID = cursor.getString(geometryIDIndex);
            route.Geometry = cursor.getString(geometryIndex);
            list.add(route);
        }
        return list;
    }
}

這些知識都是數據庫的基礎知識。當然復雜的知識也是在基礎知識的基礎上拼接起來的,先學好了基礎才幹談復雜項目中多個表多個字段數據庫的運用!

我非常喜歡的一句話,不積跬步無以至千裏,一直陪伴著我的學習和工作!


不足之處請指正。謝謝!

10分鐘理解Android數據庫的創建與使用(附具體解釋和演示樣例代碼)