1. 程式人生 > >greendao是如何實現查詢操作的,多執行緒是否安全?

greendao是如何實現查詢操作的,多執行緒是否安全?

想要了解GreenDao如何進行資料庫CRUD操作,那麼可以看原始碼。

查詢:

先看最簡單最容記得查詢方法queryBuilder().list()。

/** Executes the query and returns the result as a list containing all entities loaded into memory. */
    public List<T> list() {
        checkThread();
        Cursor cursor = dao.getDatabase().rawQuery(sql, parameters);
        return daoAccess.loadAllAndCloseCursor(cursor);
    }

通過sql語句進行查詢,然後返回一個遊標。根據這個遊標進行處理。檢視下方法實現

/** Reads all available rows from the given cursor and returns a list of entities. */
    protected List<T> loadAllFromCursor(Cursor cursor) {
        int count = cursor.getCount();
        if (count == 0) {
            return new ArrayList<T>();
        }
        List<T> list = new ArrayList<T>(count);
        CursorWindow window = null;
        boolean useFastCursor = false;
        if (cursor instanceof CrossProcessCursor) {
            window = ((CrossProcessCursor) cursor).getWindow();
            if (window != null) { // E.g. Robolectric has no Window at this point
                if (window.getNumRows() == count) {
                    cursor = new FastCursor(window);
                    useFastCursor = true;
                } else {
                    DaoLog.d("Window vs. result size: " + window.getNumRows() + "/" + count);
                }
            }
        }

        if (cursor.moveToFirst()) {
            if (identityScope != null) {
                identityScope.lock();
                identityScope.reserveRoom(count);
            }

            try {
                if (!useFastCursor && window != null && identityScope != null) {
                    loadAllUnlockOnWindowBounds(cursor, window, list);
                } else {
                    do {
                        list.add(loadCurrent(cursor, 0, false));
                    } while (cursor.moveToNext());
                }
            } finally {
                if (identityScope != null) {
                    identityScope.unlock();
                }
            }
        }
        return list;
    }

看到這裡,發現和我們自己寫SQLite原生查詢的時候處理遊標差不多。

它首先判斷cursor是否為空,接著新建List,再從遊標中讀取資料存進list中然後返回,整體理解起來不難。那麼它轉化成我們需要的物件是在loadCurrent()這個方法中。

final protected T loadCurrent(Cursor cursor, int offset, boolean lock)

所以總體思路是這樣:

我們呼叫實體類Dao的queryBuilder().list()方法,接著它使用SQL語句進行資料庫查詢,返回一個cursor,再對cursor進行解析,解析cursor的方法是

final protected T loadCurrent(Cursor cursor, int offset, boolean lock)

,存進List中返回給我們。

再看看queryBuilder().listLazy()

該方法返回一個LazyList<T>,這個LazyList是實現了List介面的,我們得到這個LazyList時,操作相關的資料是的方法有構造方法和get方法。

看下他實現的的方法。構造方法

 LazyList(InternalQueryDaoAccess<E> daoAccess, Cursor cursor, boolean cacheEntities) {
        this.cursor = cursor;
        this.daoAccess = daoAccess;
        size = cursor.getCount();
        if (cacheEntities) {
            entities = new ArrayList<E>(size);
            for (int i = 0; i < size; i++) {
                entities.add(null);
            }
        } else {
            entities = null;
        }
        if (size == 0) {
            cursor.close();
        }

        lock = new ReentrantLock();
    }
@Override
    public E get(int location) {
        if (entities != null) {
            E entity = entities.get(location);
            if (entity == null) {
                lock.lock();
                try {
                    entity = entities.get(location);
                    if (entity == null) {
                        entity = loadEntity(location);
                        entities.set(location, entity);
                        // Ignore FindBugs: increment of volatile is fine here because we use a lock
                        loadedCount++;
                        if (loadedCount == size) {
                            cursor.close();
                        }
                    }
                } finally {
                    lock.unlock();
                }
            }
            return entity;
        } else {
            lock.lock();
            try {
                return loadEntity(location);
            } finally {
                lock.unlock();
            }
        }
    }

可以看到LazyList中的get方法是執行緒安全的,裡面使用了雙重檢驗。提高了多執行緒的安全性和效率。裡面使用了loadEntity()方法來解析遊標資料,檢視原始碼

可以發現最終也呼叫了loadCurrent()方法來解析cursor並封裝成一個實體類返回給get方法。最後封裝成一個LazyList返回給使用者。

