联系人数据库设计之AbstractContactsProvider
个人见解,欢迎交流。
联系人数据库设计,源代码下载请自行去android官网下载。
package com.android.providers.contacts; import android.content.ContentProvider;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteTransactionListener;
import android.net.Uri; import java.util.ArrayList; /**
* A common base class for the contacts and profile providers. This handles much of the same
* logic that SQLiteContentProvider does (i.e. starting transactions on the appropriate database),
* but exposes awareness of batch operations to the subclass so that cross-database operations
* can be supported.
* 用于联系人和配置信息的ContentProvider的公共基类。处理相同的数据库逻辑,同时暴露批处理处理的操作到子类中,从而实现
* 跨数据库操作支持
*
* 事务 详细请@百度百科
* 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作。
* 事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。
* 通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。
* 一个逻辑工作单元要成为事务,必须满足所谓的ACID(原子性、一致性、隔离性和持久性)属性。
*/
public abstract class AbstractContactsProvider extends ContentProvider
implements SQLiteTransactionListener {//接口,用于transactionEvent。在ContactsTransaction中的监听 /**
* Duration in ms to sleep after successfully yielding the lock during a batch operation.
* 间隙。批处理操作成功释放lock锁,休眠时间
*/
protected static final int SLEEP_AFTER_YIELD_DELAY = 4000; /**
* Maximum number of operations allowed in a batch between yield points.
* 批处理中允许的最大操作数。在一个yield points到另一个yield point之间
*/
private static final int MAX_OPERATIONS_PER_YIELD_POINT = 500; /**
* Number of inserts performed in bulk to allow before yielding the transaction.
*/
private static final int BULK_INSERTS_PER_YIELD_POINT = 50; /**
* The contacts transaction that is active in this thread.
* 关于ThreadLocal请查阅java编程思想 ThreadLocal=线程本地存储
*/
private ThreadLocal<ContactsTransaction> mTransactionHolder; /**
* The DB helper to use for this content provider.
* 为此ContentProvider设计的SQLiteOpenHelper。
*/
private SQLiteOpenHelper mDbHelper; /**
* The database helper to serialize all transactions on. If non-null, any new transaction
* created by this provider will automatically retrieve a writable database from this helper
* and initiate a transaction on that database. This should be used to ensure that operations
* across multiple databases are all blocked on a single DB lock (to prevent deadlock cases).
* 数据库助手用于序列话所有的事务(transaction)。如果不为null,所有由此ContentProvider创建的事务都会自动收到
* 一个可写的数据库,并且数据库上存在一个事务。
* 这主要用来保证所有的跨数据库操作都阻塞在一个单独的数据库锁上。从而杜绝死锁。
* 不错的设计,看看下面如何实现的。
*
* ---------------------附设计思想(个人见解)
* 正常情况下我们使用事务,首先得到一个db(database),开始事务调用db.beginTransaction。事务结束调用db.endTransaction。
* 但我们有时候要操作的数据库是对个数据表进行操作为了便于管理,所有的事务对象的db,由mSerializeOnDbHelper产生。
* -----------------------------
*/
private SQLiteOpenHelper mSerializeOnDbHelper; /**
* The tag corresponding to the database used for serializing transactions.
* 序列话事务的tag,这个tag和数据库database相映射
*/
private String mSerializeDbTag; @Override
public boolean onCreate() {
Context context = getContext();
mDbHelper = getDatabaseHelper(context);
mTransactionHolder = getTransactionHolder();
return true;
} public SQLiteOpenHelper getDatabaseHelper() {
return mDbHelper;
} /**
* Specifies a database helper (and corresponding tag) to serialize all transactions on.
* @param serializeOnDbHelper The database helper to use for serializing transactions.
* @param tag The tag for this database.
* 序列化事务的SQLiteOpenHelper以及tag
*/
public void setDbHelperToSerializeOn(SQLiteOpenHelper serializeOnDbHelper, String tag) {
mSerializeOnDbHelper = serializeOnDbHelper;
mSerializeDbTag = tag;
} public ContactsTransaction getCurrentTransaction() {
return mTransactionHolder.get();
} @Override
public Uri insert(Uri uri, ContentValues values) {
//添加ContactsTransaction到mTransactionHolder(线程本地存储)中。如果ContactsTrasanction不存在,创建一个。
//参数为由mSerializeOnDbHelper序列化的可写数据库,mSerializeDbTag,以及当前类的实现。
//false:代表当前为非批处理操作
ContactsTransaction transaction = startTransaction(false);
try {
Uri result = insertInTransaction(uri, values);//在子类中实现
if (result != null) {
transaction.markDirty();
}
transaction.markSuccessful(false);
return result;
} finally {
endTransaction(false);//结束当前事务,释放锁
}
} @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
ContactsTransaction transaction = startTransaction(false);
try {
int deleted = deleteInTransaction(uri, selection, selectionArgs);
if (deleted > 0) {
transaction.markDirty();
}
transaction.markSuccessful(false);
return deleted;
} finally {
endTransaction(false);
}
} @Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
ContactsTransaction transaction = startTransaction(false);
try {
int updated = updateInTransaction(uri, values, selection, selectionArgs);
if (updated > 0) {
transaction.markDirty();
}
transaction.markSuccessful(false);
return updated;
} finally {
endTransaction(false);
}
} @Override
public int bulkInsert(Uri uri, ContentValues[] values) {
ContactsTransaction transaction = startTransaction(true);//参数为true,代表批处理操作
int numValues = values.length;
int opCount = 0;
try {
for (int i = 0; i < numValues; i++) {
insert(uri, values[i]);
if (++opCount >= BULK_INSERTS_PER_YIELD_POINT) {
opCount = 0;
try {//如果批处理超过BULK_INSERTS_PER_YIELD_POINT(50),那么给其他线程请求让路。不要占用数据库太久
yield(transaction);//给其他线程让路,查看详细实现,查阅ContactProvider2中的yield方法实现。
} catch (RuntimeException re) {
transaction.markYieldFailed();
throw re;
}
}
}
transaction.markSuccessful(true);
} finally {
endTransaction(true);
}
return numValues;
} @Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
int ypCount = 0;
int opCount = 0;
ContactsTransaction transaction = startTransaction(true);//参数为true,代表批处理事务
try {
final int numOperations = operations.size();
final ContentProviderResult[] results = new ContentProviderResult[numOperations];
for (int i = 0; i < numOperations; i++) {
if (++opCount >= MAX_OPERATIONS_PER_YIELD_POINT) {//如果批处理个数太多,给其他线程让路
throw new OperationApplicationException(
"Too many content provider operations between yield points. "
+ "The maximum number of operations per yield point is "
+ MAX_OPERATIONS_PER_YIELD_POINT, ypCount);
}
final ContentProviderOperation operation = operations.get(i);
if (i > 0 && operation.isYieldAllowed()) {
opCount = 0;
try {
if (yield(transaction)) {
ypCount++;
}
} catch (RuntimeException re) {
transaction.markYieldFailed();
throw re;
}
} results[i] = operation.apply(this, results, i);
}
transaction.markSuccessful(true);
return results;
} finally {
endTransaction(true);
}
} /**
* If we are not yet already in a transaction, this starts one (on the DB to serialize on, if
* present) and sets the thread-local transaction variable for tracking. If we are already in
* a transaction, this returns that transaction, and the batch parameter is ignored.
* @param callerIsBatch Whether the caller is operating in batch mode.
* 添加ContactsTransaction到mTransactionHolder(线程本地存储)中。如果ContactsTrasanction不存在,创建一个。
* 参数为由mSerializeOnDbHelper序列化的可写数据库,mSerializeDbTag,以及当前类的实现。
* false:代表当前为非批处理操作
*/
private ContactsTransaction startTransaction(boolean callerIsBatch) {
ContactsTransaction transaction = mTransactionHolder.get();
if (transaction == null) {
transaction = new ContactsTransaction(callerIsBatch);
if (mSerializeOnDbHelper != null) {
transaction.startTransactionForDb(mSerializeOnDbHelper.getWritableDatabase(),
mSerializeDbTag, this);
}
mTransactionHolder.set(transaction);
}
return transaction;
} /**
* Ends the current transaction and clears out the member variable. This does not set the
* transaction as being successful.
* @param callerIsBatch Whether the caller is operating in batch mode.
* 结束事务。清楚线程本地存储中的ContactTransaction引用。
*/
private void endTransaction(boolean callerIsBatch) {
ContactsTransaction transaction = mTransactionHolder.get();
if (transaction != null && (!transaction.isBatch() || callerIsBatch)) {
try {
if (transaction.isDirty()) {//如果数据库存在变化,notifyChange。
notifyChange();
}
transaction.finish(callerIsBatch);//关闭由序列化SQLiteHelper创建的数据库上的事务。
} finally {
// No matter what, make sure we clear out the thread-local transaction reference.
mTransactionHolder.set(null);
}
}
} /**
* Gets the database helper for this contacts provider. This is called once, during onCreate().
*/
protected abstract SQLiteOpenHelper getDatabaseHelper(Context context); /**
* Gets the thread-local transaction holder to use for keeping track of the transaction. This
* is called once, in onCreate(). If multiple classes are inheriting from this class that need
* to be kept in sync on the same transaction, they must all return the same thread-local.
* 返回线程本地存储,用于追踪事务。在onCreate中被调用一次。;如果是多继承设计中,必须保证多次调用返回的是同一个对象。
*/
protected abstract ThreadLocal<ContactsTransaction> getTransactionHolder(); protected abstract Uri insertInTransaction(Uri uri, ContentValues values); protected abstract int deleteInTransaction(Uri uri, String selection, String[] selectionArgs); protected abstract int updateInTransaction(Uri uri, ContentValues values, String selection,
String[] selectionArgs); protected abstract boolean yield(ContactsTransaction transaction); protected abstract void notifyChange();
}
联系人数据库设计之AbstractContactsProvider的更多相关文章
- 联系人数据库设计之ContactsTransaction
不当之处,请雅正. 请自行下载android源代码 package com.android.providers.contacts; import com.google.android.collect. ...
- MySQL 数据库设计 笔记与总结(1)需求分析
数据库设计的步骤 ① 需求分析 ② 逻辑设计 使用 ER 图对数据库进行逻辑建模 ③ 物理设计 ④ 维护优化 a. 新的需求进行建表 b. 索引优化 c. 大表拆分 [需求分析] ① 了解系统中所要存 ...
- 一、MySQL中的索引 二、MySQL中的函数 三、MySQL数据库的备份和恢复 四、数据库设计和优化(重点)
一.MySQL中的索引###<1>索引的概念 索引就是一种数据结构(高效获取数据),在mysql中以文件的方式存在.存储建立了索引列的地址或者指向. 文件 :(以某种数据 结构存放) 存放 ...
- 电子商务(电销)平台中订单模块(Order)数据库设计明细
电子商务(电销)平台中订单模块(Order)数据库设计明细 - sochishun - 博客园 http://www.cnblogs.com/sochishun/p/7040628.html 电子商务 ...
- 电子商务(电销)平台中内容模块(Content)数据库设计明细
以下是自己在电子商务系统设计中的数据库设计经验总结,而今发表出来一起分享,如有不当,欢迎跟帖讨论~ 文章表 (article)|-- 自动编号|-- 文章标题 (title)|-- 文章类别编号 (c ...
- web-51job(前程无忧)-账户、简历-数据库设计
ylbtech-DatabaseDesgin:web-51job(前程无忧)-账户.简历-数据库设计 1.A,数据库关系图 1.B,数据库设计脚本 /App_Data/1,Account.sql ...
- CMDB数据库设计
title: CMDB 数据库设计 tags: Django --- CMDB数据库设计 具体的资产 服务器表和网卡.内存.硬盘是一对多的关系,一个服务器可以有多个网卡.多个内存.多个硬盘 hostn ...
- [SQL] 外卖系统数据库设计
注意: 1.项目需求:小程序外卖系统,以美团,饿了么为参考. 2.表设计没有外键约束,设计是在程序中进行外键约束. 3.希望通过分享该数据库设计,获取大家的建议和讨论. SQL: CREATE DAT ...
- 数据库设计_ERMaster安装使用_PowerDesigner数据设计工具
数据库设计 1. 说在前面 项目开发的流程包括哪些环节 需求调研[需求调研报告]-- 公司决策层 (1) 根据市场公司需求分析公司是否需要开发软件来辅助日常工作 (2) 公司高层市场考察,市场分析,决 ...
随机推荐
- [转]PostgreSQL 中文资料汇总
原文链接:http://francs3.blog.163.com/blog/static/405767272014017341219/ --1 中文社区网站 PostgreSQL 中文社区官网: h ...
- Python 第九篇:队列Queue、生产者消费者模型、(IO/异步IP/Select/Poll/Epool)、Mysql操作
Mysql操作: grant select,insert,update,delete on *.* to root@"%" Identified by "123456&q ...
- java Native 方法
一. 什么是Native Method 简单地讲,一个Native Method就是一个java调用非java代码的接口.一个Native Method是这样一个java的方法:该方法的实现由非j ...
- Linux下动态库使用
1. 静态库和动态库的基本概念 静态库,是在可执行程序连接时就已经加入到执行码中,在物理上成为执行程序的一部分:使用静态库编译的程序运行时无需该库文件支持,哪里都可以用, 但是生成的可执行文件较大.动 ...
- Homebrew 1.0.0 发布,MacOS 上的包管理器
神器,没有它不知道怎么用macos https://www.oschina.net/news/77367/homebrew-1-0-0
- 如何在VMware中修改Mac OS的屏幕分辨率
关于mac os分辨率问题:方法一:临时方法,只对当次启动有效,即在启动倒计时的时候,回车,等待输入参数是输入如下文本:“Graphics Mode"="1280x800x32@6 ...
- windows安装Apache,注册服务出现“(OS 5)拒绝访问。 : AH00369: Failed to open the WinNT service manager..."错误
原文:http://blog.csdn.net/jaray/article/details/9950211 在安装Apache的时候,我下载的是zip格式,不是msi安装版,需要自己注册服务,才能在桌 ...
- hdu4620 Fruit Ninja Extreme
Fruit Ninja Extreme Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- delphi高手突破学习笔记之面向对象类和对象的本质(有汇编解释 good)
知识点1:堆和栈 每个应用程序可以获得的内存空间分为两种:堆(heap)和栈(stack). 堆又称为“自由存储区”,其中的内存空间的分配与释放是必须由程序员来控制的.例如,用GetMem函数获取了一 ...
- 基于visual Studio2013解决面试题之1102合并字符串
题目