第一期:[特殊字符] 深入理解MyBatis[特殊字符]从JDBC到MyBatis——持久层开发的转折点[特殊字符]
前言 🌟
在软件开发的过程中,持久层(或数据访问层)是与数据库进行交互的关键部分。早期,开发者通常使用 JDBC(Java Database Connectivity)来实现与数据库的连接与操作。虽然 JDBC 在一定程度上简化了数据库操作,但它仍然存在许多挑战和不便之处,比如 SQL 语句的硬编码、结果集的处理复杂度、以及代码的冗长和重复性等问题。📉
随着时间的推移,开发者们意识到,JDBC 无法完全满足高效、灵活、易维护的开发需求,尤其是在面对复杂的业务逻辑时。于是,MyBatis 作为一种解决方案应运而生,填补了 JDBC 的空白,极大地简化了数据库操作的复杂性。💡
MyBatis 不仅提供了强大的 SQL 映射功能,还能让开发者专注于业务逻辑,避免了大量的重复代码编写。与 JDBC 相比,它的优势在于支持动态 SQL、映射文件的配置、与 POJO(Plain Old Java Object)之间的映射等,使得持久层的开发更加灵活、高效且易于维护。⚙️
在这一篇文章中,我们将详细探讨从 JDBC 到 MyBatis 的过渡,并分析两者之间的差异与优劣。💬
从 JDBC 到 MyBatis —— 为什么是转折点?
-
JDBC 的痛点 💥
-
SQL 与 Java 代码耦合度高,难以维护。
-
操作繁琐,需要大量手动编写的代码(例如,连接管理、异常处理、结果集映射)。
-
难以进行灵活的动态 SQL 构建。
-
-
MyBatis 的优势 🏆
-
SQL 映射:通过 XML 或注解的方式,将 SQL 语句与 Java 方法进行映射,减少了代码冗余。
-
动态 SQL:MyBatis 提供了强大的动态 SQL 功能,能够根据不同条件动态生成 SQL 语句。
-
分离 SQL 与 Java:通过配置文件或者注解方式,可以轻松将 SQL 与 Java 代码进行解耦,便于管理和维护。
-
MyBatis 的引入使得持久层开发的工作更加专注于业务逻辑,而不是被琐碎的 SQL 语句和数据库交互所困扰。🌍
接下来的章节将带你深入了解如何使用 MyBatis 进行高效的持久层开发,帮助你从 JDBC 迈向更为现代和灵活的数据库操作方式。🚀
如果你对 MyBatis 感兴趣,那就继续跟随我们一起探索吧!📚
1. 背景与痛点分析 🔍
在开发过程中,持久层(数据访问层)是应用程序与数据库之间的重要桥梁。在传统的 JDBC 开发中,开发者需要手动编写大量的数据库连接、查询、更新等操作,这使得开发流程显得非常繁琐且容易出错。让我们来回顾一下 JDBC 开发流程,并分析其面临的痛点。💥
传统 JDBC 开发流程 📜
-
数据库连接:
-
每次操作数据库时,开发者需要手动创建数据库连接。
-
需要配置数据库的连接信息(URL、用户名、密码等),并确保连接成功。
-
-
执行 SQL 语句:
-
手动编写 SQL 查询语句(
SELECT
、INSERT
、UPDATE
、DELETE
),并在代码中将其硬编码。 -
使用
Statement
或PreparedStatement
对象执行 SQL 语句,并返回结果。
-
-
结果集处理:
-
使用
ResultSet
对象获取查询结果,手动处理数据的转换和映射。 -
如果查询结果较为复杂,可能需要多次遍历和处理。
-
-
资源管理:
-
开发者需要手动关闭数据库连接、
Statement
和ResultSet
对象,以避免资源泄漏。 -
需要特别小心在异常发生时正确释放资源,容易导致内存泄漏或数据库连接池过载。
-
-
异常处理:
-
需要对数据库操作进行大量的异常捕获和处理,通常会涉及 SQL 异常、连接超时等各种问题。
-
这些步骤看似简单,但实际上每一个步骤都需要额外的代码支持,且容易出现重复。💡
痛点分析 💥
-
繁琐的代码:每个数据库操作都需要手动编写大量的代码,这些代码不仅冗长,而且容易出错。尤其是连接的管理和结果集的处理,都需要开发者手动完成。
-
重复的代码:不同的操作(如增、删、改、查)虽然只是细节不同,但需要的代码非常相似,导致大量重复代码的存在。每个操作的 SQL 语句、数据库连接、关闭资源等步骤都需要重复编写。
-
资源管理复杂:开发者需要时刻关注连接、
Statement
、ResultSet
等资源的关闭和释放。由于操作数据库时常常会出现异常,处理这些资源时容易漏掉,从而导致数据库连接泄漏和性能问题。 -
SQL 和 Java 代码耦合:SQL 语句通常硬编码在 Java 代码中,导致 SQL 的修改需要重新编译 Java 代码。而且,复杂的 SQL 语句与 Java 代码的混合,使得代码难以阅读、维护和扩展。
-
难以维护:随着项目的增长,JDBC 代码逐渐变得冗长且复杂。如果业务需求发生变化,需要修改 SQL 或数据库操作时,可能需要修改多个地方,容易引入错误。
引入持久层概念及 DAO 设计思想 🏗️
为了解决传统 JDBC 开发中的这些痛点,持久层(Persistence Layer) 的概念应运而生。持久层的核心思想是将与数据库相关的操作封装成独立的模块,提供对数据库的统一接口,从而让业务逻辑与数据库操作分离。📊
DAO(Data Access Object)设计模式 🧩
DAO 设计模式是一种常见的解决方案,它通过提供数据访问对象,将数据库操作与业务逻辑隔离开来,达到以下目标:
-
封装数据库操作:将所有数据库的增删改查操作集中在一个 DAO 类中,业务逻辑只需要与 DAO 对象交互,不需要关心底层的数据库细节。
-
统一接口:DAO 提供统一的接口,方便维护和扩展。业务逻辑与数据库操作之间的耦合度降低,便于修改数据库实现(如更换数据库系统)。
-
简化代码结构:DAO 模式将数据库操作代码封装,避免了大量重复的数据库访问代码,提升了代码的可读性和可维护性。
-
易于扩展和维护:随着需求的增加或数据库结构的变化,修改数据库相关代码时,只需更新 DAO 层,而不必改变业务逻辑代码。💪
为什么需要更高效的解决方案?
传统的 JDBC 开发虽然可以完成数据库操作,但它无法满足以下需求:
-
开发效率:手动管理数据库连接、资源释放和异常处理的繁琐操作,大大降低了开发效率。
-
代码可维护性:冗长、重复且耦合的代码难以维护和扩展。
-
灵活性与可扩展性:当业务需求发生变化时,修改 SQL 或数据库操作变得困难且容易出错。
因此,持久层 和 DAO 设计模式为解决这些问题提供了更高效的解决方案。通过引入 MyBatis 或类似框架,我们可以进一步简化数据库操作,避免重复代码,提高开发效率和代码的可维护性。🚀
2. 什么是 MyBatis 💡
MyBatis 是一个用于简化数据库操作的 持久层框架,它使得 Java 程序能够更加高效地与数据库进行交互。MyBatis 通过 SQL 映射 的方式,将 SQL 语句与 Java 方法进行关联,从而避免了传统 JDBC 中繁琐的数据库操作。MyBatis 的设计理念是提供更大的灵活性,允许开发者自由编写 SQL 语句的同时,又能享受框架带来的便利。🚀
MyBatis 的发展历程与框架定位 🛠️
1. 初始版本(iBatis) 📅
-
iBatis 是 MyBatis 的前身,它最早由 Clinton Begin 于 2002 年创建,并作为一个开源项目发布。iBatis 的初衷是简化数据库交互,尤其是帮助开发者避免过多的 JDBC 代码。
-
iBatis 提供了一个映射框架,使得开发者可以通过 XML 配置文件来将 Java 对象和 SQL 语句进行映射。这种方式使得开发者可以将 SQL 语句与 Java 代码分离,从而提高了代码的可维护性。
2. MyBatis 的诞生 🌱
-
在 2010 年,iBatis 进行了一个重要的版本更新,之后该项目更名为 MyBatis。这个改名不仅代表了技术的进步,还为 MyBatis 带来了更多的功能增强和社区支持。🔥
-
MyBatis 的目标是进一步简化数据库操作,并且更加关注于 SQL 映射 和 Java 对象映射,从而让开发者能够更加灵活地控制数据库操作,同时减少数据库访问代码的复杂性。
3. 框架定位 🎯
-
轻量级框架:MyBatis 是一个轻量级框架,能够灵活地与任何类型的 Java 应用程序一起使用。它不仅支持传统的单机应用,也能与分布式系统、微服务架构等搭配使用。
-
SQL 映射框架:MyBatis 的最大特色就是 SQL 映射机制,它允许开发者自定义 SQL 语句,并将其与 Java 方法进行绑定。与 Hibernate 等 ORM 框架相比,MyBatis 更加直接地让开发者控制 SQL,从而提供了更大的灵活性。
-
解耦 SQL 和 Java 代码:MyBatis 通过 XML 配置文件或注解的方式,将 SQL 语句从 Java 代码中分离开来,使得 SQL 可以独立进行管理和优化。这样既有利于 SQL 语句的重用,又提升了代码的可维护性。
与传统 JDBC 相比,MyBatis 如何通过映射机制简化数据库操作 💥
1. 避免繁琐的 JDBC 代码 ⚙️
在传统的 JDBC 开发中,开发者需要手动管理数据库连接、执行 SQL 语句、处理结果集以及关闭各种资源。这些步骤都需要大量的代码,并且容易出错。
而 MyBatis 通过 SQL 映射机制,简化了这些步骤。开发者只需定义映射文件或注解来关联 SQL 语句和 Java 方法,框架会自动处理数据库连接、资源管理等细节。📉
传统 JDBC 示例:
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "root", "password");
PreparedStatement statement = connection.prepareStatement("SELECT * FROM users WHERE id = ?");
statement.setInt(1, userId);
ResultSet resultSet = statement.executeQuery();while (resultSet.next()) {User user = new User();user.setId(resultSet.getInt("id"));user.setName(resultSet.getString("name"));// 处理其他字段
}resultSet.close();
statement.close();
connection.close();
MyBatis 示例:
@Select("SELECT * FROM users WHERE id = #{userId}")
User getUserById(int userId);
可以看到,MyBatis 通过注解或者映射文件,将 SQL 语句直接与 Java 方法绑定,省去了手动写 SQL 连接、资源管理和结果集处理的麻烦。🎉
2. SQL 与 Java 代码分离 🛠️
在传统的 JDBC 中,SQL 语句是嵌入在 Java 代码中的,这样的耦合使得 SQL 语句的修改需要重新编译 Java 代码。而在 MyBatis 中,SQL 语句和 Java 代码是分离的,可以放在独立的 XML 配置文件中。这样,SQL 的修改无需重新编译 Java 代码,大大提高了灵活性和可维护性。📂
MyBatis 配置示例(XML):
<mapper namespace="com.example.UserMapper"><select id="getUserById" resultType="User">SELECT * FROM users WHERE id = #{userId}</select>
</mapper>
这样,SQL 语句可以与 Java 代码完全分离,便于后期的维护和优化。🎯
3. 动态 SQL 支持 🔄
MyBatis 通过 <if>
, <choose>
, <foreach>
等标签,支持灵活的动态 SQL。开发者可以根据条件动态构建 SQL 语句,而不需要手动拼接字符串,避免了 SQL 注入和冗余代码的问题。💡
动态 SQL 示例:
<select id="findUsers" resultType="User">SELECT * FROM users<where><if test="name != null">AND name = #{name}</if><if test="age != null">AND age = #{age}</if></where>
</select>
通过动态 SQL,开发者可以更加灵活地处理复杂的查询需求,同时提高代码的可读性。👀
4. 简化的映射机制 🗺️
在 JDBC 中,开发者需要手动将查询结果从 ResultSet
转换为 Java 对象,这通常涉及大量的代码编写。而 MyBatis 提供了 映射器 功能,可以将查询结果自动映射到 Java 对象中,从而大大简化了对象的转换过程。
MyBatis 映射示例:
@Select("SELECT * FROM users WHERE id = #{userId}")
@ResultMap("userResultMap")
User getUserById(int userId);
MyBatis 会自动将查询结果转换为对应的 User
对象,无需手动处理每个字段的映射,极大地提高了开发效率和代码的简洁性。🎉
总结 📝
与传统的 JDBC 开发相比,MyBatis 通过 SQL 映射机制简化了数据库操作,避免了繁琐的 JDBC 代码,提升了开发效率和代码可维护性。它通过提供灵活的映射方式、动态 SQL 支持以及 SQL 与 Java 代码的分离,成为了数据库交互中一个强大而灵活的解决方案。🌟
通过 MyBatis,开发者可以更加专注于业务逻辑,而不必为繁琐的数据库操作所困扰。
3. ⚙️ MyBatis 环境准备与配置 🛠️
在这一部分,我们将展示如何在 Spring Boot 项目中集成 MyBatis 并进行基本的配置。同时,我们将以一个简单的示例(如软书架和用户表)来说明如何使用 MyBatis 进行数据操作。💡
1. 创建 Spring Boot 工程,添加 MyBatis 和 MySQL 依赖 🚀
首先,你需要创建一个 Spring Boot 项目。如果你使用的是 Spring Initializr,可以选择以下依赖项:
-
Spring Web
-
Spring Data JPA
-
MyBatis Framework
-
MySQL Driver
如果你是通过手动配置的方式创建项目,接下来的步骤是将 MyBatis 和 MySQL 相关的依赖添加到 pom.xml
(Maven)或 build.gradle
(Gradle)中。
Maven 配置:
在 pom.xml
中添加如下依赖:
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Spring Boot Starter for MySQL --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!-- MyBatis Spring Boot Starter --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><!-- MySQL JDBC Driver --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- Spring Boot Starter Logging (Optional, for logging configuration) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency>
</dependencies>
Gradle 配置:
如果你使用 Gradle,则在 build.gradle
文件中添加如下依赖:
dependencies {// Spring Boot Starter Webimplementation 'org.springframework.boot:spring-boot-starter-web'// Spring Boot Starter for MySQLimplementation 'org.springframework.boot:spring-boot-starter-data-jpa'// MyBatis Spring Boot Starterimplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'// MySQL JDBC Driverimplementation 'mysql:mysql-connector-java'// Spring Boot Starter Logging (Optional)implementation 'org.springframework.boot:spring-boot-starter-logging'
}
2. 数据库连接配置及 MyBatis 日志配置 🔧
在 Spring Boot 中,我们通常在 application.yml
或 application.properties
文件中进行数据库连接和日志配置。
配置 application.yml
文件 📂
spring:datasource:url: jdbc:mysql://localhost:3306/bookstore?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTCusername: rootpassword: root123driver-class-name: com.mysql.cj.jdbc.Drivermybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.example.demo.modelconfiguration:map-underscore-to-camel-case: truelogging:level:org.mybatis: DEBUG # 启用 MyBatis SQL 日志org.springframework.jdbc.core: DEBUG # 启用 Spring JDBC 日志
配置 application.properties
文件 📂
如果你使用的是 application.properties
文件,可以按以下方式配置:
spring.datasource.url=jdbc:mysql://localhost:3306/bookstore?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root123
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Drivermybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.demo.model
mybatis.configuration.map-underscore-to-camel-case=truelogging.level.org.mybatis=DEBUG
logging.level.org.springframework.jdbc.core=DEBUG
在配置中:
-
spring.datasource
用于设置数据库连接的 URL、用户名、密码等信息。 -
mybatis.mapper-locations
配置了 MyBatis 映射文件的位置,这里假设映射文件存放在classpath:mapper
目录下。 -
mybatis.type-aliases-package
配置了实体类所在的包路径。 -
mybatis.configuration.map-underscore-to-camel-case
设置是否支持数据库字段和实体类属性之间的下划线和驼峰命名法的自动转换。 -
logging.level.org.mybatis
和logging.level.org.springframework.jdbc.core
用于启用 SQL 日志,帮助开发者调试 SQL 查询。
3. 构建简单数据表(如软书架和用户表)并分析实体类与数据库字段如何映射 📊
在数据库中,我们构建一个简单的用户表(users
)以及软书架表(bookshelf
)。这将帮助我们了解 MyBatis 如何通过映射机制将数据库字段与实体类的属性进行映射。
SQL 表结构 🗄️
-
用户表(
users
):
CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(50) NOT NULL,password VARCHAR(255) NOT NULL,email VARCHAR(100),created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-
软书架表(
bookshelf
):
CREATE TABLE bookshelf (id INT AUTO_INCREMENT PRIMARY KEY,user_id INT,book_title VARCHAR(255) NOT NULL,book_author VARCHAR(255),added_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY (user_id) REFERENCES users(id)
);
实体类与数据库字段的映射 🧑💻
接下来,我们来创建两个实体类:User
和 Bookshelf
。
-
User 实体类:
package com.example.demo.model;import java.time.LocalDateTime;public class User {private Integer id;private String username;private String password;private String email;private LocalDateTime createdAt;// Getters and Setters
}
-
Bookshelf 实体类:
package com.example.demo.model;import java.time.LocalDateTime;public class Bookshelf {private Integer id;private Integer userId;private String bookTitle;private String bookAuthor;private LocalDateTime addedDate;// Getters and Setters
}
分析映射 🔍
-
字段映射:MyBatis 会根据
@Param
注解或 XML 配置文件中定义的#{}
占位符,自动将查询结果中的数据库字段映射到实体类的属性。 -
驼峰命名法与下划线转换:如果我们启用了
map-underscore-to-camel-case
配置项,MyBatis 会自动将数据库中的created_at
映射为 Java 实体类中的createdAt
,这避免了手动转换字段名的麻烦。
MyBatis 映射文件(XML)示例 📝
对于 User
和 Bookshelf
表,我们可以定义如下的 MyBatis 映射文件:
<mapper namespace="com.example.demo.mapper.UserMapper"><resultMap id="BaseResultMap" type="User"><id column="id" property="id"/><result column="username" property="username"/><result column="password" property="password"/><result column="email" property="email"/><result column="created_at" property="createdAt"/></resultMap><select id="selectUserById" resultMap="BaseResultMap">SELECT * FROM users WHERE id = #{id}</select>
</mapper>
DAO 接口 🧑💻
在 Spring Boot 中,我们通常会为每个实体创建一个对应的 DAO 接口来执行数据库操作:
package com.example.demo.mapper;import com.example.demo.model.User;
import org.apache.ibatis.annotations.Select;public interface UserMapper {@Select("SELECT * FROM users WHERE id = #{id}")User selectUserById(int id);
}
总结 📝
通过本节的学习,我们成功地在 Spring Boot 中配置了 MyBatis 并与 MySQL 数据库连接。我们创建了简单的 User 和 Bookshelf 表,并展示了如何通过 MyBatis 映射机制将数据库字段与 Java 实体类属性进行自动映射。这一过程简化了传统 JDBC 开发中的繁琐操作,极大提高了开发效率和代码可维护性。🚀
4. 🔍 JDBC 与 MyBatis 编程模型对比代码示例
在这部分,我们将通过代码示例对比传统的 JDBC 编程和 MyBatis 编程模型。我们将使用一个简单的查询操作(查询用户信息)来展示两者的区别。
1. JDBC 编程模型 ⚙️
在传统的 JDBC 中,开发者需要手动处理数据库连接、执行 SQL 语句、映射查询结果以及释放资源。代码通常如下:
import java.sql.*;public class UserDao {public User getUserById(int userId) {// JDBC 连接、查询用户信息String url = "jdbc:mysql://localhost:3306/mydb";String username = "root";String password = "password";String query = "SELECT * FROM users WHERE id = ?";try (Connection conn = DriverManager.getConnection(url, username, password);PreparedStatement pstmt = conn.prepareStatement(query)) {pstmt.setInt(1, userId);ResultSet rs = pstmt.executeQuery();if (rs.next()) {User user = new User();user.setId(rs.getInt("id"));user.setUsername(rs.getString("username"));user.setPassword(rs.getString("password"));return user;}} catch (SQLException e) {e.printStackTrace();}return null;}
}
在 JDBC 中,开发者需要显式地管理数据库连接、执行 SQL 语句、处理 ResultSet
和手动释放资源(如连接、语句和结果集)。这使得代码变得冗长且容易出错。
2. MyBatis 编程模型 🔧
与 JDBC 相比,MyBatis 通过映射机制简化了数据库操作,开发者不需要手动处理 SQL 语句的执行和结果集的映射,代码更加简洁。示例如下:
import org.apache.ibatis.annotations.Select;public interface UserMapper {@Select("SELECT * FROM users WHERE id = #{userId}")User getUserById(int userId);
}
在 MyBatis 中,通过简单的注解或 XML 配置,SQL 语句与 Java 方法进行绑定,MyBatis 会自动执行 SQL、映射结果集并返回 Java 对象。开发者不需要关心连接的创建和关闭,也不需要处理 SQL 执行的细节。
JDBC 与 MyBatis 对比总结 📝
特性 | JDBC | MyBatis |
---|---|---|
SQL 书写方式 | 手动书写 SQL 语句 | SQL 语句可以通过注解或 XML 配置书写 |
数据库连接管理 | 需要手动创建和关闭数据库连接 | 自动管理数据库连接 |
结果映射 | 手动处理 ResultSet 到 Java 对象的映射 | 自动映射 ResultSet 到 Java 对象 |
资源释放 | 需要手动关闭 Connection 、Statement 、ResultSet | 自动关闭连接和资源,避免了资源泄漏 |
灵活性 | 灵活,但代码冗长且容易出错 | 灵活,但封装了很多细节,减少了出错的机会 |
代码简洁性 | 较冗长,需要多行代码来处理 SQL 和结果映射 | 简洁,通过注解或 XML 配置实现 SQL 与 Java 方法的绑定 |
层次结构图(Controller、Service、DAO)及资源释放流程
在 Spring Boot 项目中,常见的分层结构包括 Controller 层、Service 层和 DAO 层。下面是各层之间的关系以及资源释放的流程。
层次结构图(Controller、Service、DAO)
+--------------------+
| Controller | ---> 接受 HTTP 请求,调用 Service 层方法
+--------------------+|v
+--------------------+
| Service | ---> 业务逻辑层,调用 DAO 层进行数据操作
+--------------------+|v
+--------------------+
| DAO (Data Access)| ---> 直接与数据库进行交互,执行 SQL 查询
+--------------------+
资源释放流程图
在 JDBC 编程模型中,资源释放(如数据库连接)是开发者需要手动管理的。与之不同,MyBatis 会自动处理资源的关闭。
-
JDBC 资源释放流程:
+---------------------------+
| 开始数据库操作 |
+---------------------------+|v
+---------------------------+
| 1. 获取数据库连接 | ---> 连接可能失败,异常处理
+---------------------------+|v
+---------------------------+
| 2. 执行 SQL 语句 |
+---------------------------+|v
+---------------------------+
| 3. 处理 ResultSet | ---> 映射为 Java 对象
+---------------------------+|v
+---------------------------+
| 4. 关闭 ResultSet | ---> 释放 ResultSet 资源
+---------------------------+|v
+---------------------------+
| 5. 关闭 PreparedStatement|
+---------------------------+|v
+---------------------------+
| 6. 关闭数据库连接 |
+---------------------------+
-
MyBatis 资源释放流程:
+---------------------------+
| 开始数据库操作 |
+---------------------------+|v
+---------------------------+
| MyBatis 自动管理连接 | ---> 自动管理连接池,连接被自动获取
+---------------------------+|v
+---------------------------+
| 执行 SQL 语句 | ---> SQL 由 MyBatis 执行
+---------------------------+|v
+---------------------------+
| MyBatis 自动映射结果 | ---> 将 SQL 查询结果映射为 Java 对象
+---------------------------+|v
+---------------------------+
| MyBatis 自动关闭资源 | ---> 自动关闭 `Connection` 和 `Statement`
+---------------------------+
总结 📝
-
JDBC 需要开发者手动管理数据库连接、执行 SQL 语句以及释放资源,这导致代码较为冗长且容易出错。
-
MyBatis 提供了 SQL 映射机制,使得 SQL 语句与 Java 方法绑定,自动管理数据库连接和资源,减少了重复的代码和资源管理工作,极大地提高了开发效率。
在 Spring Boot 项目中,通常采用 Controller 层、Service 层和 DAO 层的分层架构,帮助开发者组织和管理不同的业务逻辑及数据库操作。
结语 🎉
在软件开发的历程中,持久层的演进不仅代表了技术的进步,也反映了开发者对高效、灵活和可维护代码的追求。从 JDBC 到 MyBatis 的过渡,无疑是持久层开发中的一个重要转折点。💡
通过这篇文章,我们回顾了 JDBC 和 MyBatis 各自的特点与优劣,并深入探讨了 MyBatis 在简化数据库操作、提升开发效率和增强代码可维护性方面的巨大优势。📈
尽管 JDBC 仍然在一些特殊场景下有其存在的价值,但在现代的开发环境中,MyBatis 提供了更为灵活、可扩展且易于维护的解决方案。它不仅让数据库操作变得更简单,还能够与现代开发架构无缝融合,为开发者提供更多的自由度和控制力。⚙️
随着技术的不断发展,持久层开发也在持续变化,新的框架和工具不断涌现,但 MyBatis 作为一个成熟且强大的框架,在很多场景中仍然发挥着重要作用。🚀
希望通过本篇文章的介绍,你对 MyBatis 和持久层开发有了更深的理解,并能将其应用于你的项目中,提高开发效率,减少重复代码。🎯
在未来的项目中,使用 MyBatis 将让你更专注于业务逻辑和创新,而无需为数据库交互的细节所困扰。📚
感谢你跟随我们一起探索这个技术领域的转折点,愿你的编程之路更加顺畅!💻🚀
相关文章:
第一期:[特殊字符] 深入理解MyBatis[特殊字符]从JDBC到MyBatis——持久层开发的转折点[特殊字符]
前言 🌟 在软件开发的过程中,持久层(或数据访问层)是与数据库进行交互的关键部分。早期,开发者通常使用 JDBC(Java Database Connectivity)来实现与数据库的连接与操作。虽然 JDBC 在一定程度上…...
指针的进阶2
六、函数指针数组 字符指针数组 - 存放字符指针的数组 char* arr[10] 整型指针数组 - 存放整型指针的数组 int* arr[10] 函数指针数组 - 存放函数指针的数组 void my_strlen() {} int main() {//指针数组char* ch[5];int arr[10] {0};//pa是是数组指针int (*pa)[10] &…...
Java学习——day28(Java并发工具类与线程池)
文章目录 1. 并发工具类简介1.1 ExecutorService1.2 Callable 和 Future1.3 Executors 工具类1.4 线程池优势 2. 实践:线程池执行任务并收集结果示例2.1 示例代码 3. 代码详解3.1 线程池的创建3.2 定义任务列表3.3 提交任务并收集 Future3.4 获取任务执行结果3.5 关…...
2021第十二届蓝桥杯大赛软件赛省赛C/C++ 大学 B 组
记录刷题的过程、感悟、题解。 希望能帮到,那些与我一同前行的,来自远方的朋友😉 大纲: 1、空间-(题解)-字节单位转换 2、卡片-(题解)-可以不用当组合来写,思维题 3、直…...
【数据结构】之二叉树
二叉树是我们在数据结构中学到的第一个非线性结构,是后续学习更为复杂的树、图结构的基础。本文整理了二叉树的概念定义、基本操作、遍历算法、伪代码与代码实现以及实例说明,方便大家随时查找对应。 一、定义与基本术语 二叉树是一种树形结构…...
电感、互感器、变压器和磁珠综合对比——《器件手册--电感/线圈/变压器/磁珠篇》
三、电感/线圈/变压器/磁珠 名称 定义 特点...
CLIP中的Zero-Shot Learning原理
CLIP(Contrastive Language-Image Pretraining)是一种由OpenAI提出的多模态模型,它通过对比学习的方式同时学习图像和文本的表示,并且能在多种任务中进行零样本学习(Zero-Shot Learning)。CLIP模型的核心创…...
基于 Redis 实现一套动态配置中心 DCC 服务与反射基础知识讲解
目录 动态配置中心核心价值 轻量级 Redis 方案与 ZooKeeper 的对比分析 为什么选择自定义 Redis 方案? 1. 技术决策背景 一、活动降级拦截 1. 定义与作用 2. 实现原理 二、活动切量拦截 1. 定义与作用 2. 实现原理 三、两者的核心区别 四、实际应用案例 1. 电商大促…...
vue 前端遇到问题 样式不展示
vue 前端遇到问题 样式不展示 先看接口返回有数据没 如果有数据看下 是不是 输入赋值给其他 字段 没有赋值上导致报错 所以页面没展示数据...
基于 Spring Boot + Vue 的 [业务场景] 管理系统设计与实现
技术范围:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…...
2025蓝桥杯JavaB组
说明 博主自己水平有限,而且答案也不一定对,下面代码和思路仅作分享。我只把我考场上做了的写出来了,有什么问题欢迎评论区交流。 A:逃离高塔 思路: 由于有了去年的经验,所以一上来我就是找规律…...
HDF5文件格式:数据类型与读写功能详解
HDF5文件格式:数据类型与读写功能详解 HDF5简介 HDF5(Hierarchical Data Format version 5)是一种用于存储和管理大量科学数据的文件格式和库。它由美国国家高级计算应用中心(NCSA)开发,具有以下特点&…...
探索 Python 的 functools 模块:缓存、属性缓存与 LRU 缓存
李升伟 编译 Python 的 functools 模块是函数式编程爱好者的宝库,提供了许多工具来提升代码的效率和优雅性。本文将深入探讨三个强大的函数——cache、cached_property 和 lru_cache,它们通过存储昂贵计算的结果来优化性能。无论是加速递归算法还是简化…...
缓存与数据库一致性:从问题到解决方案全解析
一、⼀致性问题的由来:为什么会不一致? 我们先从现实例子出发,来看为什么会出现一致性问题: 📦 场景举例:电商下单业务 用户提交订单 → 服务写入数据库订单表;同时更新缓存(比如用…...
【android bluetooth 框架分析 02】【Module详解 2】【gd_shim_module 模块介绍】
1. 背景 上一章节 我们介绍了 module_t 的 大体框架 ,本节内容我们就选择 我们的 gd_shim_module 模块为例子,具体剖析一下,它里面的逻辑。 static const char GD_SHIM_MODULE[] "gd_shim_module";// system/main/shim/shim.cc …...
dbt:新一代数据转换工具
dbt(Data Build Tool)一款专为数据分析和工程师设计的开源工具,专注于 ETL/ELT 流程的数据转换(Transform)环节,帮助用户以高效、可维护的方式将原始数据转换为适合分析的数据模型。 用户只需要编写查询&am…...
Linux-内核驱动-makemenu,make modules,make uImage,杂项
动态生成设备节点设备号...
linux 内存踩踏导致的空指针问题分析纪要
1,查看日志信息打印 我们看到日志发现发包的skb模块有NULL pointer情况,我们看代码分析skb指针不可能出现是空指针,这个时候我们怀疑可能是出现了踩内存导致的空指针情况,所以我们首先需要找到系统PANIC的条件,也就是…...
【C++】 —— 笔试刷题day_14
一、乒乓球筐 题目解析 题目输入两个字符串A和B,分别代表A和B中的乒乓球,不同的大写字母就表示不同的乒乓球; 如果判断B中的所有乒乓球在A中都有,且A中每种乒乓球的数量大于等于B中的。(简单来说就是B是A的子集&#…...
在WPS中通过JavaScript宏(JSA)调用DeepSeek官方API自动识别标题级别和目录
我们希望通过AI,能够自动识别像“一”、“(一)”、“1”、“(1)” 这类常见标题序号。做一个规则,如果存在“一”时,则“一”、“(一)”、“1”分别识别为H1、H2、H3&…...
修复 WPS 编译错误:缺少:Sub或Function 且出现两个MathType加载项
问题首次出现于2025.4.12。 同时使用了Word和WPS,在里面都使用了MathType,在Microsoft的Word中,加载项能正常加载且显示,这也是我们要的效果。 而在WPS中,却出现了两个MathType,且在启动时会弹窗报错&…...
HTTP协议
目录 1 Fiddler工具 2 HTTP协议 2.1 HTTP请求和响应格式 2.2 URL 2.3 方法method 2.3.1 GET 2.3.2 POST 2.4 请求报头Header 2.5 请求正文body 2.6 http响应状态码 2.7 响应报头header HTTP协议是应用层的协议,基于传输层的TCP协议来传输,数据…...
拓扑排序 —— 2. 力扣刷题207. 课程表
题目链接:https://leetcode.cn/problems/course-schedule/description/ 题目难度:中等 相关标签:拓扑排序 / 广度优先搜搜 BFS / 深度优先搜索 DFS 2.1 问题与分析 2.1.1 原题截图 2.1.2 题目分析 首先,理解题目后必须马上意识到…...
寻找峰值 --- 二分查找
目录 一:题目 二:算法原理 三:代码实现 一:题目 题目链接:162. 寻找峰值 - 力扣(LeetCode) 二:算法原理 三:代码实现 class Solution { public:int findPeakElemen…...
SAP系统客户可回收包材库存管理
问题:客户可回收包材库存管理 现象:回收瓶无库存管理,在库数量以及在客户的库存数量没有统计,管理混乱。 解决方法: 客户可回收包装材料在SAP有标准的解决方案,在集团尚未启用该业务,首先…...
C++标识符:检查是否和保留字冲突
1. 基础知识 最基本的要求: 字母、数字、下划线组成, 并且不能是数字开头。 禁忌1: C 关键字不能用做标识符。 它们是: alignas alignof asm auto bool break case catch char char16_t char32_t class const constexpr const_…...
【Java多线程】告别线程混乱!深度解析Java多线程4大实现方式(附实战案例)
一、继承Thread类 实现步骤: 1.继承Thread类 2.重写run()方法 3.创建线程对象并调用start()方法 示例: class MyThread extends Thread {Overridepublic void run() {for (int i 0; i < 5; i) {System.out.println(Thread.currentThread().getNam…...
Linux安装yum和python
一、安装yum(CentOS) 查看yum版本 yum --version 如果未安装,执行以下部分: 1. 确保你的系统中已经安装了epel仓库,如果没有安装可以通过以下命令安装: sudo yum install epel-release 2.yum安装 – CentOS/RHEL系统&#…...
【数据结构】HashMap源码 —— 简单介绍
HashMap源码介绍 下面并非完整的源码,主要简单了解其流程。 1. 基本成员变量 哈希桶/开散列,链地址法/开链法是由:数组 链表(单链表) 红黑树(当数组长度>64 && 链表长度>8以后,链表变成红黑树…...
149页研读——华为基于IPD全过程研发质量管理【附全文阅读】
本文介绍了IPD(集成产品开发)的全过程研发质量管理,强调了以客户需求为导向,通过跨部门协同、资源整合、快速响应等方式提高研发效率和成功率。文章详细阐述了IPD研发管理体系的精要,包括其核心思想、优势、框架以及核心理念。 其中,跨领域平台与技术研发、端到端流程与项…...
深入理解 v-for 指令及其使用方法
在 Vue.js 中,v-for 是用于渲染列表的核心指令,它允许你通过循环渲染数据源中的每一项。通过 v-for,你可以轻松地将数组、对象或其他可迭代的数据渲染成 HTML 元素。本文将详细介绍 v-for 的基本用法、常见的应用场景、最佳实践及性能优化&am…...
swift菜鸟教程24-25(可选链,自动引用计数)
一个朴实无华的目录 今日学习内容:1.Swift 可选链1.1定义1.2通过可选链调用方法1.3使用可选链调用下标脚本1.4通过可选链接调用来访问下标1.4访问可选类型的下标 2.Swift 自动引用计数(ARC)2.1实例之间的循环强引用会造成内存泄露2.2弱引用&a…...
使用 Visual Studio 2022 (VS2022) 编译 FreeCAD 1.0.0 的详细教程
一、环境准备 官方教程:在 Windows 上编译 - FreeCAD Documentation Windows 10/11(推荐) git vs2022 cmake 3.26.4 Doxygen1.12 二、获取源码与依赖 版本关系 打开Git Bash或CMD,执行以下命令 git clone --recurse-sub…...
机械臂只有位置信息是否可以进行手眼标定?
平常我在做手眼标定时,一般都是通过OpenCV的cv::calibrateHandEye函数进行求解,需要输入多组不同的机械臂位姿。今天遇到了一款舵机机器人,只能获取位置,得不到姿态信息,想着那就把姿态都设为0,结果求不出来…...
Unity入门
文章目录 Unity脚本基础大基础生命周期函数Inspector窗口显示常用特性辅助特性 MnonBehaviour基类成员变量成员方法 组件GameObject成员变量gameObject静态方法成员方法 组件Time静态成员变量 组件TransformVector3结构体基础基本概念常用向量表示常用方法 位置与位移位置posit…...
《汽车制造技术基础》第一次作业
作业内容 查阅相关资料,谈谈对汽车制造技术的发展的理解。 可以是关于汽车的先进制造技术 或 汽车先进制造技术 与 制造理念的发展趋势 或 汽车先进制造技术对环境与可持续发展的影响等。 以下从技术突破、制造理念转型及环境影响三个维度展开对汽车制造技…...
烟花爆竹储存作业安全要求
烟花爆竹储存作业证是从事相关作业的法定凭证,旨在确保操作人员具备专业知识和安全技能,防止因违规操作引发火灾、爆炸等事故。根据《烟花爆竹安全管理条例》及相关法规,未取得作业证的人员不得从事烟花爆竹储存、搬运、管理等作业。 仓库选址…...
Flask+Plotly结合动态加载图形页面实践
1. DeepSeek帮我实践 1.1. 我的提问既设计方案 原有如下主页:dashboard.html,现增加“预测模型学习”,对感知机神经网络描述如下: 1、输入与输出为固定值,例如输入层215,输出层48; 2、模型为回归神经网络; 3、中层是可动态调整的,例如定义如下:第二层,200,第三层…...
leetcode每日一题:统计好整数的数目
题目 给你两个 正 整数 n 和 k 。 如果一个整数 x 满足以下条件,那么它被称为 k 回文 整数 。 x 是一个 回文整数 。 x 能被 k 整除。 如果一个整数的数位重新排列后能得到一个 k 回文整数 ,那么我们称这个整数为 好 整数。比方说,k 2 …...
《2025蓝桥杯C++B组:D:产值调整》
**作者的个人gitee** 作者的算法讲解主页▶️ 每日一言:“泪眼问花花不语,乱红飞过秋千去🌸🌸” 题目 二.解题策略 本题比较简单,我的思路是写三个函数分别计算黄金白银铜一次新产值,通过k次循环即可获…...
【模块化拆解与多视角信息1】基础信息:隐藏的筛选规则——那些简历上没说出口的暗号
写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…...
当Browser Use遇见A2A:浏览器自动化与智能体协作的“冰与火之歌“
——一场正在改写数字文明的技术奇遇 第一章 浏览器革命:从"手动挡"到"自动驾驶" 1.1 传统自动化工具的"中年危机" 还记得2023年那个抓狂的凌晨吗?你蹲守演唱会门票时,Selenium脚本因为验证码识别失败第108次…...
Python:开启自动化办公与游戏开发的无限可能
重要的事情放在前面 Python自动化办公和游戏 Python:开启自动化办公与游戏开发的无限可能 在数字化时代的浪潮中,Python以其强大的功能和简洁的语法,成为了众多开发者手中的得力工具,尤其在自动化办公与游戏开发领域࿰…...
腾讯后台开发 一面
一、手撕 合并升序链表 合并两个排序的链表_牛客题霸_牛客网 顺时针翻转矩阵 顺时针旋转矩阵_牛客题霸_牛客网 二、八股 1、静态变量和实例变量 public class House {public static String buildDate "2024-10-27"; // 静态变量public String color; // 实…...
基于生成对抗网络(GAN)的手写数字生成实践
基于生成对抗网络(GAN)的手写数字生成实践 一、图像生成的技术演进 在人工智能领域,图像生成技术经历了从传统算法到深度学习的革命性发展。其中,生成对抗网络(Generative Adversarial Networks, GANs)作…...
网络互连与互联网
1.在路由表中找不到目标网络时使用默认路由,默认路由通常指本地网关的地址。 2.OSPF最主要的特征是使用分布式链路状态协议,而RIP使用的是距离向量协议。 3.OSPF使用链路状态公告LSA扩散路由信息 4.内部网关路由协议IGRP是一种动态距离矢量路由协议&a…...
大模型常见面试题
大模型常见面试题 大模型相关的面试问题通常涉及模型的原理、应用、优化以及面试者对于该领域的理解和经验。以下是一些常见的 大模型面试问题以及建议的回答方式: 请简述什么是大模型,以及它与传统模型的主要区别是什么? 回答:…...
python高级编程一(生成器与高级编程)
@TOC 生成器 生成器使用 通过列表⽣成式,我们可以直接创建⼀个列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含100万个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后⾯绝⼤多数元素占 ⽤的空间都⽩⽩浪费了。所以,如果…...
Linux线程属性与多线程开发:API详解与实战代码解析
Linux 线程的属性 线程池 多线程的创建 线程的属性 引入 我们设想一个场景,使用pthread_detach时,发现线程早就已经结束了,这时候pthread_detach还能正常发挥清理线程的 独有空间 的作用吗? 答案是可以的,但是这难…...
Inkscape安装教程
Inkscape 是一款开源的矢量图形编辑软件,功能强大且免费,适用于 Windows、macOS 和 Linux 系统。以下是在不同操作系统上安装 Inkscape 的详细教程: 一、Windows 系统安装 Inkscape 1. 下载安装包 打开浏览器,访问 Inkscape 官方…...