网站首页 > 精选文章 正文
哈喽 大家好!
我是老陈,在学这节课之前,如果你对数据库不了解,建议你先看《程序员必修数据库》合集。操作数据库,就像人通过笔记本(数据库)记录信息,先找到笔记本(连接数据库),再按格式写内容(创建表结构),之后随时翻看、修改、补充(增删改查)。
我们以SQLite为例,学习Java是如何操作数据库的。首先,你需要去下载sqlite-jdbc开发包并导入到工程里。
37.1 创建数据库
通过JDBC实现与SQLite的交互,核心是通过驱动程序建立连接并执行数据库操作。SQLiteFeatures类包含创建数据库文件、连接管理及异常处理等核心功能。
package com.sqlite.demo;
import java.sql.*;
import java.io.File;
/**
* @author 今日头条:老陈说编程
* 使用Java的JDBC API连接SQLite数据库,
* 包含数据库文件自动创建、连接管理和基本异常处理功能。
* 使用说明:
* 1. 确保项目中包含SQLite JDBC驱动依赖
* 2. 运行程序后将在当前目录生成crm.db文件
* 3. 可通过修改dbPath变量指定其他数据库路径
* 异常处理:
* - 数据库连接失败时捕获SQLException并输出错误信息
* - 处理其他可能的运行时异常并提供堆栈跟踪
*/
public class SQLiteFeatures {
public static void main(String[] args) {
// 定义SQLite数据库文件路径
String dbPath = "crm.db";
// 创建文件对象用于检查数据库文件状态
File dbFile = new File(dbPath);
try {
// 检查数据库文件是否存在
if (!dbFile.exists()) {
System.out.println("数据库文件不存在,将自动创建:" + dbFile.getAbsolutePath());
// SQLite会在首次连接时自动创建不存在的数据库文件
}
// 使用try-with-resources自动关闭数据库连接
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbPath)) {
System.out.println("成功连接到SQLite数据库");
// 连接成功后再次检查文件状态并输出信息
if (dbFile.exists()) {
System.out.println("数据库文件大小:" + dbFile.length() + " 字节");
}
// 可在此处添加更多数据库操作代码
} catch (SQLException e) {
// 捕获SQL异常并输出错误信息和堆栈跟踪
System.out.println("数据库连接错误:" + e.getMessage());
e.printStackTrace();
}
} catch (Exception e) {
// 捕获其他未知异常
System.out.println("发生未知错误:" + e.getMessage());
e.printStackTrace();
}
}
}
37.2 创建表并插入数据
SQLiteBasicOps类使用JDBC在 SQLite 中创建具有自增主键和自动时间戳功能的数据表,搞懂资源自动管理和 SQL 异常处理机制。
package com.sqlite.demo;
import java.sql.*;
/**
* @author 今日头条:老陈说编程
* 使用Java的JDBC API连接SQLite数据库
* 创建表,并采用了try-with-resources自动关闭资源
*/
public class SQLiteBasicOps {
public static void main(String[] args) {
// 数据库文件路径
String dbPath = "crm.db";
// 使用try-with-resources自动关闭Connection连接
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbPath)) {
System.out.println("成功连接到SQLite数据库:" + dbPath);
// 1. 创建用户表,包含自增主键和创建时间戳
String createTableSQL = "CREATE TABLE IF NOT EXISTS users (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"username TEXT NOT NULL," +
"email INTEGER UNIQUE," +
"created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)";
// 使用try-with-resources自动关闭Statement
try (Statement stmt = conn.createStatement()) {
stmt.execute(createTableSQL);
System.out.println("用户表创建成功");
}
} catch (SQLException e) {
// 捕获SQL异常并打印错误信息和堆栈跟踪
System.out.println("数据库操作错误:" + e.getMessage());
e.printStackTrace();
}
}
}
37.3 数据操作:增删改查
旁白: SQLiteCRUD类通过 JDBC 操作 SQLite 数据库的完整增删改查流程,采用面向对象设计封装数据实体,并使用预编译语句防止 SQL 注入。
package com.sqlite.demo;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author 今日头条:老陈说编程
* SQLite数据库的完整CRUD操作
* 包含用户对象定义和对用户表的增删改查方法
* 使用了预编译语句防止SQL注入,并通过try-with-resources自动处理资源关闭
*/
public class SQLiteCRUD {
/**
* 用户实体类,封装用户信息
*/
static class Users {
private int id; // 用户ID,对应数据库主键
private String username; // 用户姓名
private String email; //邮件地址
// Getter和Setter方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// 重写toString方法,便于打印用户信息
@Override
public String toString() {
return "Users{id=" + id + ", username='" + username + "', email=" + email + "}";
}
}
public static void main(String[] args) {
String dbPath = "crm.db"; // 数据库文件路径
// 使用try-with-resources自动关闭数据库连接
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbPath)) {
// 确保数据库连接成功
System.out.println("成功连接到SQLite数据库");
// 1. 查询所有用户记录
List<Users> userList = queryAllUsers(conn);
System.out.println("查询到" + userList.size() + "个用户:");
userList.forEach(System.out::println);
// 2. 插入新用户并返回自动生成的ID
int newId = insertUser(conn, "王五", "user1@example.com");
System.out.println("插入新用户,ID:" + newId);
// 3. 更新指定用户的邮件
updateUserEmail(conn, newId, "user1@laochen.com");
System.out.println("更新用户邮箱为user666@laochen.com");
// 4. 根据ID删除用户
deleteUser(conn, 1); // 删除ID=1的用户
System.out.println("删除ID=1的用户");
// 5. 再次查询验证操作结果
userList = queryAllUsers(conn);
System.out.println("最终用户列表:");
userList.forEach(System.out::println);
} catch (SQLException e) {
// 异常处理:打印SQL异常堆栈信息
System.err.println("SQL操作错误: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 查询所有用户记录
*
* @param conn 数据库连接
* @return 用户列表
* @throws SQLException SQL操作异常
*/
private static List<Users> queryAllUsers(Connection conn) throws SQLException {
List<Users> list = new ArrayList<>();
String sql = "SELECT id, username, email FROM Users ORDER BY id";
// 使用try-with-resources自动关闭Statement和ResultSet
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
// 遍历结果集,将每条记录转换为Users对象
while (rs.next()) {
Users user = new Users();
user.setId(rs.getInt("id")); // 获取ID字段
user.setUsername(rs.getString("username")); // 获取姓名字段
user.setEmail(rs.getString("email")); // 获取邮箱
list.add(user);
}
}
return list;
}
/**
* 插入新用户记录
*
* @param conn 数据库连接
* @param name 用户名
* @param email 邮件地址
* @return 新记录的ID,失败时返回-1
* @throws SQLException SQL操作异常
*/
private static int insertUser(Connection conn, String name, String email) throws SQLException {
String sql = "INSERT INTO Users(username, email) VALUES (?, ?)";
// 使用预编译语句并要求返回生成的键
try (PreparedStatement pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
pstmt.setString(1, name); // 设置第一个参数
pstmt.setString(2, email); // 设置第二个参数
pstmt.executeUpdate();
// 获取自动生成的ID
try (ResultSet rs = pstmt.getGeneratedKeys()) {
if (rs.next()) {
return rs.getInt(1); // 返回自动生成的主键值
}
}
}
return -1; // 插入失败时返回-1
}
/**
* 更新用户年邮箱
*
* @param conn 数据库连接
* @param id 用户ID
* @param email 新邮箱
* @throws SQLException SQL操作异常
*/
private static void updateUserEmail(Connection conn, int id, String email) throws SQLException {
String sql = "UPDATE Users SET email = ? WHERE id = ?";
// 使用预编译语句防止SQL注入
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, email); // 设置邮箱
pstmt.setInt(2, id); // 设置ID参数
pstmt.executeUpdate();
}
}
/**
* 根据ID删除用户
*
* @param conn 数据库连接
* @param id 用户ID
* @throws SQLException SQL操作异常
*/
private static void deleteUser(Connection conn, int id) throws SQLException {
String sql = "DELETE FROM Users WHERE id = ?";
// 使用预编译语句执行删除操作
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id); // 设置ID参数
pstmt.executeUpdate();
}
}
}
37.4 事务处理:确保数据一致性
旁白: 事务是数据库操作的基本单元,确保一组 SQL 操作要么全部成功执行,要么在发生错误时全部回滚,维持数据的一致性。
package com.sqlite.demo;
import java.sql.*;
/**
* @author 今日头条:老陈说编程
* SQLite数据库事务处理
* 尝试向Users表中顺序插入两条用户记录,
* 由于使用固定ID(1),第二条插入会触发唯一约束冲突,
* 从而导致整个事务回滚。
*/
public class SQLiteTransaction {
/**
* 程序入口点
*
* @param args 命令行参数(未使用)
*/
public static void main(String[] args) {
// 数据库文件路径
String dbPath = "crm.db";
// 使用try-with-resources自动关闭数据库连接
try (Connection conn = DriverManager.getConnection("jdbc:sqlite:" + dbPath)) {
// 关闭自动提交,开启手动事务管理
conn.setAutoCommit(false);
System.out.println("开始事务操作");
try {
// 步骤1: 插入用户A(赵六)到Users表
insertUser(conn, "赵六", "user2@example.com");
System.out.println("插入用户A");
// 步骤2: 插入用户B(钱七),故意使用重复ID(1)引发约束冲突
insertUser(conn, "钱七", "user3@example.com");
System.out.println("插入用户B"); // 若上一步抛异常,此句不会执行
// 所有操作成功,提交事务
conn.commit();
System.out.println("事务提交成功");
} catch (SQLException e) {
// 捕获SQL异常,回滚事务到初始状态
conn.rollback();
System.out.println("事务回滚:" + e.getMessage());
} finally {
// 恢复自动提交模式(默认行为)
conn.setAutoCommit(true);
}
} catch (SQLException e) {
// 处理数据库连接异常
e.printStackTrace();
}
}
/**
* 向Users表插入用户记录(故意使用固定ID=1制造唯一约束冲突)
*
* @param conn 数据库连接
* @param username 用户姓名
* @param email 邮箱
* @throws SQLException 执行SQL语句异常
*/
private static void insertUser(Connection conn, String username, String email) throws SQLException {
// 注意:固定ID=1会导致多次插入时违反唯一约束
String sql = "INSERT INTO Users (id, username, email) VALUES (1, ?, ?)";
// 使用预编译语句防止SQL注入
try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, username); // 设置第一个占位符(姓名)
pstmt.setString(2, email); // 设置第二个占位符(邮箱)
pstmt.executeUpdate(); // 执行插入操作
}
}
}
总结SQLite的适用场景
移动应用本地存储:Android、iOS 和鸿蒙应用的本地数据持久化;
桌面工具数据存储:轻量级桌面应用的数据存储,如笔记和待办事项软件;
嵌入式系统:物联网设备、智能家居的本地数据记录;
下期将讲解网络请求,记得点赞关注,评论区留下你遇到的SQLite 操作问题,我们一起解决!
猜你喜欢
- 2025-07-23 MySQL之数据库的设计(mysql数据库设计与应用)
- 2025-07-23 MySQL--索引(mysql索引有哪几种)
- 2025-07-23 系统整容纪:用知识来"武装"自己~认识MySQL的锁与事务
- 2025-07-23 MySQL innodb的B+树到底长什么样,为什么MySQL要这样设计?
- 2025-07-23 软网推荐:超强密码的产生与记忆(网络密码解锁软件)
- 2025-07-23 Go语言数据库编程:GORM 的基本使用
- 2025-07-23 数据库——主键和唯一键的区别(mysql简述主键与唯一约束的区别)
- 2025-07-23 系统性能分析从入门到进阶(系统性能分析怎么写)
- 2025-07-23 从零开始一个完整的全栈项目(2) - 创建数据库表
- 2025-07-23 MySQL数据库之数据库约束,一文带你了解
- 最近发表
- 标签列表
-
- 向日葵无法连接服务器 (32)
- git.exe (33)
- vscode更新 (34)
- dev c (33)
- git ignore命令 (32)
- gitlab提交代码步骤 (37)
- java update (36)
- vue debug (34)
- vue blur (32)
- vscode导入vue项目 (33)
- vue chart (32)
- vue cms (32)
- 大雅数据库 (34)
- 技术迭代 (37)
- 同一局域网 (33)
- github拒绝连接 (33)
- vscode php插件 (32)
- vue注释快捷键 (32)
- linux ssr (33)
- 微端服务器 (35)
- 导航猫 (32)
- 获取当前时间年月日 (33)
- stp软件 (33)
- http下载文件 (33)
- linux bt下载 (33)