總體思路是這樣:

使用者呼叫queryBuilder().LazyList()方法,該方法使用SQL語句進行資料庫查詢並返回一個遊標,接著遊標層層傳遞,在LazyList的get方法中進行資料解析,解析cursor的方法是loadEntity(location),但是該方法呼叫了loadCurrent方法,所以最終解析cursor資料的方法是loadCurrent,然後封裝成實體類返回,裝載進LazyList返回給使用者,完成查詢。

再看看迭代查詢,queryBuilder().listIterator()

該方法返回一個迭代器,在迭代器中獲取資料使用到next()方法,判斷是否還有資料則使用hasNext()方法,接下來看看原始碼

層層進入原始碼,最終 發現進入的是LazyList

看看next()方法,非常容易理解,裡面通過一個get()方法來進行資料的獲取

@Override
        public E next() {
            if (index >= size) {
                throw new NoSuchElementException();
            }
            E entity = get(index);
            index++;
            if (index == size && closeWhenDone) {
                close();
            }
            return entity;
        }

點進去發現和我們的Lislazy方法一毛一樣!!  也是最終通過loadCurrent()方法解析遊標資料進行實體類封裝返回給使用者。

其實除了list方法,其餘的三個查詢方法都用到了LazyList類,最終呼叫的步驟也是一致。不過和list的區別就是惰性載入(按需載入),而且需要開發者手動關閉連線。

總體思路:

使用者呼叫該方法,然後它new 一個迭代器,通過LazyList類的get方法載入資料封裝實體存進迭代器返回給使用者。

總結:

list方法和listLazy(),listLazyUncached(),listIterator()區別就是:後者需要關閉連線(因為有遊標的引用),後者是惰性載入,即使用到該資料才會載入進記憶體,而前者則是全部載入進快取,開銷比後者大。

後者多執行緒安全。

相關推薦

greendao是如何實現查詢操作執行是否安全

