☰
JAVA 建立 DAO 包实现增删改查:方法调用与 TaoToken 统一 Key 接入实践
2026/10/8 17:58:52 网站建设 项目流程

1. 从一次真实的 DAO 重构说起:为什么你的增删改查总是散落各处

刚接手一个 Java 项目时,我最怕看到的不是复杂算法,而是打开MainActivity或者某个Service类,发现里面塞满了SQLiteDatabase db = helper.getWritableDatabase();这样的代码。插入一条数据要写一遍ContentValues,查询一条数据要写一遍Cursor遍历,删除和更新又是另外几坨逻辑。这种写法在功能少的时候还能忍,一旦表结构变了、字段加了一个,你就得满项目搜索values.put去改,漏掉一处就是线上事故。

DAO 包要解决的就是这个问题。DAO 全称 Data Access Object,翻译过来就是数据访问对象。你可以把它理解成数据库和业务逻辑之间的一道“前台”:业务代码想存一条用户记录,不需要知道底层是 SQLite、MySQL 还是别的什么,只需要告诉前台“帮我存一下这个用户”,前台负责翻译成具体的 SQL 语句、处理游标、关闭连接。这道前台就是 DAO 层。

具体到 Java 项目里,一个标准的 DAO 包通常包含三部分:实体类(Entity/Bean)、DAO 接口(定义增删改查方法签名)、DAO 实现类(真正写 SQL 和游标操作的地方)。业务层只依赖接口,不依赖实现,这样以后换数据库、加缓存、做单元测试都方便。我试过在一个中等规模的项目里把散落的数据库操作全部收拢到 DAO 包,代码行数少了将近三分之一,而且新增字段时只需要改实体类和对应的实现类,业务层几乎不用动。

这篇文章会带你从零建立 DAO 包,写出可复制的增删改查接口与实现,然后跑通方法调用链路。同时,因为现在很多项目需要调用大模型能力来做数据清洗、字段补全或者智能查询,我会把 TaoToken 的统一 Key 接入也串进来,让你在 DAO 层之外,顺手把 AI 通道的配置也理清楚。适合谁看?适合已经会写 Java 基础语法、但项目里数据库代码还比较乱、想系统整理一层的开发者。下面直接进入实操。

2. TaoToken 统一 Key 前置准备:把 AI 通道配置成 DAO 之外的一个“数据源”

在讲 DAO 代码之前,先花几分钟把 TaoToken 的 Key 拿到手。为什么放在前面?因为后面验证请求时,我们会写一个调用示例,把 DAO 查询出来的数据送给模型做处理,如果没有 Key,那一步就卡住了。TaoToken 在这里扮演的角色,是一个统一的 API 通道,你不需要在项目里维护多套不同厂商的 Key,一个 Key 就能走通模型对话、编码辅助等能力。

获取 Key 的入口在官网控制台。打开https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,注册登录后进入控制台,找到 API Keys 页面,新建一个 Key。这个 Key 就是后面所有请求的凭证。注意,Key 只在创建时完整显示一次,复制下来存到安全的地方,不要直接硬编码在 Java 源码里提交到仓库。

拿到 Key 之后,你需要知道两个地址:Base URL 是https://taotoken.net/api,这个地址不加任何 UTM 参数,直接用于代码里的请求前缀。模型 ID 根据你的需求选,比如做通用对话可以用gpt-4o或者claude-3-5-sonnet这类,具体以控制台模型列表为准。这三个东西——Base URL、Key、Model ID——就是接入的三件套,缺一不可。

在 Java 项目里,我建议把这三个值放到配置文件或者环境变量里,而不是写死在代码中。比如用config.properties:

taotoken.base.url=https://taotoken.net/api taotoken.api.key=sk-你的实际Key taotoken.model.id=gpt-4o

然后在代码里用Properties加载。这样做的好处是,本地开发、测试环境、生产环境可以各用各的 Key,切换时不用改代码。如果你用的是 Spring Boot,直接放到application.yml里更自然:

taotoken: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} model-id: gpt-4o

