Spring与JDBC:高效数据库操作的艺术引言

引言:JDBC在Spring生态中的重要性

在Java生态中,JDBC(Java Database Connectivity)是连接应用程序与数据库的核心技术。Spring框架通过其强大的JDBC支持,极大地简化了数据库操作,减少了样板代码,提高了开发效率。本文将带您探索JDBC技术的演进历程,并展示Spring如何优雅地解决传统JDBC的痛点。

一、JDBC技术的演进之路

1. 基础JDBC:原始连接方式

// JDBC.java - 最基础的JDBC操作
public class JDBC {
    public static void main(String[] args) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/bishe?serverTimezone=UTC",
                "root",
                "2020"
            );
            
            stmt = conn.createStatement();
            String sql = "SELECT id,`name`,studentID FROM student WHERE id=1";
            rs = stmt.executeQuery(sql);
            
            if (rs.next()) {
                Student student = new Student();
                student.setId(rs.getInt("id"));
                student.setName(rs.getString("name"));
                student.setStudentID(rs.getString("studentID"));
                System.out.println(student);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 繁琐的资源关闭...
                        try {
                if (rs != null) rs.close();
            } catch (Exception e) { e.printStackTrace(); }

            try {
                if (stmt != null) stmt.close();
            } catch (Exception e) { e.printStackTrace(); }

            try {
                if (conn != null) conn.close();
            } catch (Exception e) { e.printStackTrace(); }
        }
    }
}

痛点分析

  • 重复的样板代码(驱动加载、连接获取、资源关闭)

  • 硬编码的数据库配置

  • 异常处理冗长

  • 资源管理容易出错

2. JDBC工具类进化史

版本1.0:基础封装
package com.qcby.utils;

import java.sql.*;

