日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
SQLite做為本地緩存應(yīng)注意的幾大方面

今天看到了園友陸敏計的一篇文章<>, 寫到了SQLite的諸多優(yōu)點,尤其適應(yīng)于本地數(shù)據(jù)緩存和應(yīng)用程序。

依蘭網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián)公司,依蘭網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為依蘭近1000家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的依蘭做網(wǎng)站的公司定做!

轉(zhuǎn)自陸兄的內(nèi)容,來夸夸Sqlite:

SQLite官方網(wǎng)站: http://www.sqlite. org/ 時第一眼看到關(guān)于SQLite的特性。

1. ACID事務(wù)

2. 零配置 – 無需安裝和管理配置

3. 儲存在單一磁盤文件中的一個完整的數(shù)據(jù)庫

4. 數(shù)據(jù)庫文件可以在不同字節(jié)順序的機器間自由的共享

5. 支持?jǐn)?shù)據(jù)庫大小至2TB

6. 足夠小, 大致3萬行C代碼, 250K

7. 比一些流行的數(shù)據(jù)庫在大部分普通數(shù)據(jù)庫操作要快

8. 簡單, 輕松的API

9. 包含TCL綁定, 同時通過Wrapper支持其他語言的綁定

10. 良好注釋的源代碼, 并且有著90%以上的測試覆蓋率

11. 獨立: 沒有額外依賴

12. Source完全的Open, 你可以用于任何用途, 包括出售它

13. 支持多種開發(fā)語言,C, PHP, Perl, Java, ASP .NET,Python

正好前一段時間我做了這方面的應(yīng)用,我就結(jié)合陸兄的這篇文章,談?wù)勎以赟qlite本地緩存業(yè)務(wù)數(shù)據(jù)時的經(jīng)驗,給大家借鑒一下。我開發(fā)時比較倉促,很多地方請大家多提意見。

解決的問題

首先介紹我用Sqlite解決的實際問題是什么?

問題1:某個功能的數(shù)據(jù)需要連接一個遠程數(shù)據(jù)庫查詢速度很慢,查一次數(shù)據(jù)不容易,希望能夠重復(fù)利用之前查過的數(shù)據(jù)集。

問題2:非常大的數(shù)據(jù)量比如幾千萬甚至幾億條數(shù)據(jù),一次性讀取到DataTable中,會內(nèi)存溢出的,所以在第一次分析時就是通過Reader的方式,分析完一條后并不在內(nèi)存中保存,但是緊接著用戶的第二次分析、第三次分析還是要用到的第一次分析的數(shù)據(jù),如果我們重新查詢一次遠程服務(wù)器,效率可想而知啊。

結(jié)合上面的2個問題,為了解決效率問題和數(shù)據(jù)重復(fù)利用度,減少數(shù)據(jù)庫服務(wù)器的壓力,我才用Sqlite緩存數(shù)據(jù)(當(dāng)然這不是唯一也不是最好的解決方案) 。

優(yōu)化SQLiteHelper

陸兄的SQLiteHelper類我增加了幾個有用的方法:

