10分鐘理解Android數據庫的創建與使用(附具體解釋和演示樣例代碼)
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數據庫的創建與使用(附具體解釋和演示樣例代碼)