自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Android的數(shù)據(jù)存儲(下)

移動開發(fā) Android
Android中使用android.database.sqlite.SQLiteDatabase來表示一個數(shù)據(jù)庫對象,它提供了兩種模式來幫助開發(fā)者進(jìn)行增刪改查等基本數(shù)據(jù)庫操作。

一、Android數(shù)據(jù)庫使用

Android中使用android.database.sqlite.SQLiteDatabase來表示一個數(shù)據(jù)庫對象,它提供了兩種模式來幫助開發(fā)者進(jìn)行增刪改查等基本數(shù)據(jù)庫操作。

利用SQL語句描述操作
利用SQL語句調(diào)用SQLiteDatabase.execSql或SQLiteDatabase.rawQuery來執(zhí)行操作。

  1. //利用sql查詢數(shù)據(jù) 
  2. Cursor data = db.rawQuery("select id,name from table"); 
  3.  
  4. //利用sql插入數(shù)據(jù) 
  5. db.execSql("insert into contacts (id,name) values (2,'cpacm')"); 

稍微學(xué)過sql語句的人應(yīng)該都看的懂上面的代碼(其實看語句的意思也能知道個大概~)
在 這里我來解釋一下Cursor(游標(biāo))的作用吧,游標(biāo)不能顧名思義(up主當(dāng)時學(xué)習(xí)數(shù)據(jù)庫時一度將游標(biāo)當(dāng)做與C語言里面的指針變量一樣,雖然有點對,但意 思還是理解錯了),Cursor它是系統(tǒng)為用戶開設(shè)的一個數(shù)據(jù)緩沖區(qū),是的,它是一塊數(shù)據(jù)區(qū)域,存放SQL語句的執(zhí)行結(jié)果。但是它也提供了能從包括多條數(shù) 據(jù)記錄的結(jié)果集中每次提取一條記錄的機制,這一點也跟指針很像。游標(biāo)總是與一條SQL選擇語句相關(guān)聯(lián)因為游標(biāo)由結(jié)果集(可以是零條、一條或由相關(guān)的選擇語 句檢索出的多條記錄)和結(jié)果集中指向特定記錄的游標(biāo)位置組成。當(dāng)決定對結(jié)果集進(jìn)行處理 時,必須聲明一個指向該結(jié)果集的游標(biāo)。用C語言作比較的話,如果寫過對文件進(jìn)行處理的程序,那么游標(biāo)就像您打開文件所得到的文件句柄一樣,只要文件打開成 功,該文件句柄就可代表該文件??傊涀?,游標(biāo)是一塊有著特有記號的一塊數(shù)據(jù)區(qū)域,能夠讓用戶逐條從中讀取出數(shù)據(jù)。
結(jié)構(gòu)化的方式描述數(shù)據(jù)庫的操作
這樣即使我們不熟悉SQL語句,也能使用最熟悉的面向?qū)ο蟮姆绞竭M(jìn)行數(shù)據(jù)庫操作。

  1. //結(jié)構(gòu)化的方式查詢數(shù)據(jù) 
  2. Cursor data = db.query("contacts",new String[]{"id","name"},null,null,null,null,null); 
  3.  
  4. //結(jié)構(gòu)化方式插入數(shù)據(jù) 
  5. ContentValue values = new ContentValues(); 
  6. values.put("id",2); 
  7. values.put("name","cpacm"); 
  8. db.insert("table",null,values);
  1. /** 
  2. * 參數(shù)說明 
  3. * table:數(shù)據(jù)表名,columns:需要顯示的列名,如果為null則相當(dāng)與* 
  4. * selection:相當(dāng)于sql語句的where條件;selectionArgs數(shù)組放的是where條件要替換的?號 
  5. * groupBy:SQL語句的Group, orderBy: 排序,默認(rèn)asc 
  6. **/ 
  7. public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy){ 

比如說我要查詢的SQL語句為

SELECT CustomerName, SUM(OrderPrice) FROM Orders WHERE Country=?        GROUP BY CustomerName        HAVING SUM(OrderPrice)>500  
    ORDER BY CustomerName  

那么我寫的代碼如下

  1. //數(shù)據(jù)表名 
  2. String table =  "Orders" ;   
  3. //要顯示的列名 
  4. String[] columns = new  String[] { "CustomerName" ,  "SUM(OrderPrice)" };   
  5. //選擇條件 
  6. String selection = "Country=?" ;   
  7. //里面的變量對應(yīng)條件中的問號,多個的時候請一一入座。 
  8. String[] selectionArgs = new  String[]{ "China" };   
  9. //分組名 
  10. String groupBy = "CustomerName" ;   
  11. //分組的條件 
  12. String having = "SUM(OrderPrice)>500" ;   
  13. //按字段排序 
  14. String orderBy = "CustomerName" ;   
  15. Cursor c = db.query(table, columns, selection, selectionArgs, groupBy, having, orderBy);   

這樣就能實現(xiàn)數(shù)據(jù)庫的查詢了。其它的語句參數(shù)都是差不多的,這里就不一一介紹了。

 

public long insert (String table, String nullColumnHack, ContentValues values)

 

 

public int delete(String table, String whereClause, String[] whereArgs)

 

 

public int update(String table, ContentValues values, String whereClause, String[] whereArgs)

 

課外小知識:關(guān)于GroupBy和Having的使用
group by 顧名思義就是按照xxx進(jìn)行分組,它必須有“聚合函數(shù)”來配合才能使用,使用時至少需要一個分組標(biāo)識字段。聚合函數(shù)有:sum()、count()、 avg()等,使用group by目的就是要將數(shù)據(jù)分組進(jìn)行匯總操作。比如上面sql語句的CustomerName,如果它有四個行{“張三”,“李四”,“張三”,“李四”},那 么此時就會分成兩組,分別為張三組和李四組,然后統(tǒng)計出他們使用的orderprice總和。
HAVING作用就是為每一個組指定條件,像 where指定條件一樣,也就是說,可以根據(jù)你指定的條件來選擇行。如果你要使用HAVING子句的話,它必須處在GROUP BY子句之后。還是上面的SQL語句,如果張三的SUM(OrderPrice)沒有超過500,那么張三組就不會顯示。

SQL語句的預(yù)編譯
在實踐中,有的SQL語句需要被反復(fù)使用,為了避免反復(fù)解析SQL語句產(chǎn)生的開銷,可以對需要復(fù)用的SQL語句進(jìn)行預(yù)編譯,來提高數(shù)據(jù)庫操作的執(zhí)行效率。

//編譯復(fù)雜的SQL語句
SQLiteStatement compiledSql = db.compileStatement(aSQL); //執(zhí)行SQL
compiledSql.execute();
  1. //編譯復(fù)雜的SQL語句 
  2. SQLiteStatement compiledSql = db.compileStatement(aSQL); 
  3. //執(zhí)行SQL 
  4. compiledSql.execute(); 

課外小知識:所謂事務(wù)是用戶定義的一 個數(shù)據(jù)庫操作序列,這些操作要么全做要么全不做,是一個不可分割的工作單位。例如,在關(guān)系數(shù)據(jù)庫中,一個事務(wù)可以是一條SQL語句、一組SQL語句或整個 程序。 簡單舉個例子就是你要同時修改數(shù)據(jù)庫中兩個不同表的時候,如果它們不是一個事務(wù)的話,當(dāng)***個表修改完,可是第二表改修出現(xiàn)了異常而沒能修改的情況下,就 只有第二個表回到未修改之前的狀態(tài),而***個表已經(jīng)被修改完畢。 而當(dāng)你把它們設(shè)定為一個事務(wù)的時候,當(dāng)***個表修改完,可是第二表改修出現(xiàn)了異常而沒能修改的情況下,***個表和第二個表都要回到未修改的狀態(tài)!這就是所 謂的事務(wù)回滾。

SQLiteOpenHelper
在SQLiteOpenHelper中,封裝了一個SqliteDatabase對象,使用著可以通過使用此類來進(jìn)行數(shù)據(jù)庫的操作。

  1. package com.example.notebook; 
  2.  
  3. import android.content.Context; 
  4. import android.database.sqlite.SQLiteDatabase; 
  5. import android.database.sqlite.SQLiteOpenHelper; 
  6. import android.database.sqlite.SQLiteDatabase.CursorFactory; 
  7.  
  8.  
  9. public class DBHelper extends SQLiteOpenHelper{ 
  10.     private static final int VERSION=1
  11.     /**  
  12.      * 在SQLiteOpenHelper的子類當(dāng)中,必須有該構(gòu)造函數(shù)  
  13.      * @param context   上下文對象  
  14.      * @param name      數(shù)據(jù)庫名稱  
  15.      * @param factory  
  16.      * @param version   當(dāng)前數(shù)據(jù)庫的版本,值必須是整數(shù)并且是遞增的狀態(tài)  
  17.      */ 
  18.     public DBHelper(Context context,String name,CursorFactory factory,int version){ 
  19.         super(context,name,factory,version); 
  20.     } 
  21.     public DBHelper(Context context, String name, int version){   
  22.         this(context,name,null,version);   
  23.     }   
  24.    
  25.     public DBHelper(Context context, String name){   
  26.         this(context,name,VERSION);   
  27.     } 
  28.     @Override 
  29.     public void onCreate(SQLiteDatabase db) { 
  30.          // 數(shù)據(jù)庫***構(gòu)造時,會調(diào)用該函數(shù),可以在這里構(gòu)造表、索引,等等  
  31.         System.out.println("create a database");   
  32.         //execSQL用于執(zhí)行SQL語句   
  33.         db.execSQL("create table notebook(_id integer primary key autoincrement,pic varchar(50),title varchar(20),content text,time varchar)"); 
  34.          
  35.     } 
  36.     @Override 
  37.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
  38.         // 如果給定的當(dāng)前數(shù)據(jù)庫版本高于已有數(shù)據(jù)庫版本,調(diào)用該函數(shù) 
  39.         System.out.println("upgrade a database"); 
  40.     }   
  41.  

SQLiteOpenHelper的應(yīng)用
新建一個數(shù)據(jù)庫管理類DBManager

  1. package com.example.notebook; 
  2.  
  3. import android.content.ContentValues; 
  4. import android.content.Context; 
  5. import android.database.Cursor; 
  6. import android.database.sqlite.SQLiteDatabase; 
  7. import android.database.sqlite.SQLiteException; 
  8. import android.util.Log; 
  9.  
  10. public class DBManager { 
  11.      
  12. private Context mContext = null
  13.      
  14.     private SQLiteDatabase mSQLiteDatabase = null;//用于操作數(shù)據(jù)庫的對象 
  15.     private DBHelper dh = null;//用于創(chuàng)建數(shù)據(jù)庫的對象 
  16.      
  17.     private String dbName = "note.db";//數(shù)據(jù)庫的名稱 
  18.     private int dbVersion = 1;//數(shù)據(jù)庫的版本 
  19.     public DBManager(Context context){ 
  20.         mContext = context; 
  21.     } 
  22.      
  23. public void open(){ 
  24.         try
  25.             dh = new DBHelper(mContext, dbName, null, dbVersion);//建立數(shù)據(jù)庫 
  26.             if(dh == null){ 
  27.                 Log.v("msg""is null"); 
  28.                 return ; 
  29.             } 
  30.             mSQLiteDatabase = dh.getWritableDatabase();//以可寫方式打開數(shù)據(jù)庫 
  31.             //dh.onOpen(mSQLiteDatabase); 
  32.         }catch(SQLiteException se){ 
  33.             se.printStackTrace(); 
  34.         } 
  35.     } 
  36. public void close(){ 
  37.      
  38.     mSQLiteDatabase.close();//關(guān)閉數(shù)據(jù)庫 
  39.     dh.close(); 
  40.      
  41. public Cursor selectAll(){ 
  42.     Cursor cursor = null
  43.     try
  44.         //sql語句操作 
  45.         String sql = "select * from notebook"
  46.         cursor = mSQLiteDatabase.rawQuery(sql, null); 
  47.     }catch(Exception ex){ 
  48.         ex.printStackTrace(); 
  49.         cursor = null
  50.     } 
  51.     return cursor; 
  52. public Cursor selectById(int id){ 
  53.      
  54.     //String result[] = {}; 
  55.     Cursor cursor = null
  56.     try
  57.         //sql語句操作 
  58.         String sql = "select * from notebook where _id='" + id +"'"
  59.         cursor = mSQLiteDatabase.rawQuery(sql, null); 
  60.     }catch(Exception ex){ 
  61.         ex.printStackTrace(); 
  62.         cursor = null
  63.     } 
  64.      
  65.     return cursor; 
  66. public long insert(String title, String content,String pic){ 
  67.      
  68.     long datetime = System.currentTimeMillis(); 
  69.     long l = -1
  70.     try
  71.         //結(jié)構(gòu)化方式操作 
  72.         ContentValues cv = new ContentValues(); 
  73.         cv.put("title", title); 
  74.         cv.put("content", content); 
  75.         cv.put("time", datetime); 
  76.         cv.put("pic", pic); 
  77.         l = mSQLiteDatabase.insert("notebook"null, cv); 
  78.     //    Log.v("datetime", datetime+""+l); 
  79.     }catch(Exception ex){ 
  80.         ex.printStackTrace(); 
  81.         l = -1
  82.     } 
  83.     return l; 
  84.      
  85. public int delete(int id){ 
  86.     int affect = 0
  87.     try
  88.         //結(jié)構(gòu)化方式操作 
  89.         affect = mSQLiteDatabase.delete("notebook""_id=?"new String[]{String.valueOf(id)}); 
  90.     }catch(Exception ex){ 
  91.         ex.printStackTrace(); 
  92.         affect = -1
  93.     } 
  94.      
  95.     return affect; 
  96. public int update(int id, String title, String content,String pic){ 
  97.     int affect = 0
  98.     try
  99.         //結(jié)構(gòu)化方式操作 
  100.         ContentValues cv = new ContentValues(); 
  101.         cv.put("title", title); 
  102.         cv.put("content", content); 
  103.         cv.put("pic", pic); 
  104.         String w[] = {String.valueOf(id)}; 
  105.         affect = mSQLiteDatabase.update("notebook", cv, "_id=?", w); 
  106.     }catch(Exception ex){ 
  107.         ex.printStackTrace(); 
  108.         affect = -1
  109.     } 
  110.     return affect; 
  111.  

獲取數(shù)據(jù)示例

  1. private DBManager dm = null;// 數(shù)據(jù)庫管理對象 
  2. rivate Cursor cursor = null
  3.            dm = new DBManager(this);//數(shù)據(jù)庫操作對象 
  4.            dm.open();//打開數(shù)據(jù)庫操作對象 
  5.            cursor = dm.selectAll();//獲取所有數(shù)據(jù) 
  6.            cursor.moveToFirst();//將游標(biāo)移動到***條數(shù)據(jù),使用前必須調(diào)用 
  7.             
  8.            int count = cursor.getCount();//個數(shù) 
  9.            ArrayList<String> contents = new ArrayList<String>();//圖片的所有集合 
  10.            ArrayList<String> imgs = new ArrayList<String>();//圖片的所有集合 
  11.            ArrayList<String> items = new ArrayList<String>();//標(biāo)題的所有集合 
  12.            ArrayList<String> times = new ArrayList<String>();//時間的所有集合 
  13.            for(int i= 0; i < count; i++){ 
  14.                contents.add(cursor.getString(cursor.getColumnIndex("content"))); 
  15.                imgs.add(cursor.getString(cursor.getColumnIndex("pic"))); 
  16.                items.add(cursor.getString(cursor.getColumnIndex("title"))); 
  17.                times.add(cursor.getString(cursor.getColumnIndex("time"))); 
  18.                //cursor.getInt(cursor.getColumnIndex("_id")) 
  19.                cursor.moveToNext();//將游標(biāo)指向下一個 
  20.            } 
  21.            dm.close();//關(guān)閉數(shù)據(jù)操作對象 

數(shù)據(jù)庫的并發(fā)問題
并發(fā)問題是使用數(shù)據(jù)庫過程中最容易碰到的問題,如果在開發(fā)中碰到了android.database.SQLException異常,并提示"database is locked",那很有可能是出現(xiàn)了數(shù)據(jù)庫的死鎖導(dǎo)致無法訪問。原因是Sqlite會對文件的讀寫進(jìn)行加鎖,防止數(shù)據(jù)被破壞。而在Android框架層SqliteDatabase會對所有數(shù)據(jù)庫對象進(jìn)行加鎖保護(hù),一旦出現(xiàn)了指向同一個數(shù)據(jù)庫的多個SqliteDatabase對象同時在多個線程中被使用,那就跳脫了SqliteDatabase鎖保護(hù),就會導(dǎo)致數(shù)據(jù)庫出現(xiàn)被鎖的異常。因此在實踐中,需要保證同時訪問數(shù)據(jù)庫的SqliteDatabase對象僅有一個。(可以使用全局變量來保存數(shù)據(jù)庫對象,在整個數(shù)據(jù)源對象中使用同一個連接)
課外小知識:在Android SDK中提供了工具Sqlite3,在shell模式下,可以對數(shù)據(jù)庫進(jìn)行增刪改查。
cmd->adb shell ->sqlite3 <路徑>/<數(shù)據(jù)庫名> ->sqlite > select * from sqmple;

二、Android數(shù)據(jù)的云端服務(wù)

本質(zhì)上而言,云端存儲就是通過網(wǎng)絡(luò)將移動設(shè)備上的數(shù)據(jù)存儲到遠(yuǎn)端服務(wù)器上。在Android中,增加了一些輔助功能,使得整個流程的實現(xiàn)變得更為簡單。首先是通過Google賬號來標(biāo)識用戶身份。在android中,默認(rèn)支持使用Google賬號作為用戶身份的標(biāo)識,系統(tǒng)上各個應(yīng)用都可以通過賬號系統(tǒng)獲得用戶的登錄信息。其次,有了Google賬號,使得開發(fā)者不需要自行構(gòu)建后臺服務(wù)系統(tǒng)。

Android的云端數(shù)據(jù)存取由系統(tǒng)服務(wù)BackupManagerService來統(tǒng)一管理。當(dāng)應(yīng)用提交備份數(shù)據(jù)請求時,BackupManagerService會將該請求放入備份隊列中,該隊列會按照一定的控制邏輯定時提交到云端。當(dāng)有新應(yīng)用安裝到系統(tǒng)時,會觸發(fā)數(shù)據(jù)恢復(fù)事件,BackupManagerService會憑借應(yīng)用包名和用戶賬號從云端取出相應(yīng)的備份數(shù)據(jù),嘗試恢復(fù)。

在實踐中,Android會構(gòu)造一個派生自BackupAgent類的子類android.app.backup.BackupAgentHelper的對象,來更方便地構(gòu)建云端存儲組件。

  1. import java.io.File; 
  2. import java.io.IOException; 
  3.  
  4. import android.app.backup.BackupAgentHelper; 
  5. import android.app.backup.BackupDataInput; 
  6. import android.app.backup.BackupDataOutput; 
  7. import android.app.backup.FileBackupHelper; 
  8. import android.os.ParcelFileDescriptor; 
  9.  
  10.  
  11.  
  12. public class MyBackupAgent extends BackupAgentHelper { 
  13.  
  14.     private static final String KEY = "my_backup"
  15.      
  16.     @Override 
  17.     public void onCreate() { 
  18.         //構(gòu)造文件讀寫對象,聲明需要備份的文件 
  19.         FileBackupHelper helper = new FileBackupHelper(this,"backup_file"); 
  20.         addHelper(KEY,helper); 
  21.         super.onCreate(); 
  22.     } 
  23.      
  24.     @Override 
  25.     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 
  26.             ParcelFileDescriptor newState) throws IOException { 
  27.         //調(diào)用父類方法,提交整個文件到云端 
  28.         super.onBackup(oldState, data, newState); 
  29.     } 
  30.  
  31.     @Override 
  32.     public void onRestore(BackupDataInput data, int appVersionCode, 
  33.             ParcelFileDescriptor newState) throws IOException { 
  34.         // 調(diào)用父類方法,將從云端獲取的文件覆蓋本地文件 
  35.         super.onRestore(data, appVersionCode, newState); 
  36.     } 
  37.  
  38.     @Override 
  39.     public void onRestoreFile(ParcelFileDescriptor data, long size, 
  40.             File destination, int type, long mode, long mtime) 
  41.             throws IOException { 
  42.         // TODO Auto-generated method stub 
  43.         super.onRestoreFile(data, size, destination, type, mode, mtime); 
  44.     } 
Android不會自行將數(shù)據(jù)提交到云端,開發(fā)者需要顯性調(diào)用android.app.backup.BackupManager的dataChanged函數(shù)來觸發(fā)。

和所有組件一樣,云端存儲組件是由系統(tǒng)進(jìn)行托管的。這就需要把組件的相關(guān)信息放入配置文件中。

 

<application android:backupAgent = "MyBackupAgent"  ...> 

 

責(zé)任編輯:chenqingxiang 來源: cnblogs
相關(guān)推薦

2014-08-26 10:04:51

數(shù)據(jù)存儲

2017-02-23 10:27:59

2017-11-29 09:48:19

存儲數(shù)據(jù)備份

2013-12-10 14:31:41

華為HPC大數(shù)據(jù)存儲

2012-08-14 10:21:29

2018-10-08 13:52:28

Android數(shù)據(jù)安全存儲安全

2010-01-26 14:43:53

Android數(shù)據(jù)存儲

2011-05-31 17:32:32

Android SharedPref

2013-06-14 15:43:46

Android開發(fā)移動開發(fā)數(shù)據(jù)存儲

2013-06-14 15:24:57

Android開發(fā)移動開發(fā)數(shù)據(jù)存儲方式

2024-06-21 13:47:17

2017-03-08 11:56:49

2012-06-08 09:46:26

大數(shù)據(jù)

2017-03-13 20:48:47

2017-02-15 14:47:34

冷存儲

2012-05-04 09:47:56

虛擬化存儲虛擬化思杰

2021-01-11 05:13:50

數(shù)據(jù)存儲字節(jié)

2023-11-10 11:02:28

Android10分區(qū)存儲

2009-05-27 11:01:29

UbuntuMySQL存儲
點贊
收藏

51CTO技術(shù)棧公眾號