方案 1:使用 MySQL 的 INSERT ... ON DUPLICATE KEY UPDATE 語句(推薦)
前提條件
示例步驟
CREATE TABLE user (
id INT PRIMARY KEY, -- 主鍵(唯一約束)
name VARCHAR(50),
age INT
);
import java.sql.*;
public class MysqlUpsert {
// 數據庫連接信息
private static final String URL = "jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC";
private static final String USER = "root";
private static final String PASSWORD = "123456";
public static void upsertUser(int id, String name, int age) {
// SQL 語句:若 id 已存在則更新 name 和 age,否則插入新記錄
String sql = "INSERT INTO user (id, name, age) " +
"VALUES (?, ?, ?) " +
"ON DUPLICATE KEY UPDATE " + // 觸發條件:違反唯一約束(此處為 id 重複)
"name = ?, age = ?"; // 更新的字段(注意參數順序)
try (Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
PreparedStatement pstmt = conn.prepareStatement(sql)) {
// 設置插入的參數(id, name, age)
pstmt.setInt(1, id);
pstmt.setString(2, name);
pstmt.setInt(3, age);
// 設置更新的參數(name, age)—— 與上面的 name 和 age 一致
pstmt.setString(4, name);
pstmt.setInt(5, age);
// 執行 SQL(返回受影響的行數:插入成功返回1,更新成功返回2)
int rowsAffected = pstmt.executeUpdate();
System.out.println(rowsAffected > 0 ? "操作成功" : "操作失敗");
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 測試:第一次執行是插入(id=1不存在),第二次執行是更新(id=1已存在)
upsertUser(1, "張三", 20); // 插入
upsertUser(1, "張三", 21); // 更新(年齡從20→21)
}
}
方案 2:先查詢再判斷(適用於不支持 ON DUPLICATE KEY 的場景)
java
運行
public static void upsertUserByCheck(int id, String name, int age) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(URL, USER, PASSWORD);
conn.setAutoCommit(false); // 開啓事務
// 1. 查詢記錄是否存在
String checkSql = "SELECT id FROM user WHERE id = ?";
pstmt = conn.prepareStatement(checkSql);
pstmt.setInt(1, id);
rs = pstmt.executeQuery();
if (rs.next()) {
// 2. 記錄存在:執行更新
String updateSql = "UPDATE user SET name = ?, age = ? WHERE id = ?";
pstmt = conn.prepareStatement(updateSql);
pstmt.setString(1, name);
pstmt.setInt(2, age);
pstmt.setInt(3, id);
} else {
// 3. 記錄不存在:執行插入
String insertSql = "INSERT INTO user (id, name, age) VALUES (?, ?, ?)";
pstmt = conn.prepareStatement(insertSql);
pstmt.setInt(1, id);
pstmt.setString(2, name);
pstmt.setInt(3, age);
}
pstmt.executeUpdate();
conn.commit(); // 提交事務
System.out.println("操作成功");
} catch (SQLException e) {
try {
if (conn != null) conn.rollback(); // 事務回滾
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
// 關閉資源(rs, pstmt, conn)
try { if (rs != null) rs.close(); } catch (SQLException e) {e.printStackTrace();}
try { if (pstmt != null) pstmt.close(); } catch (SQLException e) {e.printStackTrace();}
try { if (conn != null) conn.close(); } catch (SQLException e) {e.printStackTrace();}
}
}
兩種方案對比
|
方案
|
優點
|
缺點
|
適用場景
|
|
|
性能好(一次 SQL 操作)、原子性強
|
依賴唯一約束,僅 MySQL 支持
|
支持該語法的 MySQL 環境
|
|
先查詢再操作
|
兼容性好(所有數據庫通用)
|
性能較差(至少兩次 SQL 操作)、需手動控制事務
|
不支持 |