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

JDBC 數據庫連接與 CRUD 完整實戰:從驅動加載到連接池最佳實踐

     編輯:Java 綜合教學

手把手構建 Java 數據庫訪問基石:MySQL 驅動、Connection、PreparedStatement、ResultSet、事務、連接池全流程

JDBC 是 Java 訪問關係型數據庫的統一 API。本文以 MySQL 為例,完整演示驅動加載、建立連接、實體類映射、DAO 層封裝 (增刪改查)、Servlet 控制器調用、JSP 頁面交互、字符集過濾器、項目目錄結構,並給出生產環境必備的連接池 (Druid/HikariCP) 遷移指南。

一、 環境準備與資料庫腳本

CREATE DATABASE LandDB;
USE LandDB;
CREATE TABLE T_BL_CANTON_CODE (
    CTN_CODE INT PRIMARY KEY,
    CTN_NAME VARCHAR(60) NOT NULL,
    GOV_NAME VARCHAR(60) NOT NULL,
    LAND_DP_NAME VARCHAR(60) NOT NULL,
    PARENT_CODE INT NOT NULL
);
INSERT INTO T_BL_CANTON_CODE VALUES (12000, '長沙市', '長沙市人民政府', '長沙市國土資源廳', 'HN');
INSERT INTO T_BL_CANTON_CODE VALUES (11000, '北京市', '北京市人民政府', '北京市國土資源廳', 'BN');

驅動包:mysql-connector-java-5.1.x.jar 放入 WEB-INF/lib 或 Maven 依賴。

二、 核心類代碼實現

1. 實體類 Canton

public class Canton {
    private int ctn_code;
    private String ctn_name, gov_name, land_dp_name, parent_code;
    // Getter/Setter 省略
}

2. 數據庫連接工具類 BuildConn

public class BuildConn {
    private static final String URL = "jdbc:mysql://localhost:3306/landdb";
    private static final String USER = "user2";
    private static final String PASS = "123456";

    public Connection openConn() throws SQLException {
        try { Class.forName("com.mysql.jdbc.Driver"); }
        catch (ClassNotFoundException e) { throw new SQLException("驅動加載失敗", e); }
        return DriverManager.getConnection(URL, USER, PASS);
    }
}

3. DAO 實現類 CantonDaoImp

public class CantonDaoImp {
    private BuildConn buildConn = new BuildConn();

    // 增
    public boolean addCanton(Canton c) {
        String sql = "INSERT INTO T_BL_CANTON_CODE VALUES (?,?,?,?,?)";
        try (Connection con = buildConn.openConn();
             PreparedStatement ps = con.prepareStatement(sql)) {
            ps.setInt(1, c.getCtn_code());
            ps.setString(2, c.getCtn_name());
            ps.setString(3, c.getGov_name());
            ps.setString(4, c.getLand_dp_name());
            ps.setString(5, c.getParent_code());
            return ps.executeUpdate() > 0;
        } catch (SQLException e) { e.printStackTrace(); return false; }
    }

    // 刪 (按主鍵)
    public int delCanton(int ctnCode) {
        String sql = "DELETE FROM T_BL_CANTON_CODE WHERE CTN_CODE = ?";
        try (Connection con = buildConn.openConn();
             PreparedStatement ps = con.prepareStatement(sql)) {
            ps.setInt(1, ctnCode);
            return ps.executeUpdate();
        } catch (SQLException e) { e.printStackTrace(); return 0; }
    }

    // 查 (全部)
    public List<Canton> listCanton() {
        String sql = "SELECT * FROM T_BL_CANTON_CODE";
        List<Canton> list = new ArrayList<>();
        try (Connection con = buildConn.openConn();
             PreparedStatement ps = con.prepareStatement(sql);
             ResultSet rs = ps.executeQuery()) {
            while (rs.next()) {
                Canton c = new Canton();
                c.setCtn_code(rs.getInt("CTN_CODE"));
                c.setCtn_name(rs.getString("CTN_NAME"));
                c.setGov_name(rs.getString("GOV_NAME"));
                c.setLand_dp_name(rs.getString("LAND_DP_NAME"));
                c.setParent_code(rs.getString("PARENT_CODE"));
                list.add(c);
            }
        } catch (SQLException e) { e.printStackTrace(); }
        return list;
    }
    // 改... 類似
}