想要了解GreenDao如何進行資料庫CRUD操作,那麼可以看原始碼。 查詢: 先看最簡單最容記得查詢方法queryBuilder().list()。 /** Executes the query and returns the result as a list c

python3實現tkinter視窗懸浮右鍵選單操作執行控制

專案需要,做了一個demo直接上程式碼供大家參考,並且留為記錄 需要更深入瞭解,可以加微信qypangu相信交流,請注時"csdn  python" #!/usr/bin/python3 # -*- coding: utf-8 -*- import tkinter im

【Django】Uwsgi+Nginx+Django2.0+Python3.7實現高併發執行高效能

一、系統以及環境 伺服器系統:Ubuntu 16.04 專案環境:python 3.7 框架:Django2.0 伺服器環境:Uwsgi、Nginx 效能監測工具:Uwsgitop 使用背景:因為Dj

socket伺服器程式設計的程序執行實現

socket伺服器程式設計: 顧名思義就是使用socket套接字來編寫伺服器程式的過程。不熟悉socket程式設計的小夥伴可以看我之前的文章,但是當時所實現的功能伺服器同時只能和一個客戶端進行互動,效率太低,利用多程序或者多執行緒方式來實現伺服器可以做到同時和多個客戶端進行互動。提高伺服器的效能

一行 Python 實現並行化 -- 日常執行操作的新思路

春節坐在回家的火車上百無聊賴,偶然看到 Parallelism in one line 這篇在 Hacker News 和 reddit 上都評論過百的文章,順手譯出,enjoy:-) http://www.zhangzhibo.net/2014/02/01/

spring+ActiveMQ+JMS+執行實現簡單的分散式執行工的非同步任務處理系統

前言:隨著系統的業務功能不斷增強,傳統的單機、單任務,單執行緒的執行模式已經逐漸的被淘汰,取而代之的是分散式,多工,多執行緒,當然,現在開源的這方面的框架也非常的多,大概的思想也都類似,下面就結合我這一年多的工作心得,分享一個簡單易實現的分散式,多工,多執行緒的非同步任務處理系統的基本實現。 1.系統部署圖

Linux程式設計 程序執行求解PI(圓周率)

題目: 連結 多程序: #include <unistd.h> #include <stdio.h> #include <stdlib.h> #define n 100000000.0 int main() { i

執行的弊端執行基礎學習

using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using

libcurl執行gzip共享DNS

http://hi.baidu.com/jjxiaoyan/item/e17b9ec3e31b93d4964452d8   libcurl是一個不錯的socket庫,而且又是開源的。如果僅僅是簡單的HTTP請求,那麼只需要幾行程式碼就能輕鬆實現。不過要用libcurl實現高效、高頻率的HTTP請

學習彙集地如果你擅長計算機組成原理執行設計模式jvm前端或者其他都可以

擅長jvm 多執行緒 設計模式 資料庫 前端 分散式什麼的一起學習共同進步。   目的是大家在自學新的領域的時候有地方可以探討求疑 比如在看到垃圾回收各種收集器中遇到執行緒方面知識的時候 學習設計模式分不清單例和享元的區別,只有書本經驗不知道如何應用到實際開發的時候 學習資料庫系統

實現Runnable解決執行資料安全問題

xl_echo編輯整理,歡迎轉載,轉載請宣告文章來源。更多IT、程式設計案例、資料請聯絡QQ:1280023003,加群298140694。百戰不敗,依不自稱常勝,百敗不頹,依能奮力前行。——這才是真正的堪稱強大!! 之前的文章我們講到了,四個電影院視窗同時出售50張彩票的

Qt TCP通訊執行伺服器端

相信許多初學Qt的同學都會和我一樣遇到這樣的問題: 一、Qt TCP通訊在使用nextPendingConnect後,伺服器端就只會與最後接入的客戶端通訊,這個時候就會考慮繼承QThread實現多執行緒,從而實現多個客戶端與伺服器端通訊,每當一個新的客戶端連線時,通過標識碼socke

利用itertools生成密碼字典執行撞庫破解rar壓縮檔案密碼

指令碼功能:  利用itertools生成密碼字典(迭代器形式)  多執行緒併發從密碼字典中取出密碼進行驗證  驗證成功後把密碼寫入檔案中儲存 #!/usr/bin/env python # -*- coding: UTF-8 -*- # Author:Leslie-x import itert

FMDB使用事務執行加密等比較全面的用法。

一:簡單使用 既然FMBD是對資料庫的封裝,那基本功能應該包括 增、刪、改、查。 主要使用到的類為FMDatabase(資料庫)FMResultSet(查詢的結果)。 其中增、刪、改,三個方法都是使用FMDatabase類的executeUpdate方法也就是都算作資料的更新, 而查

c++單例模式執行使用

c++ 11保證了這樣做是執行緒安全的。 一:class Singleton{ static Singleton* GetInstance(){         static Singleton s;     

程序執行

一個程序可以多執行緒,但是多執行緒就像是十字路,一個執行緒掛了,如果對多執行緒的共享堆、全域性變數等非棧記憶體造成了影響,那麼它所屬的程序就掛了。 而多程序則像是立交橋,互不想幹。一個程序掛了不會導致整個程式崩潰。所以在想要保證 程式的可用性(不會動不動就堵塞)是可以使用多程序,也可以保證主程序的穩定,比

Java——執行基本使用(三) 餓漢式和懶漢式的單例設計模式執行之間的通訊

這一則部落格主要寫的是單例設計模式,與實現多執行緒之間的通訊等等~ 1.單例設計模式:保證類在記憶體中只有一個物件 2.保證類在記憶體中只有一個物件            &

MFCSTL執行網路通訊linux泛型IO

1 C++介面庫 2 MFC入門教程 3    C++筆記——第一個MFC程式 4 STL運用的C++技術——後記 5 C++ STL庫使用注意點 6 C++ STL 一般總結 7 C++中STL用法總結 8 c++ STL 9

java第16天----TreeMap的注意點增強for迴圈Arrays和Collecttions工具類執行簡介

昨天知識總結 1.泛型 泛型的定義 泛型的基礎 泛型在類上,介面上,方法上的使用 泛型–限制上限,限制下線 2.Map Map與Collection的比較 Map介面常用方法 Map的遍歷----會—重點 HashMap的去重和TreeMap的排序 Tre

安卓開發筆記(九)—— HttpURLConnection請求訪問Web服務解析JSON資料執行CardView佈局技術(bilibili的使用者視訊資訊獲取軟體)

中山大學資料科學與計算機學院本科生實驗報告 (2018年秋季學期) 一、實驗題目 WEB API 第十四周實驗目的 學會使用HttpURLConnection請求訪問Web服務 學習Android執行緒機制,學會執行緒更新UI 學會解析JSO