第一個方法是GetSchema,得到某個表的表結(jié)構(gòu)。

  
 
 
  1. ///      
  2. /// 查詢數(shù)據(jù)庫中的所有數(shù)據(jù)類型信息     
  3. ///      
  4. ///      
  5. public DataTable GetSchema()  
  6. {  
  7.     using (SQLiteConnection connection = new SQLiteConnection(connectionString))  
  8.     {  
  9.         connection.Open();  
  10.         DataTable data = connection.GetSchema("TABLES");  
  11.         connection.Close();  
  12.         //foreach (DataColumn column in data.Columns)     
  13.         //{     
  14.         //    Console.WriteLine(column.ColumnName);     
  15.         //}     
  16.         return data;  
  17.     }  

第二個方法是IsTableExist,判斷SQLite數(shù)據(jù)庫重某個表是否存在 。

  
 
 
  1. ///      
  2. /// 判斷SQLite數(shù)據(jù)庫表是否存在    
  3. ///      
  4. /// 要創(chuàng)建的SQLite數(shù)據(jù)庫文件路徑     
  5. public bool IsTableExist(string tableName)  
  6. {  
  7.     using (SQLiteConnection connection = new SQLiteConnection(connectionString))  
  8.     {  
  9.         connection.Open();  
  10.         using (SQLiteCommand command = new SQLiteCommand(connection))  
  11.         {  
  12. command.CommandText = "SELECT COUNT(*) FROM sqlite_master where type='table' and name='" + tableName + "'";  
  13.             int iaaa = Convert.ToInt32(command.ExecuteScalar());  
  14.             if (Convert.ToInt32(command.ExecuteScalar()) == 0)  
  15.             {  
  16.                 return false;  
  17.             }  
  18.             else  
  19.             {  
  20.                 return true;  
  21.             }  
  22.         }  
  23.     }  

第三個方法是Query,執(zhí)行查詢語句,返回DataSet

  
 
 
  1. ///  
  2. /// 執(zhí)行查詢語句,返回DataSet  
  3. ///  
  4. /// 查詢語句 
  5. /// DataSet 
  6. public DataSet Query(string SQLString)  
  7. {  
  8.     using (SQLiteConnection connection = new SQLiteConnection(connectionString))  
  9.     {  
  10.         DataSet ds = new DataSet();  
  11.         try  
  12.         {  
  13.             connection.Open();  
  14.             SQLiteDataAdapter command = new SQLiteDataAdapter(SQLString, connection);  
  15.             command.Fill(ds, "ds");  
  16.         }  
  17.         catch (System.Data.SQLite.SQLiteException ex)  
  18.         {  
  19.             throw new Exception(ex.Message);  
  20.         }  
  21.         return ds;  
  22.     }  

構(gòu)建緩存對象模型和緩存控制器

每一塊緩存對象,在數(shù)據(jù)庫中會產(chǎn)生一個表,而表名稱是有緩存控制器自動生成的,訪問緩存的工作全部交由緩存控制器完成,通過緩存項的ID和ModuleKey來訪問。

在Sqlite中還需要一個系統(tǒng)表來維護每個緩存項和實際緩存存儲表之間的對應(yīng)關(guān)系,我們稱之為配置表,它將在緩存控制器創(chuàng)建Sqlite緩存數(shù)據(jù)庫文件時創(chuàng)建。

配置表共有以下幾個字段,分別和緩存對象模型CdlCacheItem類映射:

列名稱說明
Id緩存的唯一數(shù)字編號
ModuleKey緩存模塊名稱,一個模塊可以有多個緩存數(shù)據(jù),ID可以區(qū)分。實際應(yīng)用時,某個功能時會經(jīng)常緩存數(shù)據(jù)的,所以通過ModuleKey就可以得到這個功能所有的緩存列表,然后選定其中的部分緩存來進行使用。
Comments緩存說明
TableName緩存數(shù)據(jù)存儲的數(shù)據(jù)表名稱
AddDate緩存時間戳

創(chuàng)建數(shù)據(jù)庫的方法如下

  
 
 
  1. static void CreateDB()  
  2. {  
  3.     //總共有ID、ModuleKey、Comments、AddDate這幾列  
  4.     string sql = "CREATE TABLE SYSCDLTABLES(ID 
  5. INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,MODULEKEY VARCHAR(200),
  6. COMMENTS VARCHAR(500),TABLENAME VARCHAR(100),ADDDATE DATETIME)";  
  7.     SQLiteDBHelper.CreateDB(CACHEFILEPATH, sql);  

每個緩存項(緩存對象模型)定義如下,和配置表對應(yīng):

  
 
 
  1. ///  
  2. /// 緩存項對象  
  3. ///  
  4. /// Tecky Lee 
  5. /// 2011-1-11 15:11 
  6. public class CdlCacheItem  
  7. {  
  8.     int m_id;  
  9.  
  10.     public int Id  
  11.     {  
  12.         get { return m_id; }  
  13.         set { m_id = value; }  
  14.     }  
  15.     string m_moduleKey;  
  16.  
  17.     public string ModuleKey  
  18.     {  
  19.         get { return m_moduleKey; }  
  20.         set { m_moduleKey = value; }  
  21.     }  
  22.     string m_comments;  
  23.  
  24.     public string Comments  
  25.     {  
  26.         get { return m_comments; }  
  27.         set { m_comments = value; }  
  28.     }  
  29.     string m_tableName;  
  30.  
  31.     public string TableName  
  32.     {  
  33.         get { return m_tableName; }  
  34.         set { m_tableName = value; }  
  35.     }  
  36.     DateTime m_timestamp;  
  37.  
  38.     public DateTime Timestamp  
  39.     {  
  40.         get { return m_timestamp; }  
  41.         set { m_timestamp = value; }  
  42.     }  

下面是控制器的接口定義:

  
 
 
  1. public interface ICdlCacheController  
  2.     {  
  3.         void BeginLoadRow();  
  4.         void EndLoadRow();  
  5.         System.Collections.Generic.IList GetCdlCacheItems(string moduleKey);  
  6.         CdlCacheItem GetCdlCacheItems(int id);  
  7.         void LoadRow(System.Data.DataRow row, string tableName);  
  8.         void LoadRow(IEnumerable row, string tableName);  
  9.         string LoadTable(System.Data.DataTable dt, string moduleKey, string comments);  
  10.         System.Data.Common.DbDataReader QueryCdlTableReader(CdlCacheItem item);  
  11.         System.Data.DataTable QueryCdlTables(CdlCacheItem item);  
  12.         System.Data.DataTable QueryCdlTables(string sql);  
  13.         void RemoveAllTables();  
  14.         void RemoveCdlTables(string moduleKey);  
  15.         void RemoveCdlTables(System.Collections.Generic.IList items);  
  16.         void RemoveCdlTables(CdlCacheItem item);  
  17.         void RemoveCdlTables(int id);  
  18.     } 
  19. 上面的函數(shù)下面來做個說明:

    1、BeginLoadRow、LoadRow和EndLoadRow,三個函數(shù)組為了在我們查詢主數(shù)據(jù)庫時使用Reader方式讀取數(shù)據(jù)時,可以一條條將數(shù)據(jù)同時存放在緩存中。

    2、RemoveAllTables和RemoveCdlTables是用來刪除緩存項的。

    3、GetCdlCacheItems,通過moduleKey得到多個緩存項。比如用戶想基于這幾天內(nèi)保存的某個功能的數(shù)據(jù)做一次快速分析,那么我們就可以通過這個函數(shù)得到緩存列表,由用戶選擇列表中的一個來繼續(xù)。

    4、QueryCdlTableReader,得到某個緩存數(shù)據(jù)的Reader對象,這樣可以一行行的分析,一次讀出大數(shù)據(jù)量的數(shù)據(jù)到DataTable中,內(nèi)存可能會溢出的。

    5、QueryCdlTables,將某個緩存項查詢并裝載到DataTable中。

    提高緩存數(shù)據(jù)寫入效率

    Sqlite在保存數(shù)據(jù)的時候,比如一次保存一個億條的數(shù)據(jù),一條條插入效率非常低下,網(wǎng)上也有人對其進行討論。

    效率低下的主要原因在于IO操作次數(shù)過于頻繁,所以在LoadTable或者是使用BeginLoadRow·EndLoadRow的時候,使用了事務(wù)來減少數(shù)據(jù)提交的次數(shù),結(jié)果保存的效率非常的高,我測試的結(jié)果是400萬條數(shù)據(jù)查詢,只需要幾十秒鐘,這點時間相對于重新查一次遠程服務(wù)器那是可以忽略了。

    下面給出BeginLoadRow和EndLoadRow的具體代碼(只有在EndRow的時候才會提交一次數(shù)據(jù)):

      
     
     
    1. SQLiteConnection m_connection;  
    2. SQLiteCommand m_command;  
    3. DbTransaction m_transaction;  
    4. public void BeginLoadRow()  
    5. {  
    6.     m_connection = new SQLiteConnection("Data Source=" + CACHEFILEPATH);  
    7.  
    8.     m_connection.Open();  
    9.     m_transaction = m_connection.BeginTransaction();  
    10.     m_command = new SQLiteCommand(m_connection);  
    11. }  
    12. public void EndLoadRow()  
    13. {  
    14.     try  
    15.     {  
    16.         if (m_command != null)  
    17.             m_command.Dispose();  
    18.  
    19.         if (m_transaction != null)  
    20.         {  
    21.             m_transaction.Commit();  
    22.         }  
    23.  
    24.         if (m_connection != null)  
    25.         {  
    26.             m_connection.Close();  
    27.             m_connection.Dispose();  
    28.         }  
    29.     }  
    30.     catch (System.Exception ex)  
    31.     {  
    32.         LogHandle.Error(ex);  
    33.     }  

    LoadTable函數(shù)內(nèi)部也是調(diào)用BeginLoadRow·EndLoadRow模式來完成的。

    數(shù)據(jù)庫文件如何創(chuàng)建:

    Sqlite數(shù)據(jù)庫文件如果不存在,在執(zhí)行sql語句的時候,會自動根據(jù)ConnetionString中指定的位置創(chuàng)建數(shù)據(jù)庫文件,默認(rèn)創(chuàng)建的空數(shù)據(jù)庫只有4K。

    其他有待討論的問題:

    1、我是將所有的緩存做到一個數(shù)據(jù)庫文件中了,實際應(yīng)用根據(jù)業(yè)務(wù)的不同,可以一份緩存數(shù)據(jù)一個文件也是很好管理的,維護也方便,資源管理器中就可以拷貝刪除等。

    2、當(dāng)我們存儲一億條數(shù)據(jù)到Sqlite的時候,因為Sqlite沒有壓縮數(shù)據(jù),結(jié)果數(shù)據(jù)庫文件就可以會有好幾個G(這也不一定,適合數(shù)據(jù)庫字段的多少,字段類型有關(guān)的)。

    文件太大就消耗了磁盤空間,而且用戶或者程序如果不及時清理的,可能會耗盡磁盤空間。

    這里就必須建立一個機制,檢查sqlite的緩存并及時清理,或者設(shè)置緩存應(yīng)用的上限,當(dāng)達到上限后自動根據(jù)時間戳清理歷史緩存。


    文章標(biāo)題:SQLite做為本地緩存應(yīng)注意的幾大方面
    分享地址:http://m.5511xx.com/article/codeehg.html