4. 字符集過濾器 CharsetFilter (解決中文亂碼)

@WebFilter("/*")
public class CharsetFilter implements Filter {
    private String encoding = "UTF-8";
    @Override public void init(FilterConfig fc) { encoding = fc.getInitParameter("encoding"); }
    @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        req.setCharacterEncoding(encoding);
        res.setContentType("text/html;charset=" + encoding);
        chain.doFilter(req, res);
    }
    @Override public void destroy() {}
}

web.xml 配置 (若不使用 @WebFilter):

<filter><filter-name>CharsetFilter</filter-name><filter-class>com.example.filter.CharsetFilter</filter-class>
    <init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param>
</filter>
<filter-mapping><filter-name>CharsetFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

5. Servlet 控制器

  • CantonAddServlet:接收表單參數 → 構建 Canton → dao.addCanton() → 轉發列表頁。
  • CantonDelServlet:獲取 ctn_code → dao.delCanton() → 轉發列表頁。
  • CantonListServlet:dao.listCanton() → request.setAttribute("list", list) → 轉發 listCanton.jsp。

6. JSP 頁面關鍵片段

addCanton.jsp 表單 action="CantonAddServlet",輸入框 name="ctn_code" 等與 Servlet 參數對應。
listCanton.jsp 使用 <% List<Canton> list = (List)request.getAttribute("list"); %> 取數據,<%=ct.getCtn_name()%> 輸出,刪除鏈接 href="CantonDelServlet?ctn_code=<%=ct.getCtn_code()%>"。

三、 運行效果

列表頁截圖

四、 避坑指南與生產級升級

問題原因解決方案
頻繁創建/關閉 Connection每次 DAO 調用 new BuildConn().openConn()**引入連接池**:Druid / HikariCP,配置 DataSource,DAO 注入 DataSource 獲取連接。
SQL 注入風險拼接 SQL 字符串**全面使用 PreparedStatement** 佔位符 ?,參數綁定。
資源洩漏異常時 Connection/Statement/ResultSet 未關閉**try-with-resources (Java 7+)** 自動關閉,或 finally 手動關閉。
事務控制缺失多條 SQL 無原子性保證con.setAutoCommit(false) + commit()/rollback(),或 Spring @Transactional。
硬編碼配置URL/用戶/密碼寫死代碼**外部化配置**:properties/yaml + 環境變量,構建時注入。

五、 連接池遷移示例

// Maven 依賴
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId><version>5.0.1</version></dependency>

// Spring 配置 DataSource Bean
@Bean public DataSource dataSource() {
    HikariConfig cfg = new HikariConfig();
    cfg.setJdbcUrl("jdbc:mysql://localhost:3306/landdb");
    cfg.setUsername("user2"); cfg.setPassword("123456");
    cfg.setMaximumPoolSize(20); cfg.setMinimumIdle(5);
    return new HikariDataSource(cfg);
}

// DAO 改造
@Repository public class CantonDaoImp {
    @Autowired private DataSource dataSource;
    public Connection getConnection() throws SQLException { return dataSource.getConnection(); }
    // 其餘邏輯不變,自動受益於連接池
}

六、 總結

JDBC 雖屬底層 API,但理解其驅動加載、連接管理、預編譯語句、結果集遍歷、資源釋放、事務邊界等核心機制,是掌握 MyBatis、JPA、Spring Data 等上層框架原理、排查數據庫性能問題、設計高可用數據訪問層的基石。實際項目中**務必使用成熟連接池**,並配合事務管理框架,切勿手動管理裸連接。

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