联系人数据库设计之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 - mysql使用参数数据
"SELECT dg_id FROM dg_user WHERE dg_username = '{$clean['username']}' LIMIT 1","该用户已经 ...
- saltstack:使用教程之一安装及客户端返回写入MySQL
saltstack使用教程: 1.安装: 需要epel的yum源,没有的话把下面的复制并新建个文件 /etc/yum.repos.d/epel.repo 粘贴即可: [epel] name=Extra ...
- Android--开发过程中使用到的长度单位
px:表示屏幕实际的像素. in:表示英寸. mm:毫米. pt:表示一个点,是屏幕的物理尺寸. dp:(与密度无关的像素)逻辑长度单位,在160dpi屏幕上,1dp = 1px = 1/160英寸 ...
- 用PowerMockito来mock私有方法(转)
话说我们做的所谓的接口测试真的是不伦不类啊,测的是controller层,那叫接口木??!!可是老大们说写的是接口测试,那就接口吧! 自接手写这个接口测试不久,很多人,包括一个关系比较好的架构师就跟我 ...
- PHP函数详细剖析之rtrim函数 By ACReaper
string rtrim ( string $str [, string $charlist ] ) 这个函数很好理解.r表示右边.trim表示修剪.即右边修剪.默认修剪字符str右边的字符.默认修剪 ...
- mysql 初识之日志文件篇
日志文件 1. err日志 error log 记录mysql在运行的过程中所有较为严重的警告和错误信息,以及mysql server每次启动和关闭的详细信息.系统在默认情况下关闭error ...
- No mapping found for HTTP request with URI [/HelloWeb/] in DispatcherServlet with name 'HelloWeb' Spring MVC
I'm learning the Spring Framework, and I'm doing the HelloWeb tutorial on tutorialspoint, and I can' ...
- Milonga_百度百科
Milonga_百度百科 Milonga是Tango的一种.源于并盛行于阿根廷.6/8拍的舞曲.节奏为 AXX BXX CX 分别都是8分音符.由于第3组节奏音只有2个8分音符,比前2组而缺少 ...
- 手动加入PE文件数字签名信息及格式具体解释图之下(历史代码,贴出学习)
#include <windows.h> HANDLE hWriteFileHandle = NULL ; HANDLE hReadFileHandle = NULL ; HANDLE h ...
- Determine whether an integer is a palindrome. Do this without extra space.
看到这个题目的时候,首先不认识 Determine这个单词.英文不好没办法,查了下是确认的意思,然后不懂 palindrome这个单词, 查了下是回文的意思. 问题是 回文是个什么东西,官方解释: A ...