首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JDBC 實戰:Java 連接 SQL Server 完整 CRUD 教程(含驅動配置、連接池、事務)

     編輯:Java 綜合教學

Java JDBC 操作 SQL Server 完整指南:從驅動安裝到生產級 CRUD 封裝

JDBC(Java Database Connectivity)是 Java 訪問關係型數據庫的統一 API。本文以 SQL Server 2012+ 為例,涵蓋驅動下載、Maven/Gradle 依賴、連接參數、CRUD 完整代碼、預編譯防注入、事務控制與連接池最佳實踐。

1. 環境準備

1.1 下載 JDBC 驅動

<dependency>
    <groupId>com.microsoft.sqlserver</groupId>
    <artifactId>mssql-jdbc</artifactId>
    <version>12.4.2.jre11</version> <!-- 根據 JDK 版本選擇 jre8/jre11/jre17 -->
</dependency>

1.2 SQL Server 配置

  • 啟用 TCP/IP 協議:SQL Server Configuration Manager → Protocols for MSSQLSERVER → TCP/IP Enabled。
  • 固定埠 1433(或自定義),防火牆放行。
  • 啟用 SQL Server 驗證模式(混合模式),設定 sa 密碼。
  • 建立測試庫:CREATE DATABASE java_conn_test;

2. 連接工具類

public class JdbcUtil {
    private static final String URL = "jdbc:sqlserver://localhost:1433;DatabaseName=java_conn_test;encrypt=true;trustServerCertificate=true";
    private static final String USER = "sa";
    private static final String PASS = "123456";

    static {
        try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); }
        catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(e); }
    }

    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASS);
    }

    public static void close(Connection c, Statement s, ResultSet r) {
        try { if (r != null) r.close(); } catch (SQLException ignore) {}
        try { if (s != null) s.close(); } catch (SQLException ignore) {}
        try { if (c != null) c.close(); } catch (SQLException ignore) {}
    }
}

關鍵參數:encrypt=true;trustServerCertificate=true 解決 JDK 11+ 默認要求 SSL 加密導致的連接失敗。

3. CRUD 核心代碼

3.1 查詢

public List<User> queryAll() {
    String sql = "SELECT UserId, UserName, UserPwd FROM tb_User";
    try (Connection c = JdbcUtil.getConnection();
         PreparedStatement ps = c.prepareStatement(sql);
         ResultSet rs = ps.executeQuery()) {
        List<User> list = new ArrayList<>();
        while (rs.next()) {
            list.add(new User(rs.getString("UserId"), rs.getString("UserName"), rs.getString("UserPwd")));
        }
        return list;
    } catch (SQLException e) { throw new RuntimeException(e); }
}

3.2 新增

public int insert(User u) {
    String sql = "INSERT INTO tb_User (UserId, UserName, UserPwd) VALUES (NEWID(), ?, ?)";
    try (Connection c = JdbcUtil.getConnection();
         PreparedStatement ps = c.prepareStatement(sql)) {
        ps.setString(1, u.getUserName());
        ps.setString(2, u.getUserPwd());
        return ps.executeUpdate();
    } catch (SQLException e) { throw new RuntimeException(e); }
}

3.3 修改

public int updatePwd(String userId, String newPwd) {
    String sql = "UPDATE tb_User SET UserPwd = ? WHERE UserId = ?";
    try (Connection c = JdbcUtil.getConnection();
         PreparedStatement ps = c.prepareStatement(sql)) {
        ps.setString(1, newPwd);
        ps.setString(2, userId);
        return ps.executeUpdate();
    } catch (SQLException e) { throw new RuntimeException(e); }
}

3.4 刪除

public int delete(String userId) {
    String sql = "DELETE FROM tb_User WHERE UserId = ?";
    try (Connection c = JdbcUtil.getConnection();
         PreparedStatement ps = c.prepareStatement(sql)) {
        ps.setString(1, userId);
        return ps.executeUpdate();
    } catch (SQLException e) { throw new RuntimeException(e); }
}

4. 事務控制範例

public void transfer(String fromId, String toId, double amount) {
    Connection c = null;
    try {
        c = JdbcUtil.getConnection();
        c.setAutoCommit(false); // 開啟事務

        // 扣款
        try (PreparedStatement ps = c.prepareStatement("UPDATE tb_Account SET balance = balance - ? WHERE user_id = ?")) {
            ps.setDouble(1, amount);
            ps.setString(2, fromId);
            ps.executeUpdate();
        }
        // 入賬
        try (PreparedStatement ps = c.prepareStatement("UPDATE tb_Account SET balance = balance + ? WHERE user_id = ?")) {
            ps.setDouble(1, amount);
            ps.setString(2, toId);
            ps.executeUpdate();
        }

        c.commit(); // 提交
    } catch (SQLException e) {
        try { if (c != null) c.rollback(); } catch (SQLException ignore) {}
        throw new RuntimeException("轉賬失敗", e);
    } finally {
        try { if (c != null) c.setAutoCommit(true); } catch (SQLException ignore) {}
        JdbcUtil.close(c, null, null);
    }
}

5. 生產級升級:引入 HikariCP 連接池

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>
public class DataSourceUtil {
    private static final HikariDataSource ds = new HikariDataSource();
    static {
        ds.setJdbcUrl("jdbc:sqlserver://localhost:1433;DatabaseName=java_conn_test;encrypt=true;trustServerCertificate=true");
        ds.setUsername("sa");
        ds.setPassword("123456");
        ds.setMaximumPoolSize(20);
        ds.setMinimumIdle(5);
        ds.setIdleTimeout(300_000);
        ds.setConnectionTimeout(30_000);
        ds.setPoolName("SQLServer-Pool");
    }
    public static DataSource getDataSource() { return ds; }
}

後續直接 DataSourceUtil.getDataSource().getConnection() 獲取連接,無需手動關閉(歸還池中)。

6. 常見坑與避坑指南

現象原因解決
The driver could not establish a secure connectionJDK 11+ 默認 SSL,驅動版本過低或未配置信任憑證升級驅動 12.2+,URL 加 trustServerCertificate=true
Login failed for user 'sa'密碼錯誤/未啟用混合驗證/sa 鎖定SSMS 重置密碼、啟用 SQL 驗證、解鎖登錄
ResultSet 獲取不到數據游標默認 TYPE_FORWARD_ONLY,需 rs.next() 推進while(rs.next()) 循環讀取
PreparedStatement 防注入失效拼接 SQL 字符串而非用 ? 佔位符全部參數化,動態 IN 列表用 String.join 生成 ? 序列

7. 總結

掌握 JDBC 核心流程:加載驅動 → 獲取連接 → 預編譯 SQL → 綁參數 → 執行 → 處理結果 → 釋放資源。生產環境務必上連接池、統一異常處理、開啟慢 SQL 監控。下一步可學習 MyBatis/JPA 等 ORM 框架提升開發效率。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved