联系人数据库设计之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) 公司高层市场考察,市场分析,决 ...
随机推荐
- NGINX服务器打开目录浏览功能
我们做文件服务器的时候,希望打开目录浏览的功能.但是Nginx默认是不允许列出目录功能的.若需要此功能,需要在配置文件中手动开启. 首先需要打开开关.autoindex on;autoindex_ex ...
- 转:携程App的网络性能优化实践
http://kb.cnblogs.com/page/519824/ 携程App的网络性能优化实践 受益匪浅的一篇文章,让我知道网络交互并不是简单的传输和接受数据.真正的难点在于后面的性能优化 下面对 ...
- 【Cron Expressions】Quartz Scheduler 2.1.x 英文节选
Cron Expressions Cron-Expressions are used to configure instances ofCronTrigger. Cron-Expressions ar ...
- 《C++ Primer Plus》学习笔记1
C++ Primer Plus>学习笔记1 第二章.開始学习C++ 1.控制符endl 假设显示字符串时,在字符串中包括换行符,而不是在末尾加上endl,这样能够大大降低输入量:假设是要生成一个 ...
- SSH-Struts(一)——基本原理
简单介绍 Struts框架是MVC的一个实现,它非常好的结合了JSP.Servlet.JavaBean.Taglib等技术.它为MVC的各层提供了良好的支持,就像房地产商盖房子时先盖的大楼框架. 仅仅 ...
- [Codecademy] HTML&CSS第八课:Design a Button for Your Webwite
本文出自 http://blog.csdn.net/shuangde800 [Codecademy] HTML && CSS课程学习目录 --------------------- ...
- 真机測试时的错误:No matching provisioning profiles found
1.出现错误的原因是这种---- 公司接收一个外包项目,原来做真机測试的时候,用的是公司申请的苹果开发人员账号.如今项目结束了,准备上线,但客户要求使用客户自己的苹果开发人员是账号上线,于是就用客户的 ...
- mysql的1067错误 - 2
上一篇博文<mysql的1067错误>中由于日志配置问题产生1067错误. 由于要升级MySQL到V5.6,所以拷贝my.ini和数据文件到新的系统上. 在启动服务时,又出现1067错误! ...
- C#加密与解密
密码加密之类的用处,直接复制黏贴,可用 1.加密的代码: /// <summary> /// DEC 加密过程 /// </summary> /// <param nam ...
- 南京三星面试准备3--数组&基础数据结构
1.用递归颠倒一个栈. void PushToBottom(stack<int> &mystack,int num) { if(mystack.size()==0) { mysta ...