SQLite数据库学习小结——Frameworks层实现
3. SQLite的Frameworks层实现
3.1 Frameworks层架构
Android系统方便应用使用,在Frameworks层中封装了一套Content框架,之所以叫Content框架而不叫数据库框架之类的,是因为这里Content不一定是来自数据库的内容,也可以是来自其他数据源的内容,开发人员只需要知道如何使用ContentResovler和ContentProvider就可以在应用进程之间共享数据了。
这里我们只讨论数据源是数据库的ContentProvider,开发人员需要实现一个SQLiteOpenHelper的派生类,它使用了一系列SQLite相关的类封装了native层的SQLite动态库的接口方法,那么SQLite在Frameworks层是如何封装的,我们在使用SQLite时又需要注意些什么呢?
我们先来看一看基于SQLite的Content框架的整体架构:
Android系统在Frameworks层
(1)不管是调用getWritableDatabase方法还是getReadableDatabase方法,SQLIteOpenHelper都会以可读写模式打开数据库。
(2)如果应用程序想以WAL模式打开数据库,可在自定义SQLiteOpenHelper类的构造方法中调用setWriteAheadLoggingEnabled(true)。
SQLiteOpenHelper.java
6、SQLiteConnectionPool:数据库连接池,管理所有打开的数据库连接(Connection)。所有数据库连接都是通过它来打开,打开后会加入连接池,在读写数据库时需要从连接池中获取一个数据库连接来使用。
7、SQLiteConnection:代表了数据库连接,每个Connection封装了一个native层的sqlite3实例,通过JNI调用SQLite动态库的接口方法操作数据库,Connection要么被Session持有,要么被连接池持有。
8、CursorFactory:可选的Cursor工厂,可以提供自定义工厂来创建Cursor。
9、DatabaseErrorHandler:可选的数据库异常处理器(目前仅处理数据库Corruption),如果不提供,将会使用默认的异常处理器。
10、SQLiteDatabaseConfiguration:数据库配置,应用程序可以创建多个到SQLite数据库的连接,这个类用来保证每个连接的配置都是相同的。
11、SQLiteQuery和SQLiteStatement:从抽象类SQLiteProgram派生,封装了SQL语句的执行过程,在执行时自动组装待执行的SQL语句,并调用SQLiteSession来执行数据库操作。这两个类的实现应用了设计模式中的命令模式。
3.2 关键模块实现
本节介绍几个关键模块的实现和使用时需要注意的事项。
3.2.1 SQLiteSession
Android系统Frameworks层的数据库读写操作都是通过SQLiteSession完成的,SQLiteSession负责管理数据库连接和事务的生命周期。
一个SQLiteDatabse实例可以同时持有多个活跃的Session(但是为防止死锁,每个线程只能持有一个DB的Session),每个Session在执行SQL语句时获取数据库连接,在SQL语句执行结束后释放数据库连接,Session只有在只执行SQL语句期间保持数据库连接,执行完后就释放了。这个特性也是连接池的实现基础。
SQLiteSession.java
如果连接池中所有连接都已分配出去了,那么获取连接的SQLiteSession会阻塞直到有可用连接为止。
所以,在使用SQLite时需要注意以下几点:
(2)执行的事务尽量短。
(3)如果读写事务很长,可以考虑使用yieldTransaction()方法先提交部分事务,给其他事务执行的机会。
3.2.2 SQLiteConnectionPool
数据库连接池保持所有打开的数据库连接,在任何时候,一个数据库连接要么被连接池持有,要么被一个SQLiteSession持有,如果SQLiteSession使用完数据库连接,必须把它还给连接池。如果连接池中所有的连接都已被占用,则待执行的事务要等待有空闲的连接才能执行。
目前Android系统的实现中,如果以非WAL模式打开数据库,连接池中只会保持一个数据库连接,如果以WAL模式打开数据库,连接池中的最大连接数量则根据系统配置决定,默认配置是两个。
SQLiteConnectionPool.java:
虽然名为连接池,但是从源码来看,目前实现的池中只有一个数据库连接(以后的Android版本可能会扩展),所以如果应用程序中有大量的并发数据库读和写操作的话,每个操作的时长都可能受到影响,所以数据库操作应放在工作线程中执行,以免影响UI响应。
3.2.4 Cursor
从ContentProvider查询的数据结果是放在Cursor中返回给客户端的,在客户端看来Cursor就是一个数据容器,但隐藏在Cursor后面的实现方式很灵活,它的数据既可以不是从数据库返回的,也可以是在使用时才真正加载的,很好的体现了面向对象编程的特性和优点。
在Frameworks中把Cursor定义为了一个接口,它的定位是可以随机访问的数据集,在接口中定义了访问数据集的通用方法。业务可以根据自己的需要实现一个Cursor,具体怎么实现接口的方法由具体实现决定,所以Cursor有很多子类来满足不同场景的需要。
通过SQLiteDatabase返回的就是其中的SQLiteCursor,如果数据不是从数据库返回的,开发人员也可以在ContentProvider中动态创建一个MatrixCursor,然后填充数据并返回给客户端。
从Cursor接口和其派生类的定义来看它们都没有实现Parcelable接口,那么它是怎么跨进程传递的呢?这需要Cursor首先要解决两个问题。
第一个问题:Cursor没有实现Parcelable接口,一个Cursor实例怎么跨进称传递呢?答案是传递的不是具体数据,而是Binder引用,即在ContentProvider端创建Cursor的Binder服务端实例,然后把Binder应用传递给客户端,在客户端通过这个Binder引用跨进程获取查询到的数据的。这里Frameworks定义了一个接口:IBulkCursor。
IBulkCursor定义了跨进程的Cursor需要实现的接口方法,其中getWindow()用来获得数据窗口,onMove()用来移动Cursor的位置。
那么第二个问来了:我们知道通过Binder传递的数据大小有限(1MB),而查询到的数据大小可能超出限制,那么怎么跨进程传递数据呢?既然数据大小不定,那么我们就不通过Binder传递数据了,而是通过共享内存传递数据,这块共享内存是封装在CursorWindow中的。
CursorWindow就是数据窗口,它在服务端分配(窗口大小有Android系统配置决定)并传递到客户端,客户端再映射到自己的进程空间中,这样,服务端填充的数据就可以被客户端读取到了。上面IBulkCursor接口中定义的getWindow()方法就是获取CursorWindow的。
CursorWindow在初始化时是空的,在调用Cursor的moveToXXX方法时会通过IBulkCursor的onMove()方法调用服务端的Cursor去填充数据窗口的内容。
CursorWindow.java
frameworks\base\libs\androidfw\CursorWindow.cpp
服务端创建共享内存。
CursorWindow.java
frameworks\base\libs\androidfw\CursorWindow.cpp
客户端映射共享内存到进程内存空间。
上面知道了Frameworks解决跨进程传递Cursor数据的思路,我们再来看下具体执行跨进程传递数据的类:CursorToBulkCursorAdapter(服务端)和BulkCursorToCursorAdapter(客户端)。
服务端:
客户端:
在ContentProviderNatvie类中可以看到Cursor的专递过程。
服务端:
ContentProviderNative.onTransact()
CursorToBulkCursorAdaptor.java
服务端在通过ContentProvider得到Cursor后,用它创建一个CursorToBulkCursorAdaptor实例,然后把adaptor封装在一个实现了Parcelable接口的BulkCursorDescriptor实例中返回给客户端。
虽说是在使用时才填充数据窗口,但是实际上传递Cursor的过程中,从上面代码可以看到服务端已经替应用程序填充过一次数据了:mCursor.getCount()。
SQLiteCursor.java
客户端:
ContentProviderProxy.query()
BulkCursorToCursorAdaptor.java
在得到服务端返回的数据后创建一个BulkCursorDescriptor实例,在用它初始化一个BulkCursorToCursorAdapter实例返回给应用程序使用。
转载于:https://www.cnblogs.com/supersand/p/5560091.html
SQLite数据库学习小结——Frameworks层实现相关推荐
- android mysql实现登录注册_android简单登陆和注册功能实现+SQLite数据库学习
android简单登陆和注册功能实现+SQLite数据库学习 发布时间:2018-07-04 17:23, 浏览次数:1027 , 标签: android SQLite 这里我只是建立了一个用简单的存 ...
- SQLite数据库学习笔记1:报错:The database disk image is malformed
目录 问题现象: 问题分析: 解决方法: 问题现象: 今天在项目中用到了SQLite数据库,此前并未学习过,因此就简单的了解了一下,很快就遇到了第一个小问题,报错如下: The database di ...
- Android之SQLite数据库学习
(一)使用Android原生API 1. 介绍 SQLite是D.Richard Hipp用C语言编写的开源嵌入式数据库引擎,它是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它的设计目标是 ...
- 【SQLite数据库学习】 初步了解Sqlite3数据库
目录 一:什么是数据库 二:为什么使用数据库 三:数据库的特点 四:如何使用数据库[关于数据库的常见术语] 五:常见的SQL语句的使用 一:什么是数据库 结构化查询语句 是一种对关系型数据库中的数据进 ...
- 【SQLite数据库学习】 连表查询
目录 一:数据分析 二:数据设计 三:数据库可视化操作 四:数据库命令行操作 一:数据分析 如下图,以视频播放器的ER图来进行数据分析 二:数据设计 新建表 表中添加数据 命令操作 如下 CREATE ...
- 从C#到Objective-C,循序渐进学习苹果开发(7)--使用FMDB对Sqlite数据库进行操作
本随笔系列主要介绍从一个Windows平台从事C#开发到Mac平台苹果开发的一系列感想和体验历程,本系列文章是在起步阶段逐步积累的,希望带给大家更好,更真实的转换历程体验.本篇主要开始介绍基于XCod ...
- 安卓学习笔记29:使用SQLite数据库
文章目录 零.学习目标 一.SQLite数据库概述 1.SQLite构成 2.SQLite数据类型 3.SQLite数据库特点 二.SQLite数据库管理工具 (一)数据库控制台管理工具 - sqli ...
- 【数据库学习笔记】——操作sqlite(增删改查)以及cursor的方法介绍
目录 1.sqlite数据库介绍 1)常见的数据库操作 2)数据操作常见步骤 2.向数据表中增加数据(insert into) 1)向数据表中添加一条记录 2)向数据表中一次性添加多条记录 3.修 ...
- android sqlite 打包 xe,C++ Builder XE10快速开发关于sqlite数据库APP应用发布小结
因为C++ Builder XE10资料一直较少,所以作为C++ Builder业余fans,有必要为这冷门提供一些技术支持,与小伙伴们一起成长! 本视频系列,主要是讲解C++ Builder XE1 ...
- 一个小时内学习SQLite数据库
FROM: http://database.51cto.com/art/201205/335411.htm SQLite 是一个开源的嵌入式关系数据库,实现自包容.零配置.支持事务的SQL数据库引擎. ...
最新文章
- Marty Cagan:怎样寻找出色的产品经理
- 基于Android SQLite的升级详解
- 【数学和算法】SVD奇异值分解原理、以及在PCA中的运用
- Linux Shell实例精讲学习笔记
- DrawerLayout
- bat代码小游戏_程序员入职被27岁领导告诫:我被BAT录用过,是算法方面泰斗大哥...
- PL/SQL控制结构
- 知乎热榜:如何获得高并发的经验?
- frame或者iframe的contentwindow属性
- 江湖不再平静---51CTO学院停服公告
- java poi 自动行高,20191012——POI设置单元格自动行高(思路)
- 批处理文件——BAT学习
- matlab距离变换,图像处理之距离变换
- Ubuntu如何把主文件夹的中文设置成英文
- ubuntu 命令行批量重命名文件夹
- TPS和QPS 并发量区别;日活 访问量 活跃度
- Python入门: 贪吃蛇详解
- (转)Python--matplotlib绘图可视化知识点整理
- 抖音企业号建议做吗?有什么好处?
- 查询oracle表空间是否满了,oracle表空间满了,导致数据不能写入数据库
热门文章
- ecshop数据库操作类
- 在 MAC下安装 Exuberant ctags
- 如何在DNN4下使用VS2005进行单元测试???
- asp.net服务器控件开发-学习之路(一)
- node.js如何制作命令行工具(一)
- 20175208 《Java程序设计》第七周学习总结
- android socket_Android 10.0系统启动之Zygote进程(四)-「Android取经之路」
- Java之美[从菜鸟到高手演变]之设计模式四
- 5G商业化进程提速 运营商推进网络智能化转型
- box-shadow(text-shadow)参数详解