
1. 为什么我又把 Provider、ORMLite、GreenDao 拉出来跑了一遍Android 本地数据库选型这件事看起来是老生常谈但真正落到项目里很多人还是会卡在同一个问题上同一张表用 ContentProvider、ORMLite、GreenDao 分别写增删改查到底谁快、谁省事、谁更适合长期维护。我这次干脆把三种方案放在同一个工程里用同一套测试用例跑插入和查询把配置骨架和验证动作都整理出来方便你直接复现。这篇内容适合正在做 Android 本地存储选型的人也适合已经用了 SQLiteOpenHelper 但想对比 ORM 框架的同学。核心检索词就三个Provider、ORMLite、GreenDao外加性能对比和数据库操作。我会先给结论方向再给可复制的配置片段最后用 TaoToken 统一 Key/API 通道做一次验证请求把整个链路串起来。需要提前说明的是性能数字会受测试机、数据量、字段数量、是否批量事务影响所以我不编造具体毫秒值而是告诉你测试方法、观察点和常见偏差来源。你按本文步骤跑一遍得到的才是你自己设备上的真实结果。2. TaoToken 前置统一 Key 与 API 通道准备在开始写三种数据库实现之前先把 TaoToken 的配置准备好。原因很简单后面验证请求、跑模型对话、甚至让 coding agent 帮你生成 Dao 代码都需要一个统一的 API 通道。TaoToken 官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 注意 API 地址不带 UTM 参数。你需要先拿到 API Key。进入控制台创建 Key 的路径是https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite Key 管理页面在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。创建好之后复制保存后面 settings.json 里会用到。如果你只是想先验证模型通道是否通可以直接用模型对话页面https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。如果你打算长期做 Android 编码、让 Agent 帮你写 Provider 和 Dao 代码建议了解 Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite ClaudeCodeAnthropic 相关配置参考 https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite 。注意API Key 只放在本地配置文件或环境变量里不要硬编码进 Android 工程提交到仓库。数据库对比工程和 API 配置工程建议分开管理。3. 可复制配置Provider、ORMLite、GreenDao 三套骨架3.1 ContentProvider 注册片段与表结构ContentProvider 的写法确实比 ORM 复杂但它的优势是系统级支持、跨进程访问稳定。先在 AndroidManifest.xml 里注册 Providerprovider android:name.db.UserProvider android:authoritiescom.example.dbtest.provider android:exportedfalse /然后定义 Contract 类把表名、列名、URI 统一管理public final class UserContract { public static final String AUTHORITY com.example.dbtest.provider; public static final Uri CONTENT_URI Uri.parse(content:// AUTHORITY /users); public static final String TABLE users; public static final String COL_ID _id; public static final String COL_NAME name; public static final String COL_PHONE phone; }Provider 内部用 SQLiteOpenHelper 建表onCreate 里执行db.execSQL(CREATE TABLE IF NOT EXISTS users ( _id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, phone TEXT));增删改查通过 UriMatcher 分发insert 返回 Uriquery 返回 Cursor。Provider 的查询直接拿 Cursor 解析这也是它在读取场景表现不错的原因之一。3.2 ORMLite 配置骨架ORMLite 用注解映射表结构代码量比 Provider 少。先写实体类DatabaseTable(tableName users) public class User { DatabaseField(generatedId true) public int id; DatabaseField(canBeNull false) public String name; DatabaseField public String phone; public User() {} }再写 Helper 继承 OrmLiteSqliteOpenHelperpublic class UserDbHelper extends OrmLiteSqliteOpenHelper { private static final String DB_NAME ormlite.db; private static final int DB_VERSION 1; public UserDbHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } Override public void onCreate(SQLiteDatabase db, ConnectionSource cs) { try { TableUtils.createTable(cs, User.class); } catch (SQLException e) { throw new RuntimeException(e); } } Override public void onUpgrade(SQLiteDatabase db, ConnectionSource cs, int oldV, int newV) { try { TableUtils.dropTable(cs, User.class, true); onCreate(db, cs); } catch (SQLException e) { throw new RuntimeException(e); } } }Activity 可以继承 OrmLiteBaseActivity 直接拿 getHelper()也可以手动管理 Helper 的打开关闭。插入用 userDao.create(user)查询用 userDao.queryForAll()。3.3 GreenDao 生成器与 Dao 使用GreenDao 不用注解靠 Java 工程预生成代码所以运行时快。先建一个纯 Java 工程引入 greenDao-generator.jar 和 freemarker.jar写生成器public class ExampleDaoGenerator { public static void main(String[] args) throws Exception { Schema schema new Schema(3, com.example.dbtest.greendao.dao); addUser(schema); new DaoGenerator().generateAll(schema, ../dbTest/src-gen); } private static void addUser(Schema schema) { Entity user schema.addEntity(users); user.addIdProperty(); user.addStringProperty(name).notNull(); user.addStringProperty(phone); } }运行后会生成 DaoMaster、DaoSession、Users、UsersDao 四个类。Android 工程里这样初始化DevOpenHelper helper new DaoMaster.DevOpenHelper(this, greendao.db, null); DaoMaster daoMaster new DaoMaster(helper.getWritableDatabase()); UsersDao usersDao daoMaster.newSession().getUsersDao();之后 insert、deleteAll、queryBuilder 都通过 usersDao 调用。GreenDao 的 deleteAll 是一次性批量删除这点比 ORMLite 逐个删除要省事很多。3.4 TaoToken settings.json 配置示例把 API 通道配置成统一入口方便后面验证请求和让 Agent 辅助生成代码{ api_base: https://taotoken.net/api, api_key: 你的_API_KEY, model: 你的模型名, timeout: 60 }提示api_base 用 https://taotoken.net/api 不要加 UTM 参数。Key 从 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 获取。4. 验证请求与成功结果统一测试用例怎么跑4.1 测试用例设计三种方案用同一张 users 表字段一致id 自增、name 非空、phone 可空。测试动作分两组第一组插入 5000 条记录总耗时然后查询全部并解析。第二组先清空表再插入 1000 条重复插入和查询。每次插入前先删除旧数据观察删除方式对耗时的影响。// 统一测试入口示意 long start System.currentTimeMillis(); for (int i 0; i 5000; i) { User u new User(); u.name user_ i; u.phone 1380000 i; insertOne(u); // 三种方案各自实现 } long insertCost System.currentTimeMillis() - start; long qStart System.currentTimeMillis(); ListUser list queryAll(); long queryCost System.currentTimeMillis() - qStart;4.2 观察到的结果方向插入场景下GreenDao 优势明显因为它没有反射开销且批量操作可以走事务。ORMLite 因为用注解加反射单条插入偏慢而且它没有一次性删除全部数据的便捷接口只能逐条删清表阶段会拖慢整体。Provider 的写入中规中矩但读取时直接拿 Cursor 解析反而比较快。查询场景下Provider 多次读取的结论比较稳定。ORMLite 查询同样受反射影响。GreenDao 的 queryBuilder 在条件查询上更灵活但需要先生成代码初次配置容易晕。注意这些是方向性结论不是绝对排名。字段越多、数据量越大、是否开启事务都会改变结果。建议你自己跑一遍再下判断。4.3 用 TaoToken 验证通道配置好 settings.json 后发一次验证请求确认通道可用。可以用模型对话页面直接测试https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。如果返回正常说明 Key 和 api_base 配置正确后面让 Agent 帮你生成 Provider 或 Dao 代码就不会卡在通道上。5. 本篇常见错排查5.1 Provider 报 IllegalArgumentException: Unknown URL多数是 UriMatcher 没注册对应 code或者 AndroidManifest 里 authorities 和 Contract 里写的不一致。检查两处字符串是否完全相同包括包名前缀。5.2 ORMLite 报 Unable to create table常见原因是实体类没有无参构造函数或者 DatabaseField 用在了不支持的类型上。另外 TableUtils.createTable 要在 onCreate 里调用不要放到 Activity 里重复建表。5.3 GreenDao 生成代码失败先确认 Java 工程和 Android 工程目录关系generateAll 的路径是相对路径写错就生成到别处。再确认 greenDao-generator.jar 和 freemarker.jar 都引入了。生成后记得把 src-gen 目录加入 Android 工程的 sourceSets。5.4 清表慢得离谱ORMLite 没有 deleteAll 接口时逐条删除会非常慢。可以自己写 SQL 或改用 dao.executeRaw。GreenDao 直接用 deleteAll。Provider 用 delete 带 null 条件即可清空。5.5 TaoToken 请求 401Key 没填对或者 api_base 写成了带 UTM 的地址。正确写法是 https://taotoken.net/api 。Key 去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 重新复制。6. 选型建议与后续动作如果你追求系统级稳定和跨进程访问Provider 是绕不开的代价是代码量大。如果你想要注解式开发、代码量少ORMLite 上手快但要接受反射带来的性能损耗以及清表这类操作要自己补。如果你追求插入和批量操作性能GreenDao 更合适代价是多了代码生成这一步初次配置需要耐心。我自己的做法是小表、读多写少用 Provider中等复杂度、快速迭代用 ORMLite数据量大、写入频繁用 GreenDao。三种方案不是互斥的同一个项目里按表选型也完全可行。后续你可以把条件查询、条件删除、批量事务这几组测试补上结果会更完整。需要让 Agent 帮你补测试代码或生成 Dao 骨架可以从 Coding Plan 进入https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入细节看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。