联系人数据库设计之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) 公司高层市场考察,市场分析,决 ...
随机推荐
- PHP - FTP上传文件类
/** * 作用:FTP操作类( 拷贝.移动.删除文件/创建目录 ) * 时间:2006/5/9 * 作者:欣然随风 * QQ:276624915 */ class class_ftp { publi ...
- CentOS下Samba文件服务器的安装与配置
CentOS下Samba文件服务器的安装与配置 http://blog.csdn.net/limingzhong198/article/details/22064801 一.安装配置 1. 安装sam ...
- sqlplus
以超级管理员登录 sqlplus sys/123 as sysdba 解锁用户 alter user xutianhao account unlock
- VC6.0 导入资源崩溃
等我以后挣钱了一定买正版! 最近学习Win32编程,为了锻炼自己,在网上下载了一个VC6.0作为开发工具,应该是兼容性的问题吧,VC6 经常闹毛病. 今天导入资源的时候VC6出现崩溃的现象. 马上寻求 ...
- java.util.concurrent-------TimeUnit
java.util.concurrent并发库是JDK1.5新增的,其作者是Doug Lea ,此人是个BOSS级别的天才人物了.有了他提供的类库,使得我们对多线程并发.锁有了很大的帮助,减少了并发难 ...
- (读书笔记).NET大局观-.NET框架类库概观
.NET框架类库概况 构建在.NET框架上所有的软件,都会用到通用语言进行时,即使基于最简单的CLR程序,也需要用到一部分.NET框架类库,更精致复杂的软件则使用这个类库提供的更多服务. .NET框架 ...
- 基于visual Studio2013解决C语言竞赛题之1003字母打印
题目 解决代码及点评 ///************************************************************************/ ...
- URAL 1792. Hamming Code (枚举)
1792. Hamming Code Time limit: 1.0 second Memory limit: 64 MB Let us consider four disks intersectin ...
- StreamWrite-StreamRead 读写文本文件
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- 托管到GitHub
如何把项目托管到GitHub iOS开发拓展篇——如何把项目托管到GitHub 说明:本文主要介绍如何把一个OC项目托管到Github,重操作轻理论. 第一步:先注册一个Github的账号,这是必须的 ...