这里api-key用环境变量注入,避免明文出现在配置文件里。这一步做完,你的项目就具备了调用 AI 通道的基础条件。接下来我们回到 DAO 包本身,先把增删改查的骨架搭起来,最后再把这两条线接上。

3. 可复制配置:DAO 接口、实现类与 TaoToken 请求参数完整片段

这一节是全文的核心,我会给出完整的 DAO 包结构、接口定义、实现类代码,以及 TaoToken 请求的 JSON 配置片段。你可以直接复制到自己的项目里改包名和表名。

先看包结构。假设项目根包是com.example.app,那么 DAO 包可以这样组织:

com.example.app ├── entity │ └── User.java ├── dao │ ├── UserDao.java // 接口 │ └── impl │ └── UserDaoImpl.java // 实现类 └── util └── DBHelper.java // 数据库帮助类

实体类User.java对应数据库表user,字段有id、name、jsons:

package com.example.app.entity; public class User { private int id; private String name; private String jsons; public User() {} public User(String name, String jsons) { this.name = name; this.jsons = jsons; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getJsons() { return jsons; } public void setJsons(String jsons) { this.jsons = jsons; } }

DAO 接口UserDao.java定义增删改查方法签名。注意这里只定义“做什么”,不定义“怎么做”:

package com.example.app.dao; import com.example.app.entity.User; import java.util.List; public interface UserDao { long insert(User user); int deleteByName(String name); int update(User user); User selectByName(String name); List<User> selectAll(); }

实现类UserDaoImpl.java是真正干活的地方。这里用 SQLite 举例,如果你用 MySQL,把SQLiteDatabase换成Connection和PreparedStatement即可,思路完全一样:

package com.example.app.dao.impl; import android.content.ContentValues; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.example.app.dao.UserDao; import com.example.app.entity.User; import com.example.app.util.DBHelper; import java.util.ArrayList; import java.util.List; public class UserDaoImpl implements UserDao { private final DBHelper dbHelper; public UserDaoImpl(DBHelper dbHelper) { this.dbHelper = dbHelper; } @Override public long insert(User user) { SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("name", user.getName()); values.put("jsons", user.getJsons()); long rowId = db.insert("user", null, values); db.close(); return rowId; } @Override public int deleteByName(String name) { SQLiteDatabase db = dbHelper.getWritableDatabase(); int rows = db.delete("user", "name=?", new String[]{name}); db.close(); return rows; } @Override public int update(User user) { SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("jsons", user.getJsons()); int rows = db.update("user", values, "name=?", new String[]{user.getName()}); db.close(); return rows; } @Override public User selectByName(String name) { SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.query("user", null, "name=?", new String[]{name}, null, null, null); User user = null; if (cursor.moveToFirst()) { user = new User(); user.setId(cursor.getInt(cursor.getColumnIndexOrThrow("id"))); user.setName(cursor.getString(cursor.getColumnIndexOrThrow("name"))); user.setJsons(cursor.getString(cursor.getColumnIndexOrThrow("jsons"))); } cursor.close(); db.close(); return user; } @Override public List<User> selectAll() { SQLiteDatabase db = dbHelper.getReadableDatabase(); Cursor cursor = db.query("user", null, null, null, null, null, "id ASC"); List<User> list = new ArrayList<>(); while (cursor.moveToNext()) { User user = new User(); user.setId(cursor.getInt(cursor.getColumnIndexOrThrow("id"))); user.setName(cursor.getString(cursor.getColumnIndexOrThrow("name"))); user.setJsons(cursor.getString(cursor.getColumnIndexOrThrow("jsons"))); list.add(user); } cursor.close(); db.close(); return list; } }

注意几个细节:查询用getReadableDatabase(),写入用getWritableDatabase();游标用完必须close();getColumnIndexOrThrow比getColumnIndex更安全,字段名写错会直接抛异常而不是返回 -1。这些是我踩过的坑,早期用getColumnIndex时字段名拼错,查出来全是 null,排查了半天。

接下来是 TaoToken 的请求配置片段。如果你要在 DAO 查询之后调用模型,请求体 JSON 长这样:

{ "model": "gpt-4o", "messages": [ { "role": "system", "content": "你是一个数据清洗助手,请把用户 JSON 字段补全为标准格式。" }, { "role": "user", "content": "{\"name\":\"张三\",\"jsons\":\"{\\\"age\\\":25}\"}" } ], "temperature": 0.3 }

请求头里带上Authorization: Bearer sk-你的Key,请求地址是https://taotoken.net/api/v1/chat/completions。这个 JSON 可以直接用 Java 的HttpURLConnection或者 OkHttp 发出去。如果你用 Spring Boot,也可以用RestTemplate。关键是把 Base URL、Key、Model ID 三件套对应上,不要漏掉Bearer前缀。

4. 验证请求与成功结果:从 DAO 查询到模型返回的完整调用链路

代码写完了,怎么确认它真的能跑通?这一节我给你一个完整的验证流程,从数据库插入一条数据开始,到 DAO 查询,再到把查询结果送给 TaoToken 模型,最后打印返回内容。

先写一个测试用的main方法或者单元测试。假设你已经初始化了DBHelper,并且数据库表user已经建好:

public class DaoTest { public static void main(String[] args) { DBHelper dbHelper = new DBHelper(); UserDao userDao = new UserDaoImpl(dbHelper); // 1. 插入 User user = new User("张三", "{\"age\":25}"); long rowId = userDao.insert(user); System.out.println("插入成功,rowId=" + rowId); // 2. 查询 User queried = userDao.selectByName("张三"); System.out.println("查询结果:" + queried.getName() + " -> " + queried.getJsons()); // 3. 更新 queried.setJsons("{\"age\":26,\"city\":\"北京\"}"); int updated = userDao.update(queried); System.out.println("更新行数:" + updated); // 4. 删除 int deleted = userDao.deleteByName("张三"); System.out.println("删除行数:" + deleted); } }

运行后你应该看到类似输出:

插入成功,rowId=1 查询结果:张三 -> {"age":25} 更新行数:1 删除行数:1

如果rowId返回 -1,说明插入失败,通常是表名或字段名写错了。如果查询返回 null,检查moveToFirst()是否返回 false,也就是没查到数据。这些是 DAO 层最常见的验证点。

接下来验证 TaoToken 请求。写一个简单的 HTTP 调用方法:

import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; public class TaoTokenClient { private static final String BASE_URL = "https://taotoken.net/api"; private static final String API_KEY = System.getenv("TAOTOKEN_API_KEY"); private static final String MODEL_ID = "gpt-4o"; public static String chat(String userContent) throws IOException { URL url = new URL(BASE_URL + "/v1/chat/completions"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Type", "application/json"); conn.setRequestProperty("Authorization", "Bearer " + API_KEY); conn.setDoOutput(true); String body = "{\"model\":\"" + MODEL_ID + "\",\"messages\":[{\"role\":\"user\",\"content\":\"" + userContent.replace("\"", "\\\"") + "\"}]}"; try (OutputStream os = conn.getOutputStream()) { os.write(body.getBytes(StandardCharsets.UTF_8)); } int code = conn.getResponseCode(); InputStream is = (code == 200) ? conn.getInputStream() : conn.getErrorStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { sb.append(line); } reader.close(); return "HTTP " + code + " -> " + sb.toString(); } public static void main(String[] args) throws IOException { String result = chat("请把 {\"age\":25} 补全为包含 city 字段的 JSON"); System.out.println(result); } }

运行前确保环境变量TAOTOKEN_API_KEY已经设置。成功时你会看到HTTP 200以及一段 JSON 响应,里面choices[0].message.content就是模型返回的内容。如果返回 401,说明 Key 不对或者没带上Bearer前缀。如果返回 404,检查 Base URL 是不是写成了https://taotoken.net/api后面多加了斜杠或者少加了/v1。

把 DAO 查询和模型调用串起来,就是完整的链路:UserDaoImpl.selectByName拿到jsons字段,传给TaoTokenClient.chat,模型返回补全后的 JSON,你再写回数据库。这条链路跑通,说明你的 DAO 层和 AI 通道都配置正确了。

5. 本篇常见错排查:401、local proxy failed、reading choices 与 OAuth 报错对照

这一节把我在实际项目中遇到的报错整理出来,对照着排查,能省不少时间。

401 Unauthorized。这是最常见的。原因通常有三个:Key 没设置、Key 复制时多了空格、请求头没加Bearer。检查Authorization头的值是不是Bearer sk-xxx,注意Bearer和 Key 之间有一个空格。另外,如果你把 Key 放在config.properties里,注意 Java 读取时会不会把行尾的\r也读进去,用trim()处理一下。

local proxy failed。这个报错通常出现在你本地网络环境有代理设置,但代码没有走代理,或者代理地址配错了。检查你的HttpURLConnection是否被系统属性http.proxyHost影响。如果你不需要代理,可以在代码里清除:System.clearProperty("http.proxyHost")。如果你确实需要走代理,确保代理地址和端口正确,并且代理允许访问taotoken.net。

reading choices 报错。这个通常发生在解析响应 JSON 时,choices数组为空或者结构不对。原因可能是模型 ID 写错了,服务端返回了错误信息而不是正常的对话结构。先打印完整的响应体,看看error字段说了什么。常见的是模型 ID 不在可用列表里,换成控制台里确认过的模型 ID 即可。

OAuth 相关报错。如果你用的是某些需要 OAuth 授权的客户端工具,报错可能提示 token 过期或者 scope 不足。TaoToken 的 API Key 方式是直接 Bearer 认证,不涉及 OAuth 流程。如果你在 Claude Code 或者 Cline 这类工具里配置,注意选择 API Key 模式而不是 OAuth 模式。配置时三件套要写全:Base URL 填https://taotoken.net/api,Key 填你的sk-开头字符串,Model ID 填控制台里选的模型。

数据库相关报错。no such table说明表没建,检查DBHelper.onCreate里的建表语句。no such column说明字段名写错,用getColumnIndexOrThrow能提前暴露。CursorWindowAllocationException通常是查询返回数据量太大,加LIMIT或者分页。

连接超时。如果你在HttpURLConnection里没设置超时,默认是无限等待。建议设置conn.setConnectTimeout(10000)和conn.setReadTimeout(30000)。超时后捕获SocketTimeoutException,做重试或者降级处理。

把这些报错对照表放在手边,下次遇到直接查。排查的核心思路是:先看 HTTP 状态码,再看响应体里的error字段,最后检查配置三件套是否一致。

6. 语义一致 CTA:把 DAO 层和 AI 通道都收进你的项目骨架

DAO 包建好之后,你的项目就有了清晰的数据访问边界。业务层调用UserDao接口,不关心底层是 SQLite 还是 MySQL;实现类里集中处理游标、事务、异常;实体类负责数据承载。这套结构在项目变大时优势特别明显,新增一张表就是新增一个实体、一个接口、一个实现,互不干扰。

AI 通道的接入也是同样的思路。把 TaoToken 的 Base URL、Key、Model ID 当成一个“外部数据源”来配置,和数据库配置放在同一层级。这样你的项目里就有两类数据源:本地数据库走 DAO,远程模型走 HTTP 客户端。两者通过业务层编排,比如先查数据库,再把结果送给模型处理,最后写回数据库。

如果你在验证模型返回时想快速试不同的模型 ID,可以直接用模型对话页面发几条消息,确认模型可用后再写进代码。如果你打算长期在编码和 Agent 场景里用这个通道,Coding Plan 会更合适,配置一次就能在多个工具里复用。接入文档里有各语言和各工具的详细配置示例,遇到不确定的参数直接查文档比猜快得多。

最后留一个实用技巧:在 DAO 实现类里,把db.close()放在finally块里,而不是直接写在方法末尾。这样即使查询过程中抛异常,数据库连接也能正常释放。早期我没注意这点,跑批量插入时连接池很快就被占满了。把这个习惯养成,你的 DAO 层会稳很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询