public class JDBC02 {
    /**
     * 加载驱动的方法  static
     */
    public static void loadDrive(){
        try {
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 连接对象conn
     */
    public static Connection getConntion(){
        loadDrive();
        Connection connection = null;
        try {
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bishe", "root", "2020");
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }


    /**
     * 获取执行sql的对象  Statement
     */
    public static Statement creatstmt() throws SQLException {
        Connection conntion = getConntion();
        Statement statement = conntion.createStatement();
        return statement;
    }


    /**
     * 关闭资源的提取
     */
    public static  void close(ResultSet rs, Statement stmt, Connection conn){
        try {
            rs.close();
            stmt.close();
            conn.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

测试用例

@Test
    public void jdbc02() {//对原有的多次操作会重复的操作函数进行了封装使得编码变得简单
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        try {
            // 1. 获取数据库连接
            conn = JDBC02.getConntion();
            // 2. 创建Statement对象
            stmt = conn.createStatement();
            // 3. 执行查询语句(示例:查询student表)
            String sql = "SELECT id, name FROM  student WHERE id =1";
            rs = stmt.executeQuery(sql);
            // 4. 处理结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");

                System.out.println("ID: " + id
                        + ", Name: " + name);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 5. 关闭资源(使用工具类方法)
            JDBC02.close(rs, stmt, conn);
        }
    }

结果如图所示

版本2.0:配置文件分离
package com.qcby.utils;

import com.alibaba.druid.util.JdbcUtils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class JDBC03 {
    private static final String driverclass;
    private static final String url;
    private static final String username;
    private static final String password;

    static{
        // 加载属性文件
        Properties pro = new Properties();
        InputStream inputStream = JdbcUtils.class.getResourceAsStream("/db.properties");
        try {
            // 加载属性文件
            pro.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 给常量赋值
        driverclass = pro.getProperty("driverclass");
        url = pro.getProperty("url");
        username = pro.getProperty("username");
        password = pro.getProperty("password");
    }

    /**
     * 加载驱动
     */
    public static void loadDriver(){
        try {
            // 加载驱动类
            Class.forName(driverclass);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 加载完驱动,获取到连接,返回连接对象
     * @return
     */
    public static Connection getConnection(){
        // 加载驱动
        loadDriver();
        // 获取到连接对象,返回
        Connection conn = null;
        try {
            // 获取到连接
            conn = DriverManager.getConnection(url,username,password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭资源
     * @param conn
     * @param stmt
     * @param rs
     */
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭资源
     * @param conn
     * @param stmt
     */
    public static void close(Connection conn, Statement stmt){
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}
//db.properties配置文件
driverclass=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bishe?useSSL=false&serverTimezone=UTC
username=root
password=2020

测试用例

@Test
    public void jdbc03() {//使用配置文件将一些写死的数据传进去使得更加灵活
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;//结果集
        try {
            // 1. 获取数据库连接
            conn = JDBC03.getConnection();
            // 2. 创建预编译语句(示例:查询用户表)
            String sql = "SELECT id, name FROM student WHERE id = 1";  // 使用参数化查询
            pstmt = conn.prepareStatement(sql);
            // 4. 执行查询
            rs = pstmt.executeQuery();
            // 5. 处理结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");
                System.out.printf("ID: %d, Name: %s%n", id, name);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 6. 关闭资源
            JDBC03.close(conn, pstmt, rs);
        }
    }

测试结果

 版本3.0:连接池集成
package com.qcby.utils;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * JDBC的工具类 1.0版本
 * JDBC的工具类 2.0版本(智能一些),编写properties属性文件,程序就可以读取属性文件
 * JDBC的工具类 3.0版本,加入连接池对象
 */
public class JDBC04 {

    // 连接池对象
    private static DataSource DATA_SOURCE;

    static{
        // 加载属性文件
        Properties pro = new Properties();
        InputStream inputStream = JDBC04.class.getResourceAsStream("/lianjiechi.properties");
        try {
            // 加载属性文件
            pro.load(inputStream);
            // 创建连接池对象
            DATA_SOURCE = DruidDataSourceFactory.createDataSource(pro);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 从连接池中获取连接,返回。
     * @return
     */
    public static Connection getConnection(){
        Connection conn = null;
        try {
            conn = DATA_SOURCE.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭资源
     * @param conn
     * @param stmt
     * @param rs
     */
    public static void close(Connection conn, Statement stmt, ResultSet rs){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭资源
     * @param conn
     * @param stmt
     */
    public static void close(Connection conn, Statement stmt){
        if(stmt != null){
            try {
                stmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

}
//lianjiechi.properties连接池配置文件
# 基本配置
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/bishe?useSSL=false&serverTimezone=UTC
username=root
password=2020

# 连接池配置
initialSize=5
minIdle=5
maxActive=20
maxWait=60000
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
validationQuery=SELECT 1
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
poolPreparedStatements=true
maxPoolPreparedStatementPerConnectionSize=20
filters=stat,wall,log4j

测试用例

    @Test
    public void jdbc04() {
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;

        try {
            // 1. 从Druid连接池获取连接
            conn = JDBC04.getConnection();

            // 2. 创建预编译SQL语句(示例:查询student表)
            String sql = "SELECT id,`name` FROM student WHERE id = 1";
            pstmt = conn.prepareStatement(sql);


            // 4. 执行查询
            rs = pstmt.executeQuery();

            // 5. 处理结果集
            while (rs.next()) {
                int id = rs.getInt("id");
                String name = rs.getString("name");


                System.out.printf("学生信息 - ID: %d, 姓名: %s", id, name);
            }
        } catch (SQLException e) {
            System.err.println("数据库操作异常:");
            e.printStackTrace();
        } finally {
            // 6. 释放资源(注意:连接是返回到连接池,不是真正关闭)
            JDBC04.close(conn, pstmt, rs);
        }
    }

测试结果

 三种进化的好处

第一种

        基础封装:减少代码量

第二种:

       配置文件:使用更加灵活

第三中:

        线程池:更快,减少了重复的创建资源和释放资源的过程。

<think>首先,用户的问题是关于HTML语义化标签的作用和使用方法。我需要基于提供的引用内容来回答,确保回答真实可靠。 回顾引用内容: - 引用[1]:强调HTML语义化标签的重要性,提升可读性、可访问性、SEO效果。 - 引用[2]:解释语义化的定义,强调代码易于理解、维护、提升可访问性和SEO。 - 引用[3]:提到文本格式化标签如<h1>~<h6>, <p>, <strong>等。 - 引用[4]:给出使用示例,如<header>、<nav>、<article>等标签在新闻页面中的应用。 - 引用[5]:列出常见语义化标签及其用途,如<ul>、<ol>、<header>、<nav>、<main>、<article>、<section>、<aside>、<footer>。 用户的问题:理解HTML语义化标签及其在网页开发中的作用,具体是作用和使用方法。 回答结构: - 需要清晰、逐步解释。 - 使用中文回答。 - 在行内数学表达式中使用$...$格式(但这里可能不涉及数学,所以可能不需要)。 - 独立公式使用$$...$$格式(同样,可能不适用)。 - 确保LaTeX语法正确(但主要是文本,可能不需要)。 - 生成相关问题在末尾。 - 在回答中引用的段落末尾添加引用标识,如[^1]。 关键点: 1. **HTML语义化标签的作用**: - 提升可读性:使代码更易理解。 - 增强可访问性:帮助辅助技术如屏幕阅读器。 - 改善SEO:搜索引擎更好地索引内容。 - 便于维护:代码结构清晰。 2. **HTML语义化标签的使用方法**: - 根据内容和结构选择合适的标签。 - 示例:使用<header> for header, <nav> for navigation, <article> for main content, <footer> for footer. - 具体标签列表:参考引用[5],如<ul>、<ol>、<section>、<aside>等。 组织回答: - 先介绍什么是HTML语义化标签。 - 然后解释其作用。 - 接着说明使用方法,包括常见标签和示例。 - 最后生成相关问题。 添加引用: - 在相关句子末尾添加[^1], [^2]等。 生成相关问题: - 在末尾添加"相关问题"部分,基于主题。 最终回答结构: 1. 引言:简要介绍HTML语义化标签。 2. 作用:详细说明。 3. 使用方法:包括标签列表和代码示例。 4. 结论:总结重要性。 5. 相关问题:生成2-3个相关问题。 代码示例: - 使用引用[4]中的示例,如新闻页面。 - 格式:使用Markdown代码块。 确保回答真实可靠:基于引用内容。</think>### HTML语义化标签的作用与使用方法 HTML语义化标签是HTML5引入的核心特性,它通过使用具有明确含义的标签来描述网页内容的结构和含义,而非仅依赖视觉样式。这不仅提升了代码的可读性,还增强了网页的可访问性和搜索引擎优化(SEO)效果[^1]。下面我将逐步解释其作用和使用方法,帮助您全面理解这一关键概念。 #### 1. HTML语义化标签的作用 HTML语义化标签的主要作用体现在以下几个方面: - **提升可读性和可维护性**:语义化标签使代码更易于理解和修改,开发者能快速识别各部分功能,减少维护成本[^2]。例如,使用`<header>`标签代替通用的`<div>`,能清晰表示页面头部区域。 - **增强可访问性**:屏幕阅读器等辅助技术能更准确地解析内容,帮助残障用户访问网页。语义化标签提供结构化信息,如`<nav>`表示导航区域,确保辅助工具能正确识别[^1][^2]。 - **改善搜索引擎优化(SEO)**:搜索引擎优先索引语义化内容,标签如`<main>`和`<article>`能明确内容重要性,提升网页在搜索结果中的排名[^1][^5]。 - **优化用户体验**:语义化结构确保内容在不同设备上(如移动端)自适应显示,提高响应式设计的效率[^4]。 这些作用共同使网页更符合Web标准,提升整体质量[^2]。 #### 2. HTML语义化标签的使用方法 使用语义化标签时,需根据内容结构和含义选择合适的标签,避免滥用通用标签如`<div>`。以下是常见标签的使用方法和示例: - **基本标签列表与用途**: - `<header>`:定义页眉,通常包括网站标志或标题(例如:`<header><h1>网站标题</h1></header>`)[^5]。 - `<nav>`:表示导航链接群,仅用于重要导航区域(例如:`<nav><a href="#">首页</a><a href="#">新闻</a></nav>`)[^5]。 - `<main>`:标记页面主要内容,每个页面只使用一次(例如:`<main>文章内容...</main>`)[^5]。 - `<article>`:定义独立内容块,如新闻文章或博客(例如:`<article><h2>标题</h2><p>正文...</p></article>`)[^4][^5]。 - `<section>`:划分文档中的节或区段,如章节或页脚(例如:`<section><h3>子标题</h3><p>细节...</p></section>`)[^5]。 - `<aside>`:表示侧边栏或相关内容,如广告或友情链接(例如:`<aside><p>相关推荐...</p></aside>`)[^5]。 - `<footer>`:定义页脚,包含版权信息或联系信息(例如:`<footer><p>© 2023 公司名</p></footer>`)[^5]。 - 文本格式化标签:如`<h1>`~`<h6>`用于标题层级,`<p>`用于段落,`<strong>`表示重要文本(例如:`<p><strong>强调内容</strong></p>`)[^3]。 - **使用原则**: - **根据内容选择标签**:分析文档结构,确保标签语义匹配内容。例如,在新闻页面中: ```html <header> <h1>新闻头条</h1> <nav> <ul> <li><a href="#">国内新闻</a></li> <li><a href="#">国际新闻</a></li> </ul> </nav> </header> <main> <article> <h2>文章标题</h2> <p>正文内容...</p> </article> </main> <footer> <p>联系方式: [email protected]</p> </footer> ``` 此结构清晰区分了页眉、导航、主内容和页脚[^4]。 - **避免过度嵌套**:保持标签层级简单,例如`<section>`内可包含多个`<article>`,但不宜多层嵌套。 - **结合CSS样式**:语义化标签不影响视觉设计,可通过CSS定制样式(如`header { background-color: #f0f0f0; }`)[^3]。 - **最佳实践**: - 优先使用语义化标签代替非语义标签(如用`<nav>`替代`<div class="navigation">`)。 - 测试可访问性:使用工具如WAVE或浏览器开发者工具验证屏幕阅读器兼容性。 - 在动态内容中保持语义:例如,在JavaScript生成的元素中,也应用语义化标签。 通过合理使用语义化标签,您可以构建更高效、可维护的网页[^1][^2]。 #### 总结 HTML语义化标签是前端开发的基础,它通过结构化内容提升了网页的可读性、可访问性和SEO表现。掌握其作用和使用方法,不仅能优化代码质量,还能增强用户体验。在实际开发中,始终根据内容含义选择标签,并结合示例实践[^4][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值