当前位置: 首页 > news >正文

第四篇:[特殊字符] 深入理解MyBatis[特殊字符] 掌握MyBatis Generator ——入门与实战

引言

什么是 MyBatis Generator?

MyBatis Generator (MBG) 是一个代码生成工具,专为 MyBatis 框架设计。它可以根据数据库表结构自动生成 Java 实体类、Mapper 接口、Mapper XML 文件以及 Example 类。通过使用 MBG,开发者可以显著减少编写重复代码的工作量,提高开发效率,并确保代码的一致性和质量。

为什么需要使用 MyBatis Generator?
  1. 提高开发效率

    • 手动编写实体类、Mapper 接口和 XML 文件是一项繁琐且容易出错的任务。MBG 可以自动完成这些工作,让开发者可以专注于业务逻辑的实现。
  2. 减少错误

    • 自动生成的代码通常比手动编写的代码更一致且不易出错。MBG 生成的代码经过严格的测试,减少了因人为因素引入的错误。
  3. 一致性保证

    • 使用 MBG 生成的代码在风格和格式上保持一致,这有助于团队协作和代码维护。
  4. 快速响应变化

    • 当数据库结构发生变化时,只需重新运行 MBG 即可更新相应的 Java 代码,大大简化了维护工作。
  5. 支持多种数据库

    • MBG 支持多种数据库系统(如 MySQL、Oracle、PostgreSQL 等),使得跨数据库平台的应用开发更加方便。
本文的目标读者
  • 初学者:如果你是刚刚接触 MyBatis 或者对 MyBatis Generator 不太了解,这篇文章将帮助你从零开始学习如何使用 MBG。

  • 中级开发者:对于已经熟悉 MyBatis 但希望进一步提高开发效率的开发者,本文提供了详细的配置和使用指南,帮助你更好地利用 MBG 的功能。

  • 高级开发者:如果你已经在项目中使用过 MBG,但希望探索其更高级的功能(如自定义模板、插件等),本文也将提供一些进阶内容和最佳实践。

  • 项目经理和技术负责人:对于负责项目管理和技术决策的人员,本文可以帮助你了解 MBG 在项目中的应用价值,从而做出更好的技术选型和决策。

 

第一部分:MyBatis Generator 概述

1.什么是 MyBatis Generator?

定义和用途

MyBatis Generator (MBG) 是一个强大的代码生成工具,专为 MyBatis 框架设计。它可以根据数据库表结构自动生成 Java 实体类、Mapper 接口、Mapper XML 文件以及 Example 类。通过使用 MBG,开发者可以显著减少编写重复代码的工作量,提高开发效率,并确保代码的一致性和质量。

主要功能

  1. 生成 Java 实体类

    • 根据数据库表结构生成对应的 Java 实体类。
    • 支持基本的 CRUD 操作所需的字段和方法。
    • 可以配置是否生成构造函数、getter 和 setter 方法等。
  2. 生成 Mapper 接口

    • 生成包含基本 CRUD 操作(如 select, insert, update, delete)的 Mapper 接口。
    • 支持自定义方法的生成,可以通过插件扩展来实现更复杂的功能。
  3. 生成 Mapper XML 文件

    • 生成包含 SQL 语句映射的 XML 文件。
    • 包括基本的 SQL 语句(如 SELECT, INSERT, UPDATE, DELETE)。
    • 支持动态 SQL 生成,如 WHERE 子句的条件拼接。
  4. 生成 Example 类

    • 生成用于构建动态查询条件的 Example 类。
    • 通过 Example 类可以方便地构建复杂的查询条件,支持多条件组合。
  5. 支持多种数据库

    • 支持 MySQL、Oracle、PostgreSQL、SQL Server 等多种主流数据库系统。
    • 可以根据不同的数据库类型生成相应的 SQL 语句。
  6. 高度可配置

    • 通过 generatorConfig.xml 配置文件,可以灵活控制生成的内容和行为。
    • 支持配置目标包路径、表映射、生成选项等。
  7. 插件扩展

    • 支持自定义插件以扩展生成器的功能。
    • 可以通过插件实现更复杂的生成逻辑,如生成特定的业务逻辑代码。
  8. 模板定制

    • 支持自定义 Velocity 模板,以满足项目特定的需求。
    • 可以修改默认模板或创建新的模板,以生成符合项目规范的代码。
  9. 增量生成

    • 支持增量生成,即只生成新增或修改的表结构对应的代码。
    • 可以配置 overwrite 选项,决定是否覆盖已存在的文件。
  10. 集成到 CI/CD 流程

    • 可以轻松集成到持续集成和持续部署流程中。
    • 自动化生成代码,确保每次构建时代码的一致性和最新性。

2 MyBatis Generator 的优势

MyBatis Generator (MBG) 为开发者提供了多种优势,使其成为 MyBatis 项目中不可或缺的工具。以下是 MBG 的主要优势:

提高开发效率
  1. 自动化生成

    • MBG 可以自动生成 Java 实体类、Mapper 接口、Mapper XML 文件和 Example 类,这些通常是手动编写时非常繁琐且容易出错的部分。
    • 开发者可以将更多时间集中在业务逻辑的实现上,而不是重复的代码编写。
  2. 快速响应变化

    • 当数据库表结构发生变化时,只需重新运行 MBG 即可更新相应的 Java 代码,大大简化了维护工作。
    • 自动化生成确保了代码与数据库结构的一致性,减少了手动同步的工作量。
  3. 减少配置时间

    • 通过配置文件 generatorConfig.xml,可以一次性定义多个表的生成规则,避免了逐个手动配置的时间消耗。
    • 配置文件支持灵活的选项,可以根据项目需求进行调整。
减少重复代码
  1. 一致的代码风格

    • 自动生成的代码在风格和格式上保持一致,减少了因人为因素引入的错误。
    • 一致的代码风格使得团队协作更加顺畅,代码维护也变得更加简单。
  2. 避免手动错误

    • 手动编写大量相似的代码容易引入拼写错误、语法错误等,而 MBG 生成的代码经过严格的测试,减少了这类错误的发生。
    • 生成的代码通常比手动编写的代码更可靠,提高了代码的质量。
  3. 减少冗余代码

    • MBG 只生成必要的代码,避免了冗余和不必要的代码片段。
    • 通过配置文件,可以控制生成哪些方法和字段,进一步减少冗余代码。
一致性保证
  1. 统一的代码模板

    • MBG 使用预定义的模板生成代码,确保生成的代码在风格和格式上保持一致。
    • 可以通过自定义模板来满足项目的特定需求,但仍保持一致的代码风格。
  2. 易于维护

    • 一致的代码风格使得团队成员更容易理解和维护代码。
    • 当新的开发者加入项目时,一致的代码风格有助于他们更快地熟悉项目代码。
  3. 版本控制友好

    • 生成的代码可以轻松纳入版本控制系统(如 Git),便于团队协作和版本管理。
    • 生成器配置文件也可以纳入版本控制,确保所有团队成员使用相同的生成规则。
  4. 文档生成

    • 生成的代码通常包含注释和文档,帮助开发者理解代码的功能和用途。
    • 一致的文档风格也有助于提高代码的可读性和可维护性。

3 MyBatis Generator 的工作原理

生成器的架构

MyBatis Generator (MBG) 的架构设计使其能够高效地从数据库表结构生成 Java 代码。以下是 MBG 的主要组成部分及其功能:

  1. 配置文件 (generatorConfig.xml)

    • 定义了生成器的行为,包括数据库连接信息、目标包路径、表映射等。
    • 支持多种配置选项,如是否生成某些特定的方法(例如 selectByExample)。
  2. 数据库元数据读取

    • 从数据库中读取表结构、字段信息等元数据。
    • 支持多种数据库驱动,如 MySQL、Oracle、PostgreSQL 等。
  3. 代码生成器

    • 根据配置文件和数据库元数据生成 Java 实体类、Mapper 接口、Mapper XML 文件和 Example 类。
    • 支持自定义模板和插件扩展。
  4. 输出文件

    • 生成的代码文件被写入指定的目标包路径。
    • 包括 Java 实体类、Mapper 接口、Mapper XML 文件和 Example 类。
生成过程详解

以下是 MyBatis Generator 生成代码的详细过程:

  1. 读取配置文件

    • 生成器首先读取 generatorConfig.xml 配置文件,获取数据库连接信息、目标包路径、表映射等配置。
    • 配置文件中的内容决定了生成器的行为,包括哪些表需要生成代码、生成的目标包路径、是否覆盖现有文件等。
  2. 建立数据库连接

    • 使用配置文件中的数据库连接信息(如驱动类、URL、用户名和密码)建立数据库连接。
    • 连接成功后,生成器可以访问数据库中的元数据。
  3. 读取数据库元数据

    • 通过数据库连接读取指定表的元数据,包括表名、字段名、字段类型、主键等信息。
    • 元数据是生成代码的基础,生成器会根据这些信息生成相应的 Java 类和 SQL 映射。
  4. 生成代码

    • 根据读取到的元数据和配置文件中的设置,生成相应的 Java 实体类、Mapper 接口、Mapper XML 文件和 Example 类。
    • 生成的代码基于预定义的模板,支持自定义模板和插件扩展。
    • 生成的具体内容包括:
      • Java 实体类:包含表的字段、构造函数、getter 和 setter 方法等。
      • Mapper 接口:包含基本的 CRUD 操作方法(如 select, insert, update, delete)。
      • Mapper XML 文件:包含与 Mapper 接口方法对应的 SQL 语句。
      • Example 类:用于构建动态查询条件的类。
  5. 写入输出文件

    • 将生成的代码文件写入指定的目标包路径。
    • 如果配置文件中设置了 overwrite 选项,则会覆盖已存在的文件;否则,将保留现有文件。
    • 生成的文件通常包括:
      • Java 实体类文件(例如 User.java
      • Mapper 接口文件(例如 UserMapper.java
      • Mapper XML 文件(例如 UserMapper.xml
      • Example 类文件(例如 UserExample.java
  6. 日志记录

    • 生成过程中,生成器会记录详细的日志信息,包括生成的文件路径、生成的状态等。
    • 日志信息有助于调试和跟踪生成过程中的问题。

第二部分:环境准备

在使用 MyBatis Generator 之前,需要确保你的开发环境已经安装并配置了必要的工具和依赖。以下是详细的环境准备步骤:

安装 Java Development Kit (JDK)

JDK 的安装步骤

  1. 下载 JDK

    • 访问 Oracle 官方网站 或 OpenJDK 下载适合你操作系统的 JDK 版本。
    • 推荐使用 LTS(长期支持)版本,如 JDK 8 或 JDK 11。
  2. 安装 JDK

    • 运行下载的安装程序,并按照提示进行安装。
    • 在 Windows 上,通常选择默认安装路径(如 C:\Program Files\Java\jdk-<version>)。
    • 在 macOS 和 Linux 上,通常通过包管理器进行安装,例如在 Ubuntu 上可以使用以下命令:
      sudo apt update
      sudo apt install openjdk-11-jdk
      
  3. 验证安装

    • 打开终端或命令提示符,输入以下命令来验证 JDK 是否安装成功:
      java -version
      
    • 如果安装成功,会显示 JDK 的版本信息。

配置环境变量

  1. 设置 JAVA_HOME 环境变量

    • 在 Windows 上,打开“系统属性” -> “高级系统设置” -> “环境变量”。
    • 在“系统变量”中点击“新建”,添加 JAVA_HOME 变量,值为 JDK 的安装路径(例如 C:\Program Files\Java\jdk-<version>)。
    • 在“系统变量”中找到 Path 变量,点击“编辑”,将 %JAVA_HOME%\bin 添加到路径中。
  2. 在 macOS 和 Linux 上配置环境变量

    • 编辑 ~/.bashrc~/.zshrc 文件(取决于你使用的 shell),添加以下内容:
      export JAVA_HOME=/path/to/jdk
      export PATH=$JAVA_HOME/bin:$PATH
      
    • 保存文件后,运行以下命令使更改生效:
      source ~/.bashrc
      
安装 Maven

Maven 的安装步骤

  1. 下载 Maven

    • 访问 Apache Maven 官方网站 下载最新版本的 Maven 压缩包。
  2. 解压 Maven

    • 将下载的压缩包解压到一个目录,例如 C:\Program Files\Apache\maven-<version>(Windows)或 /usr/local/apache-maven-<version>(macOS/Linux)。
  3. 配置环境变量

    • 在 Windows 上

      • 打开“系统属性” -> “高级系统设置” -> “环境变量”。
      • 在“系统变量”中点击“新建”,添加 MAVEN_HOME 变量,值为 Maven 的安装路径(例如 C:\Program Files\Apache\maven-<version>)。
      • 在“系统变量”中找到 Path 变量,点击“编辑”,将 %MAVEN_HOME%\bin 添加到路径中。
    • 在 macOS 和 Linux 上

      • 编辑 ~/.bashrc~/.zshrc 文件,添加以下内容:
        export MAVEN_HOME=/path/to/maven
        export PATH=$MAVEN_HOME/bin:$PATH
        
      • 保存文件后,运行以下命令使更改生效:
        source ~/.bashrc
        
  4. 验证安装

    • 打开终端或命令提示符,输入以下命令来验证 Maven 是否安装成功:
      mvn -v
      
    • 如果安装成功,会显示 Maven 的版本信息。
数据库驱动的安装

示例:MySQL JDBC 驱动的安装

  1. 下载 MySQL JDBC 驱动

    • 访问 MySQL 官方网站 下载最新版本的 MySQL Connector/J 驱动。
  2. 将驱动添加到项目中

    • 对于 Maven 项目

      • 在项目的 pom.xml 文件中添加以下依赖:
        <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version>
        </dependency>
        
      • 运行 mvn install 命令以下载并安装依赖。
    • 对于非 Maven 项目

      • 将下载的 JAR 文件(例如 mysql-connector-java-8.0.23.jar)复制到项目的 lib 目录下。
      • 在 IDE 中配置项目的类路径,确保包含该 JAR 文件。
  3. 验证驱动

    • 创建一个简单的 Java 程序,尝试连接到 MySQL 数据库,以验证驱动是否正确安装和配置。例如:
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;public class TestConnection {public static void main(String[] args) {String url = "jdbc:mysql://localhost:3306/your_database";String user = "your_username";String password = "your_password";try (Connection conn = DriverManager.getConnection(url, user, password)) {System.out.println("Connected to the database!");} catch (SQLException e) {e.printStackTrace();}}
      }
      

第三部分:配置 MyBatis Generator

在这一部分,我们将详细介绍如何配置 MyBatis Generator (MBG),包括创建 Maven 项目、配置 generatorConfig.xml 文件、配置表映射以及自定义模板。

创建 Maven 项目

使用 IDE 创建 Maven 项目

  1. 使用 IntelliJ IDEA 创建 Maven 项目

    • 打开 IntelliJ IDEA。
    • 选择 File -> New -> Project
    • 选择 Maven,点击 Next
    • 输入项目名称和位置,点击 Finish
  2. 使用 Eclipse 创建 Maven 项目

    • 打开 Eclipse。
    • 选择 File -> New -> Other
    • 选择 Maven -> Maven Project,点击 Next
    • 选择 Create a simple project (skip archetype selection),点击 Next
    • 输入项目名称和位置,点击 Finish

添加 MyBatis Generator 依赖

在项目的 pom.xml 文件中添加 MyBatis Generator 的依赖。此外,还需要添加数据库驱动的依赖(以 MySQL 为例):

<dependencies><!-- MyBatis Generator 依赖 --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.4.0</version><scope>test</scope></dependency><!-- MySQL JDBC 驱动依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency>
</dependencies>
创建 generatorConfig.xml 文件

配置文件的基本结构

generatorConfig.xml 是 MyBatis Generator 的核心配置文件,它定义了生成器的行为。以下是一个基本的配置文件结构:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 数据库连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/your_database"userId="your_username"password="your_password"></jdbcConnection><!-- Java 模型生成目标包 --><javaModelGenerator targetPackage="com.yourpackage.model" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/></javaModelGenerator><!-- SQL 映射文件生成目标包 --><sqlMapGenerator targetPackage="com.yourpackage.mapper" targetProject="src/main/resources"><property name="enableSubPackages" value="true"/></sqlMapGenerator><!-- Mapper 接口生成目标包 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.yourpackage.mapper" targetProject="src/main/java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!-- 表配置 --><table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/></table>
</generatorConfiguration>

数据库连接信息

  • driverClass:数据库驱动类名。
  • connectionURL:数据库连接 URL。
  • userId:数据库用户名。
  • password:数据库密码。

目标包和目标项目

  • targetPackage:生成的 Java 类的目标包路径。
  • targetProject:生成的 Java 类的目标项目路径。
  • enableSubPackages:是否启用子包。
  • trimStrings:是否修剪字符串(去除前后空格)。
配置表映射

表配置详解

  • tableName:数据库表名。
  • domainObjectName:生成的实体类名。
  • enableCountByExampleenableUpdateByExampleenableDeleteByExampleenableSelectByExample:是否生成对应的 Example 方法。
  • selectByExampleQueryId:是否生成查询 ID。

自定义生成选项

  • generatedKey:指定主键生成策略。

    <generatedKey column="id" sqlStatement="MySql" identity="true"/>
    
  • columnOverride:覆盖列的属性。

    <columnOverride column="name" property="userName" javaType="String" jdbcType="VARCHAR"/>
    
  • ignoreColumn:忽略某些列。

    <ignoreColumn column="created_at" />
    
自定义模板

使用 Velocity 模板

MyBatis Generator 支持使用 Velocity 模板来自定义生成的代码。你可以在配置文件中指定模板路径,并编写自定义的 Velocity 模板。

自定义模板示例

  1. 创建自定义模板文件

    • 在项目的资源目录下创建一个 templates 文件夹,并在其中创建自定义模板文件。例如,创建 JavaModel.vmJavaMapper.vm
  2. 编写自定义模板

    • JavaModel.vm 示例:

      #set($className = $table.className)
      package ${table.javaModelGenerator.targetPackage};import java.util.Date;public class ${className} {#foreach ($column in $table.columns)private ${column.javaType} ${column.javaProperty};#end#foreach ($column in $table.columns)public ${column.javaType} get${column.javaProperty}() {return this.${column.javaProperty};}public void set${column.javaProperty}(${column.javaType} ${column.javaProperty}) {this.${column.javaProperty} = ${column.javaProperty};}#end
      }
      
    • JavaMapper.vm 示例:

      #set($className = $table.className)
      package ${table.javaClientGenerator.targetPackage};import org.apache.ibatis.annotations.*;
      import ${table.javaModelGenerator.targetPackage}.${table.className};public interface ${className}Mapper {@Select("SELECT * FROM ${table.tableName} WHERE id = #{id}")${className} selectById(@Param("id") Long id);@Insert("INSERT INTO ${table.tableName} (#{columns}) VALUES (#{values})")@Options(useGeneratedKeys = true, keyProperty = "id")int insert(${className} record);
      }
      
  3. 配置 generatorConfig.xml 使用自定义模板

    <table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/><context property="javaFileGenerator" value="com.yourpackage.MyCustomJavaFileGenerator"/><context property="javaClientGenerator" value="com.yourpackage.MyCustomJavaClientGenerator"/>
    </table><plugin type="org.mybatis.generator.plugins.SerializablePlugin" />
    <plugin type="org.mybatis.generator.plugins.ToStringPlugin" /><javaModelGenerator targetPackage="com.yourpackage.model" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/><property name="templateFile" value="path/to/templates/JavaModel.vm"/>
    </javaModelGenerator><javaClientGenerator type="XMLMAPPER" targetPackage="com.yourpackage.mapper" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="templateFile" value="path/to/templates/JavaMapper.vm"/>
    </javaClientGenerator>
    

通过以上步骤,你可以配置 MyBatis Generator 以生成符合项目需求的代码。接下来的部分将介绍如何运行 MyBatis Generator 并检查生成的代码。

第四部分:运行 MyBatis Generator

在这一部分,我们将详细介绍如何运行 MyBatis Generator (MBG),包括使用命令行和 Maven 插件两种方式。我们还将介绍生成的文件结构,帮助你理解生成的代码。

使用命令行运行

命令行参数详解

MyBatis Generator 可以通过命令行直接运行。以下是常用的命令行参数:

  • -configfile-c:指定配置文件的路径。
  • -overwrite-o:是否覆盖已存在的文件。
  • -verbose-v:输出详细的日志信息。
  • -help-h:显示帮助信息。

运行示例

假设你已经将 MyBatis Generator 的 JAR 包下载到本地,并且配置文件 generatorConfig.xml 位于项目的 src/main/resources 目录下,可以使用以下命令运行生成器:

java -jar mybatis-generator-core-1.4.0.jar -configfile src/main/resources/generatorConfig.xml -overwrite -verbose

这个命令会读取 generatorConfig.xml 文件,并根据配置生成相应的代码。如果目标文件已经存在,-overwrite 参数会覆盖这些文件。-verbose 参数则会输出详细的日志信息,帮助你调试和跟踪生成过程。

使用 Maven 插件运行

配置 Maven 插件

如果你使用 Maven 项目,可以通过配置 MyBatis Generator Maven 插件来运行生成器。在项目的 pom.xml 文件中添加以下插件配置:

<build><plugins><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.4.0</version><configuration><configurationFile>src/main/resources/generatorConfig.xml</configurationFile><verbose>true</verbose><overwrite>true</overwrite></configuration><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency></dependencies></plugin></plugins>
</build>

运行插件示例

在终端或命令提示符中,导航到项目的根目录并运行以下命令:

mvn mybatis-generator:generate

这个命令会读取 generatorConfig.xml 文件,并根据配置生成相应的代码。Maven 插件会自动处理依赖关系,并执行生成任务。

生成的文件结构

运行 MyBatis Generator 后,会在指定的目标包路径下生成以下类型的文件:

生成的 Java 实体类

  • 文件位置src/main/java/com/yourpackage/model/User.java
  • 内容示例
    package com.yourpackage.model;public class User {private Long id;private String username;private String password;private Date createdAt;// Getter and Setter methodspublic Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Date getCreatedAt() {return createdAt;}public void setCreatedAt(Date createdAt) {this.createdAt = createdAt;}
    }
    

生成的 Mapper 接口

  • 文件位置src/main/java/com/yourpackage/mapper/UserMapper.java
  • 内容示例
    package com.yourpackage.mapper;import com.yourpackage.model.User;
    import org.apache.ibatis.annotations.*;public interface UserMapper {@Select("SELECT * FROM users WHERE id = #{id}")User selectById(@Param("id") Long id);@Insert("INSERT INTO users (username, password, created_at) VALUES (#{username}, #{password}, #{createdAt})")@Options(useGeneratedKeys = true, keyProperty = "id")int insert(User user);@Update("UPDATE users SET username = #{username}, password = #{password}, created_at = #{createdAt} WHERE id = #{id}")int update(User user);@Delete("DELETE FROM users WHERE id = #{id}")int deleteById(@Param("id") Long id);
    }
    

生成的 Mapper XML 文件

  • 文件位置src/main/resources/com/yourpackage/mapper/UserMapper.xml
  • 内容示例
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.yourpackage.mapper.UserMapper"><resultMap id="BaseResultMap" type="com.yourpackage.model.User"><id column="id" property="id" jdbcType="BIGINT"/><result column="username" property="username" jdbcType="VARCHAR"/><result column="password" property="password" jdbcType="VARCHAR"/><result column="created_at" property="createdAt" jdbcType="TIMESTAMP"/></resultMap><sql id="Base_Column_List">id, username, password, created_at</sql><select id="selectById" resultMap="BaseResultMap">SELECT<include refid="Base_Column_List"/>FROM usersWHERE id = #{id}</select><insert id="insert" parameterType="com.yourpackage.model.User" useGeneratedKeys="true" keyProperty="id">INSERT INTO users (username, password, created_at)VALUES (#{username}, #{password}, #{createdAt})</insert><update id="update" parameterType="com.yourpackage.model.User">UPDATE usersSET username = #{username},password = #{password},created_at = #{createdAt}WHERE id = #{id}</update><delete id="deleteById">DELETE FROM usersWHERE id = #{id}</delete>
    </mapper>
    

生成的 Example 类

  • 文件位置src/main/java/com/yourpackage/model/UserExample.java
  • 内容示例
    package com.yourpackage.model;import java.util.ArrayList;
    import java.util.List;public class UserExample {protected String orderByClause;protected boolean distinct;protected List<Criteria> oredCriteria;public UserExample() {oredCriteria = new ArrayList<>();}public void setOrderByClause(String orderByClause) {this.orderByClause = orderByClause;}public String getOrderByClause() {return orderByClause;}public void setDistinct(boolean distinct) {this.distinct = distinct;}public boolean isDistinct() {return distinct;}public List<Criteria> getOredCriteria() {return oredCriteria;}public void or(Criteria criteria) {oredCriteria.add(criteria);}public Criteria or() {Criteria criteria = createCriteriaInternal();oredCriteria.add(criteria);return criteria;}public Criteria createCriteria() {Criteria criteria = createCriteriaInternal();if (oredCriteria.size() == 0) {oredCriteria.add(criteria);}return criteria;}protected Criteria createCriteriaInternal() {Criteria criteria = new Criteria();return criteria;}public void clear() {oredCriteria.clear();orderByClause = null;distinct = false;}protected abstract static class GeneratedCriteria {protected List<Criterion> criteria;protected GeneratedCriteria() {super();criteria = new ArrayList<>();}public boolean isValid() {return criteria.size() > 0;}public List<Criterion> getAllCriteria() {return criteria;}public List<Criterion> getCriteria() {return criteria;}protected void addCriterion(String condition) {if (condition == null) {throw new RuntimeException("Value for condition cannot be null");}criteria.add(new Criterion(condition));}protected void addCriterion(String condition, Object value, String property) {if (value == null) {throw new RuntimeException("Value for " + property + " cannot be null");}criteria.add(new Criterion(condition, value));}protected void addCriterion(String condition, Object value1, Object value2, String property) {if (value1 == null || value2 == null) {throw new RuntimeException("Between values for " + property + " cannot be null");}criteria.add(new Criterion(condition, value1, value2));}public Criteria andIdIsNull() {addCriterion("id is null");return (Criteria) this;}public Criteria andIdIsNotNull() {addCriterion("id is not null");return (Criteria) this;}public Criteria andIdEqualTo(Long value) {addCriterion("id =", value, "id");return (Criteria) this;}public Criteria andIdNotEqualTo(Long value) {addCriterion("id <>", value, "id");return (Criteria) this;}public Criteria andIdGreaterThan(Long value) {addCriterion("id >", value, "id");return (Criteria) this;}public Criteria andIdGreaterThanOrEqualTo(Long value) {addCriterion("id >=", value, "id");return (Criteria) this;}public Criteria andIdLessThan(Long value) {addCriterion("id <", value, "id");return (Criteria) this;}public Criteria andIdLessThanOrEqualTo(Long value) {addCriterion("id <=", value, "id");return (Criteria) this;}public Criteria andIdIn(List<Long> values) {addCriterion("id in", values, "id");return (Criteria) this;}public Criteria andIdNotIn(List<Long> values) {addCriterion("id not in", values, "id");return (Criteria) this;}public Criteria andIdBetween(Long value1, Long value2) {addCriterion("id between", value1, value2, "id");return (Criteria) this;}public Criteria andIdNotBetween(Long value1, Long value2) {addCriterion("id not between", value1, value2, "id");return (Criteria) this;}public Criteria andUsernameIsNull() {addCriterion("username is null");return (Criteria) this;}public Criteria andUsernameIsNotNull() {addCriterion("username is not null");return (Criteria) this;}public Criteria andUsernameEqualTo(String value) {addCriterion("username =", value, "username");return (Criteria) this;}public Criteria andUsernameNotEqualTo(String value) {addCriterion("username <>", value, "username");return (Criteria) this;}public Criteria andUsernameGreaterThan(String value) {addCriterion("username >", value, "username");return (Criteria) this;}public Criteria andUsernameGreaterThanOrEqualTo(String value) {addCriterion("username >=", value, "username");return (Criteria) this;}public Criteria andUsernameLessThan(String value) {addCriterion("username <", value, "username");return (Criteria) this;}public Criteria andUsernameLessThanOrEqualTo(String value) {addCriterion("username <=", value, "username");return (Criteria) this;}public Criteria andUsernameLike(String value) {addCriterion("username like", value, "username");return (Criteria) this;}public Criteria andUsernameNotLike(String value) {addCriterion("username not like", value, "username");return (Criteria) this;}public Criteria andUsernameIn(List<String> values) {addCriterion("username in", values, "username");return (Criteria) this;}public Criteria andUsernameNotIn(List<String> values) {addCriterion("username not in", values, "username");return (Criteria) this;}public Criteria andUsernameBetween(String value1, String value2) {addCriterion("username between", value1, value2, "username");return (Criteria) this;}public Criteria andUsernameNotBetween(String value1, String value2) {addCriterion("username not between", value1, value2, "username");return (Criteria) this;}public Criteria andPasswordIsNull() {addCriterion("password is null");return (Criteria) this;}public Criteria andPasswordIsNotNull() {addCriterion("password is not null");return (Criteria) this;}public Criteria andPasswordEqualTo(String value) {addCriterion("password =", value, "password");return (Criteria) this;}public Criteria andPasswordNotEqualTo(String value) {addCriterion("password <>", value, "password");return (Criteria) this;}public Criteria andPasswordGreaterThan(String value) {addCriterion("password >", value, "password");return (Criteria) this;}public Criteria andPasswordGreaterThanOrEqualTo(String value) {addCriterion("password >=", value, "password");return (Criteria) this;}public Criteria andPasswordLessThan(String value) {addCriterion("password <", value, "password");return (Criteria) this;}public Criteria andPasswordLessThanOrEqualTo(String value) {addCriterion("password <=", value, "password");return (Criteria) this;}public Criteria andPasswordLike(String value) {addCriterion("password like", value, "password");return (Criteria) this;}public Criteria andPasswordNotLike(String value) {addCriterion("password not like", value, "password");return (Criteria) this;}public Criteria andPasswordIn(List<String> values) {addCriterion("password in", values, "password");return (Criteria) this;}public Criteria andPasswordNotIn(List<String> values) {addCriterion("password not in", values, "password");return (Criteria) this;}public Criteria andPasswordBetween(String value1, String value2) {addCriterion("password between", value1, value2, "password");return (Criteria) this;}public Criteria andPasswordNotBetween(String value1, String value2) {addCriterion("password not between", value1, value2, "password");return (Criteria) this;}public Criteria andCreatedAtIsNull() {addCriterion("created_at is null");return (Criteria) this;}public Criteria andCreatedAtIsNotNull() {addCriterion("created_at is not null");return (Criteria) this;}public Criteria andCreatedAtEqualTo(Date value) {addCriterion("created_at =", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtNotEqualTo(Date value) {addCriterion("created_at <>", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtGreaterThan(Date value) {addCriterion("created_at >", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtGreaterThanOrEqualTo(Date value) {addCriterion("created_at >=", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtLessThan(Date value) {addCriterion("created_at <", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtLessThanOrEqualTo(Date value) {addCriterion("created_at <=", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtIn(List<Date> values) {addCriterion("created_at in", values, "createdAt");return (Criteria) this;}public Criteria andCreatedAtNotIn(List<Date> values) {addCriterion("created_at not in", values, "createdAt");return (Criteria) this;}public Criteria andCreatedAtBetween(Date value1, Date value2) {addCriterion("created_at between", value1, value2, "createdAt");return (Criteria) this;}public Criteria andCreatedAtNotBetween(Date value1, Date value2) {addCriterion("created_at not between", value1, value2, "createdAt");return (Criteria) this;}}public static class Criteria extends GeneratedCriteria {protected Criteria() {super();}}public static class Criterion {private String condition;private Object value;private Object secondValue;private boolean noValue;private boolean singleValue;private boolean betweenValue;private boolean listValue;private String typeHandler;protected Criterion(String condition) {super();this.condition = condition;this.typeHandler = null;this.noValue = true;}protected Criterion(String condition, Object value, String typeHandler) {super();this.condition = condition;this.value = value;this.typeHandler = typeHandler;if (value instanceof List<?>) {this.listValue = true;} else {this.singleValue = true;}}protected Criterion(String condition, Object value) {this(condition, value, null);}protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {super();this.condition = condition;this.value = value;this.secondValue = secondValue;this.typeHandler = typeHandler;this.betweenValue = true;}protected Criterion(String condition, Object value, Object secondValue) {this(condition, value, secondValue, null);}public String getCondition() {return condition;}public Object getValue() {return value;}public Object getSecondValue() {return secondValue;}public boolean isNoValue() {return noValue;}public boolean isSingleValue() {return singleValue;}public boolean isBetweenValue() {return betweenValue;}public boolean isListValue() {return listValue;}public String getTypeHandler() {return typeHandler;}}
    }
    

通过以上步骤,你可以成功运行 MyBatis Generator 并生成所需的代码文件。生成的文件结构清晰,便于管理和维护。接下来的部分将介绍如何进一步优化和扩展 MyBatis Generator 的功能。

第五部分:生成的内容详解

在这一部分,我们将详细介绍 MyBatis Generator 生成的各个文件的具体内容和结构,包括 Java 实体类、Mapper 接口、Mapper XML 文件和 Example 类。这将帮助你更好地理解和使用生成的代码。

Java 实体类

字段映射

  • 字段:Java 实体类中的字段与数据库表中的列一一对应。
  • 注解:字段上通常会添加 @Column 注解(如果使用 JPA)或其他相关注解来描述字段属性。

构造函数和方法

  • 默认构造函数:无参构造函数,用于对象的初始化。
  • 带参数的构造函数:根据需要生成带参数的构造函数。
  • Getter 和 Setter 方法:每个字段都有对应的 Getter 和 Setter 方法,用于获取和设置字段值。

示例

假设有一个 users 表,包含 id, username, password, 和 created_at 字段,生成的 User 实体类如下:

package com.yourpackage.model;import java.util.Date;public class User {private Long id;private String username;private String password;private Date createdAt;// 默认构造函数public User() {}// 带参数的构造函数public User(Long id, String username, String password, Date createdAt) {this.id = id;this.username = username;this.password = password;this.createdAt = createdAt;}// Getter 和 Setter 方法public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Date getCreatedAt() {return createdAt;}public void setCreatedAt(Date createdAt) {this.createdAt = createdAt;}
}
Mapper 接口

CRUD 方法

  • selectById:根据主键查询单个记录。
  • insert:插入一条新记录。
  • update:更新现有记录。
  • deleteById:根据主键删除记录。

自定义方法

  • 可以通过配置文件或自定义插件添加额外的方法。

示例

package com.yourpackage.mapper;import com.yourpackage.model.User;
import org.apache.ibatis.annotations.*;public interface UserMapper {@Select("SELECT * FROM users WHERE id = #{id}")User selectById(@Param("id") Long id);@Insert("INSERT INTO users (username, password, created_at) VALUES (#{username}, #{password}, #{createdAt})")@Options(useGeneratedKeys = true, keyProperty = "id")int insert(User user);@Update("UPDATE users SET username = #{username}, password = #{password}, created_at = #{createdAt} WHERE id = #{id}")int update(User user);@Delete("DELETE FROM users WHERE id = #{id}")int deleteById(@Param("id") Long id);// 自定义方法@Select("SELECT * FROM users WHERE username = #{username}")User selectByUsername(@Param("username") String username);
}
Mapper XML 文件

SQL 语句映射

  • Result Map:定义了结果集与实体类之间的映射关系。
  • SQL 语句:定义了具体的 SQL 语句,如 SELECT, INSERT, UPDATE, DELETE

参数传递

  • 使用 #{} 占位符传递参数,MyBatis 会自动处理类型转换和防止 SQL 注入。

示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.yourpackage.mapper.UserMapper"><resultMap id="BaseResultMap" type="com.yourpackage.model.User"><id column="id" property="id" jdbcType="BIGINT"/><result column="username" property="username" jdbcType="VARCHAR"/><result column="password" property="password" jdbcType="VARCHAR"/><result column="created_at" property="createdAt" jdbcType="TIMESTAMP"/></resultMap><sql id="Base_Column_List">id, username, password, created_at</sql><select id="selectById" resultMap="BaseResultMap">SELECT<include refid="Base_Column_List"/>FROM usersWHERE id = #{id}</select><insert id="insert" parameterType="com.yourpackage.model.User" useGeneratedKeys="true" keyProperty="id">INSERT INTO users (username, password, created_at)VALUES (#{username}, #{password}, #{createdAt})</insert><update id="update" parameterType="com.yourpackage.model.User">UPDATE usersSET username = #{username},password = #{password},created_at = #{createdAt}WHERE id = #{id}</update><delete id="deleteById">DELETE FROM usersWHERE id = #{id}</delete><!-- 自定义方法 --><select id="selectByUsername" resultMap="BaseResultMap">SELECT<include refid="Base_Column_List"/>FROM usersWHERE username = #{username}</select>
</mapper>
Example 类

动态查询条件

  • Criteria:用于构建复杂的查询条件。
  • Example:封装了多个 Criteria 对象,支持多条件组合。

使用示例

package com.yourpackage.model;import java.util.ArrayList;
import java.util.List;public class UserExample {protected String orderByClause;protected boolean distinct;protected List<Criteria> oredCriteria;public UserExample() {oredCriteria = new ArrayList<>();}public void setOrderByClause(String orderByClause) {this.orderByClause = orderByClause;}public String getOrderByClause() {return orderByClause;}public void setDistinct(boolean distinct) {this.distinct = distinct;}public boolean isDistinct() {return distinct;}public List<Criteria> getOredCriteria() {return oredCriteria;}public void or(Criteria criteria) {oredCriteria.add(criteria);}public Criteria or() {Criteria criteria = createCriteriaInternal();oredCriteria.add(criteria);return criteria;}public Criteria createCriteria() {Criteria criteria = createCriteriaInternal();if (oredCriteria.size() == 0) {oredCriteria.add(criteria);}return criteria;}protected Criteria createCriteriaInternal() {Criteria criteria = new Criteria();return criteria;}public void clear() {oredCriteria.clear();orderByClause = null;distinct = false;}protected abstract static class GeneratedCriteria {protected List<Criterion> criteria;protected GeneratedCriteria() {super();criteria = new ArrayList<>();}public boolean isValid() {return criteria.size() > 0;}public List<Criterion> getAllCriteria() {return criteria;}public List<Criterion> getCriteria() {return criteria;}protected void addCriterion(String condition) {if (condition == null) {throw new RuntimeException("Value for condition cannot be null");}criteria.add(new Criterion(condition));}protected void addCriterion(String condition, Object value, String property) {if (value == null) {throw new RuntimeException("Value for " + property + " cannot be null");}criteria.add(new Criterion(condition, value));}protected void addCriterion(String condition, Object value1, Object value2, String property) {if (value1 == null || value2 == null) {throw new RuntimeException("Between values for " + property + " cannot be null");}criteria.add(new Criterion(condition, value1, value2));}public Criteria andIdIsNull() {addCriterion("id is null");return (Criteria) this;}public Criteria andIdIsNotNull() {addCriterion("id is not null");return (Criteria) this;}public Criteria andIdEqualTo(Long value) {addCriterion("id =", value, "id");return (Criteria) this;}public Criteria andIdNotEqualTo(Long value) {addCriterion("id <>", value, "id");return (Criteria) this;}public Criteria andIdGreaterThan(Long value) {addCriterion("id >", value, "id");return (Criteria) this;}public Criteria andIdGreaterThanOrEqualTo(Long value) {addCriterion("id >=", value, "id");return (Criteria) this;}public Criteria andIdLessThan(Long value) {addCriterion("id <", value, "id");return (Criteria) this;}public Criteria andIdLessThanOrEqualTo(Long value) {addCriterion("id <=", value, "id");return (Criteria) this;}public Criteria andIdIn(List<Long> values) {addCriterion("id in", values, "id");return (Criteria) this;}public Criteria andIdNotIn(List<Long> values) {addCriterion("id not in", values, "id");return (Criteria) this;}public Criteria andIdBetween(Long value1, Long value2) {addCriterion("id between", value1, value2, "id");return (Criteria) this;}public Criteria andIdNotBetween(Long value1, Long value2) {addCriterion("id not between", value1, value2, "id");return (Criteria) this;}public Criteria andUsernameIsNull() {addCriterion("username is null");return (Criteria) this;}public Criteria andUsernameIsNotNull() {addCriterion("username is not null");return (Criteria) this;}public Criteria andUsernameEqualTo(String value) {addCriterion("username =", value, "username");return (Criteria) this;}public Criteria andUsernameNotEqualTo(String value) {addCriterion("username <>", value, "username");return (Criteria) this;}public Criteria andUsernameGreaterThan(String value) {addCriterion("username >", value, "username");return (Criteria) this;}public Criteria andUsernameGreaterThanOrEqualTo(String value) {addCriterion("username >=", value, "username");return (Criteria) this;}public Criteria andUsernameLessThan(String value) {addCriterion("username <", value, "username");return (Criteria) this;}public Criteria andUsernameLessThanOrEqualTo(String value) {addCriterion("username <=", value, "username");return (Criteria) this;}public Criteria andUsernameLike(String value) {addCriterion("username like", value, "username");return (Criteria) this;}public Criteria andUsernameNotLike(String value) {addCriterion("username not like", value, "username");return (Criteria) this;}public Criteria andUsernameIn(List<String> values) {addCriterion("username in", values, "username");return (Criteria) this;}public Criteria andUsernameNotIn(List<String> values) {addCriterion("username not in", values, "username");return (Criteria) this;}public Criteria andUsernameBetween(String value1, String value2) {addCriterion("username between", value1, value2, "username");return (Criteria) this;}public Criteria andUsernameNotBetween(String value1, String value2) {addCriterion("username not between", value1, value2, "username");return (Criteria) this;}public Criteria andPasswordIsNull() {addCriterion("password is null");return (Criteria) this;}public Criteria andPasswordIsNotNull() {addCriterion("password is not null");return (Criteria) this;}public Criteria andPasswordEqualTo(String value) {addCriterion("password =", value, "password");return (Criteria) this;}public Criteria andPasswordNotEqualTo(String value) {addCriterion("password <>", value, "password");return (Criteria) this;}public Criteria andPasswordGreaterThan(String value) {addCriterion("password >", value, "password");return (Criteria) this;}public Criteria andPasswordGreaterThanOrEqualTo(String value) {addCriterion("password >=", value, "password");return (Criteria) this;}public Criteria andPasswordLessThan(String value) {addCriterion("password <", value, "password");return (Criteria) this;}public Criteria andPasswordLessThanOrEqualTo(String value) {addCriterion("password <=", value, "password");return (Criteria) this;}public Criteria andPasswordLike(String value) {addCriterion("password like", value, "password");return (Criteria) this;}public Criteria andPasswordNotLike(String value) {addCriterion("password not like", value, "password");return (Criteria) this;}public Criteria andPasswordIn(List<String> values) {addCriterion("password in", values, "password");return (Criteria) this;}public Criteria andPasswordNotIn(List<String> values) {addCriterion("password not in", values, "password");return (Criteria) this;}public Criteria andPasswordBetween(String value1, String value2) {addCriterion("password between", value1, value2, "password");return (Criteria) this;}public Criteria andPasswordNotBetween(String value1, String value2) {addCriterion("password not between", value1, value2, "password");return (Criteria) this;}public Criteria andCreatedAtIsNull() {addCriterion("created_at is null");return (Criteria) this;}public Criteria andCreatedAtIsNotNull() {addCriterion("created_at is not null");return (Criteria) this;}public Criteria andCreatedAtEqualTo(Date value) {addCriterion("created_at =", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtNotEqualTo(Date value) {addCriterion("created_at <>", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtGreaterThan(Date value) {addCriterion("created_at >", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtGreaterThanOrEqualTo(Date value) {addCriterion("created_at >=", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtLessThan(Date value) {addCriterion("created_at <", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtLessThanOrEqualTo(Date value) {addCriterion("created_at <=", value, "createdAt");return (Criteria) this;}public Criteria andCreatedAtIn(List<Date> values) {addCriterion("created_at in", values, "createdAt");return (Criteria) this;}public Criteria andCreatedAtNotIn(List<Date> values) {addCriterion("created_at not in", values, "createdAt");return (Criteria) this;}public Criteria andCreatedAtBetween(Date value1, Date value2) {addCriterion("created_at between", value1, value2, "createdAt");return (Criteria) this;}public Criteria andCreatedAtNotBetween(Date value1, Date value2) {addCriterion("created_at not between", value1, value2, "createdAt");return (Criteria) this;}}public static class Criteria extends GeneratedCriteria {protected Criteria() {super();}}public static class Criterion {private String condition;private Object value;private Object secondValue;private boolean noValue;private boolean singleValue;private boolean betweenValue;private boolean listValue;private String typeHandler;protected Criterion(String condition) {super();this.condition = condition;this.typeHandler = null;this.noValue = true;}protected Criterion(String condition, Object value, String typeHandler) {super();this.condition = condition;this.value = value;this.typeHandler = typeHandler;if (value instanceof List<?>) {this.listValue = true;} else {this.singleValue = true;}}protected Criterion(String condition, Object value) {this(condition, value, null);}protected Criterion(String condition, Object value, Object secondValue, String typeHandler) {super();this.condition = condition;this.value = value;this.secondValue = secondValue;this.typeHandler = typeHandler;this.betweenValue = true;}protected Criterion(String condition, Object value, Object secondValue) {this(condition, value, secondValue, null);}public String getCondition() {return condition;}public Object getValue() {return value;}public Object getSecondValue() {return secondValue;}public boolean isNoValue() {return noValue;}public boolean isSingleValue() {return singleValue;}public boolean isBetweenValue() {return betweenValue;}public boolean isListValue() {return listValue;}public String getTypeHandler() {return typeHandler;}}
}

使用示例

import com.yourpackage.mapper.UserMapper;
import com.yourpackage.model.User;
import com.yourpackage.model.UserExample;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.InputStream;
import java.util.List;public class Main {public static void main(String[] args) {// 读取 MyBatis 配置文件InputStream inputStream = Main.class.getResourceAsStream("/mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);try (SqlSession session = sqlSessionFactory.openSession()) {UserMapper userMapper = session.getMapper(UserMapper.class);// 查询所有用户List<User> users = userMapper.selectAll();for (User user : users) {System.out.println(user);}// 根据用户名查询用户UserExample example = new UserExample();example.createCriteria().andUsernameEqualTo("testuser");List<User> usersByName = userMapper.selectByExample(example);for (User user : usersByName) {System.out.println(user);}// 插入新用户User newUser = new User(null, "newuser", "newpassword", new Date());userMapper.insert(newUser);session.commit();// 更新用户User updateUser = new User(1L, "updateduser", "updatedpassword", new Date());userMapper.update(updateUser);session.commit();// 删除用户userMapper.deleteById(1L);session.commit();}}
}

通过以上内容,你可以详细了解 MyBatis Generator 生成的各个文件的具体结构和用法。这些生成的文件为你的项目提供了坚实的基础,使你能够更高效地进行开发。接下来的部分将介绍如何进一步扩展和优化 MyBatis Generator 的功能。

第六部分:常见问题及解决方案

在使用 MyBatis Generator 时,可能会遇到一些常见的问题。本部分将介绍这些问题及其解决方法,并提供一些性能优化的建议。

常见错误及解决方法

数据库连接失败

症状

  • 生成器无法连接到数据库。
  • 日志中显示连接超时或认证失败等错误信息。

解决方法

  1. 检查数据库连接配置

    • 确保 generatorConfig.xml 中的数据库连接信息(如驱动类、URL、用户名和密码)正确无误。
    • 例如:
      <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/your_database"userId="your_username"password="your_password">
      </jdbcConnection>
      
  2. 检查数据库服务是否运行

    • 确保数据库服务已经启动并且可以访问。
    • 使用数据库管理工具(如 MySQL Workbench 或 pgAdmin)测试连接。
  3. 检查网络连接

    • 确保你的开发环境可以访问数据库服务器。
    • 检查防火墙设置,确保端口未被阻止。
  4. 检查驱动依赖

    • 确保项目中包含了正确的数据库驱动依赖。
    • 例如,对于 MySQL:
      <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version>
      </dependency>
      

生成的代码不符合预期

症状

  • 生成的 Java 实体类、Mapper 接口或 XML 文件不符合预期。
  • 缺少某些字段或方法。

解决方法

  1. 检查表配置

    • 确保 generatorConfig.xml 中的 <table> 配置正确。
    • 例如:
      <table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/>
      </table>
      
  2. 检查字段映射

    • 确保数据库表中的字段名称和类型正确。
    • 如果需要忽略某些字段,可以使用 <ignoreColumn> 标签。
    • 例如:
      <ignoreColumn column="created_at" />
      
  3. 自定义模板

    • 如果默认模板生成的代码不符合需求,可以使用自定义模板。
    • 参考前面的自定义模板部分,编写和配置自定义模板文件。
  4. 调试日志

    • 启用详细日志输出,查看生成过程中的详细信息。
    • generatorConfig.xml 中添加 <verbose>true</verbose> 选项。
    • 例如:
      <configuration><configurationFile>src/main/resources/generatorConfig.xml</configurationFile><verbose>true</verbose><overwrite>true</overwrite>
      </configuration>
      
性能优化

优化生成配置

  1. 选择性生成

    • 只生成必要的表和字段,避免不必要的生成。
    • 使用 <table><ignoreColumn> 标签来控制生成的内容。
    • 例如:
      <table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><ignoreColumn column="created_at" />
      </table>
      
  2. 增量生成

    • 通过配置 overwrite 选项,只覆盖已存在的文件。
    • 例如:
      <configuration><configurationFile>src/main/resources/generatorConfig.xml</configurationFile><overwrite>false</overwrite>
      </configuration>
      
  3. 减少生成的方法

    • 通过配置 <table> 的属性,禁用不需要的方法。
    • 例如:
      <table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
      </table>
      

减少不必要的生成

  1. 分批生成

    • 将生成任务分成多个小任务,每次只生成一部分表。
    • 例如,创建多个 generatorConfig.xml 文件,每个文件负责一部分表的生成。
  2. 条件生成

    • 使用插件来实现条件生成逻辑,根据特定条件决定是否生成某些代码。
    • 例如,编写一个插件,在生成前检查某些条件,如果条件不满足则跳过生成。
  3. 缓存生成结果

    • 对于不经常变化的表结构,可以将生成的结果缓存起来,避免频繁生成。
    • 例如,将生成的代码文件存储在版本控制系统中,只有在表结构发生变化时才重新生成。

第七部分:最佳实践

在使用 MyBatis Generator 时,遵循一些最佳实践可以帮助你更好地管理代码、确保安全性,并提高开发效率。本部分将介绍代码管理、安全性考虑和持续集成的最佳实践。

代码管理

将配置文件纳入版本控制

  1. 配置文件版本化

    • generatorConfig.xml 文件纳入版本控制系统(如 Git),确保所有团队成员使用相同的配置。
    • 这有助于保持生成的代码一致性和可追溯性。
  2. 文档说明

    • 在项目文档中详细说明 generatorConfig.xml 的配置规则和注意事项,帮助新加入的团队成员快速上手。
  3. 定期审查

    • 定期审查 generatorConfig.xml 文件,确保其配置符合当前项目需求。
    • 可以通过代码审查工具(如 GitHub Pull Requests 或 GitLab Merge Requests)进行审查。

团队协作

  1. 统一规范

    • 制定统一的命名规范和编码风格,确保生成的代码风格一致。
    • 例如,统一表名和类名的命名规则,字段名称的转换规则等。
  2. 共享知识

    • 定期组织技术分享会,让经验丰富的开发者向团队成员传授 MyBatis Generator 的使用技巧和经验。
    • 创建内部知识库或 Wiki,记录常见问题及解决方案。
  3. 权限管理

    • 限制对 generatorConfig.xml 文件的修改权限,确保只有授权人员可以进行修改。
    • 使用版本控制系统中的分支管理和合并策略,避免冲突和误操作。
安全性考虑

防止 SQL 注入

  1. 使用参数化查询

    • 确保生成的 SQL 语句使用参数化查询,而不是直接拼接字符串。
    • MyBatis Generator 生成的代码默认使用参数化查询,但仍需注意手动编写的 SQL 语句。
  2. 输入验证

    • 对用户输入进行严格的验证和过滤,确保输入符合预期的格式和类型。
    • 例如,使用正则表达式或其他验证库来检查输入的有效性。
  3. 日志记录

    • 记录重要的数据库操作,并定期审查日志文件,及时发现异常行为。
    • 避免在错误消息中暴露过多的细节,这可能帮助攻击者进一步利用漏洞。

数据库权限管理

  1. 最小权限原则

    • 数据库用户应仅拥有执行其任务所需的最小权限。
    • 例如,如果一个应用程序只需要读取数据,则不要赋予其写入或删除数据的权限。
  2. 角色分离

    • 分离不同的数据库角色,确保每个角色只具有必要的权限。
    • 例如,创建专门用于读取数据的角色和专门用于写入数据的角色。
  3. 定期审计

    • 定期审查数据库用户的权限设置,确保没有不必要的权限。
    • 使用数据库自带的安全审计工具,监控和记录敏感操作。
持续集成

自动化生成

  1. 集成到 CI/CD 流程

    • 将 MyBatis Generator 集成到持续集成和持续部署流程中,确保每次构建时代码的一致性和最新性。
    • 例如,在 Jenkins 或 GitLab CI/CD 中配置自动运行 MyBatis Generator 的步骤。
  2. 定时生成

    • 设置定时任务,定期运行 MyBatis Generator 以更新生成的代码。
    • 例如,每天凌晨自动运行生成器,确保代码与数据库结构同步。

测试生成的代码

  1. 单元测试

    • 为生成的 Mapper 接口编写单元测试,确保生成的代码功能正确。
    • 使用 JUnit 或其他测试框架编写测试用例,覆盖基本的 CRUD 操作和其他自定义方法。
  2. 集成测试

    • 编写集成测试,验证生成的代码与数据库交互的正确性。
    • 使用测试数据库或内存数据库(如 H2)进行集成测试,确保测试环境与生产环境隔离。
  3. 代码覆盖率

    • 使用代码覆盖率工具(如 JaCoCo)监控测试覆盖率,确保生成的代码得到充分测试。
    • 定期审查代码覆盖率报告,找出未被测试的代码路径并补充测试用例。
  4. 静态代码分析

    • 使用静态代码分析工具(如 SonarQube)检查生成的代码质量。
    • 配置静态代码分析工具,自动检测潜在的问题和安全漏洞。

附录

在附录部分,我们将提供一些常用的配置示例和相关工具及资源链接,帮助你更方便地使用 MyBatis Generator。

常用配置示例

基本配置示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 数据库连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/your_database"userId="your_username"password="your_password"></jdbcConnection><!-- Java 模型生成目标包 --><javaModelGenerator targetPackage="com.yourpackage.model" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/></javaModelGenerator><!-- SQL 映射文件生成目标包 --><sqlMapGenerator targetPackage="com.yourpackage.mapper" targetProject="src/main/resources"><property name="enableSubPackages" value="true"/></sqlMapGenerator><!-- Mapper 接口生成目标包 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.yourpackage.mapper" targetProject="src/main/java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!-- 表配置 --><table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/></table>
</generatorConfiguration>

多数据库连接配置示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 数据库连接 1 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/your_database_1"userId="your_username_1"password="your_password_1"></jdbcConnection><!-- 数据库连接 2 --><jdbcConnection driverClass="org.postgresql.Driver"connectionURL="jdbc:postgresql://localhost:5432/your_database_2"userId="your_username_2"password="your_password_2"></jdbcConnection><!-- Java 模型生成目标包 --><javaModelGenerator targetPackage="com.yourpackage.model" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/></javaModelGenerator><!-- SQL 映射文件生成目标包 --><sqlMapGenerator targetPackage="com.yourpackage.mapper" targetProject="src/main/resources"><property name="enableSubPackages" value="true"/></sqlMapGenerator><!-- Mapper 接口生成目标包 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.yourpackage.mapper" targetProject="src/main/java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!-- 表配置 1 --><table tableName="users_1" domainObjectName="User1" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/></table><!-- 表配置 2 --><table tableName="users_2" domainObjectName="User2" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="PostgreSQL" identity="true"/></table>
</generatorConfiguration>

自定义插件配置示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 数据库连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/your_database"userId="your_username"password="your_password"></jdbcConnection><!-- Java 模型生成目标包 --><javaModelGenerator targetPackage="com.yourpackage.model" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/></javaModelGenerator><!-- SQL 映射文件生成目标包 --><sqlMapGenerator targetPackage="com.yourpackage.mapper" targetProject="src/main/resources"><property name="enableSubPackages" value="true"/></sqlMapGenerator><!-- Mapper 接口生成目标包 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.yourpackage.mapper" targetProject="src/main/java"><property name="enableSubPackages" value="true"/></javaClientGenerator><!-- 自定义插件 --><plugin type="com.yourpackage.CustomPlugin" /><!-- 表配置 --><table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/></table>
</generatorConfiguration>

自定义模板配置示例

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfigurationPUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN""http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration><!-- 数据库连接信息 --><jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"connectionURL="jdbc:mysql://localhost:3306/your_database"userId="your_username"password="your_password"></jdbcConnection><!-- Java 模型生成目标包 --><javaModelGenerator targetPackage="com.yourpackage.model" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="trimStrings" value="true"/><property name="templateFile" value="path/to/templates/JavaModel.vm"/></javaModelGenerator><!-- SQL 映射文件生成目标包 --><sqlMapGenerator targetPackage="com.yourpackage.mapper" targetProject="src/main/resources"><property name="enableSubPackages" value="true"/><property name="templateFile" value="path/to/templates/SqlMap.vm"/></sqlMapGenerator><!-- Mapper 接口生成目标包 --><javaClientGenerator type="XMLMAPPER" targetPackage="com.yourpackage.mapper" targetProject="src/main/java"><property name="enableSubPackages" value="true"/><property name="templateFile" value="path/to/templates/JavaMapper.vm"/></javaClientGenerator><!-- 表配置 --><table tableName="users" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"><generatedKey column="id" sqlStatement="MySql" identity="true"/></table>
</generatorConfiguration>

    结语


    1. 回顾核心价值

    通过本系列文章的学习,我们深入探讨了 MyBatis 这一灵活、高效的持久层框架,以及其代码生成工具 MyBatis Generator 的核心机制与实践技巧。以下是核心收获总结:

    • MyBatis 的核心优势

      • SQL 与代码解耦:通过 XML 或注解直接管理 SQL,兼顾灵活性与可维护性。
      • 动态 SQL 能力:借助 <if><foreach> 等标签,轻松应对复杂查询逻辑。
      • 高度可定制化:插件机制(Interceptor)支持扩展框架行为(如分页、性能监控)。
      • 与 Spring 生态无缝集成:通过 SqlSessionTemplate@MapperScan 简化配置。
    • MyBatis Generator 的实战意义

      • 自动化代码生成:快速生成实体类、Mapper 接口及 XML 文件,减少重复劳动。
      • 规范开发流程:统一代码风格,避免人工编码的潜在错误。
      • 支持自定义模板:通过修改模板文件(如 generatorConfig.ftl)适配个性化需求。

    2. 实战中的关键启示

    在入门与实战过程中,以下几个要点值得反复强调:

    1. 配置文件是核心
      • mybatis-config.xml 中全局配置(如缓存、类型处理器)需贴合项目需求。
      • generatorConfig.xml 的精准配置(数据源、生成策略)决定了代码生成的质量。
    2. 插件扩展与优化
      • 利用 MyBatis 插件实现 SQL 日志打印、分页逻辑封装。
      • 通过自定义 Generator 插件添加 Lombok 注解、Swagger 文档等实用功能。
    3. 避免过度依赖生成工具
      • 生成的代码需结合业务逻辑二次调整(如复杂关联查询、DTO 封装)。
      • 手动编写部分 SQL 以优化性能或实现特殊需求。

    3. 继续探索的方向

    MyBatis 和 MyBatis Generator 的深入学习永无止境。以下是进一步精进的建议:

    • 高级特性研究
      • 深入理解 一级缓存与二级缓存 的机制与适用场景。
      • 掌握 延迟加载(Lazy Loading) 的配置与性能优化。
    • 源码与插件开发
      • 阅读 MyBatis 核心源码(如 SqlSessionExecutor),理解执行流程。
      • 开发自定义插件,实现审计日志、数据脱敏等企业级功能。
    • 生态整合实践
      • 结合 Spring Boot 的 mybatis-spring-boot-starter 实现零配置快速集成。
      • 探索与分布式框架(如 MyBatis-Plus、ShardingSphere)的协同使用。

    4. 资源推荐
    • 官方文档
      • MyBatis 官方文档
      • MyBatis Generator 配置指南
    • 社区与工具
      • GitHub 开源项目:MyBatis 插件集合
      • 代码生成模板库:MyBatis Generator 自定义模板示例
    • 延伸阅读
      • 书籍:《MyBatis 从入门到精通》(刘增辉 著)
      • 博客系列:MyBatis 源码深度解析

    5. 最后的话

    技术的学习不仅是工具的掌握,更是设计思想与工程实践的融合。MyBatis 以其“轻量级”与“高可控性”,在 ORM 与原生 SQL 之间找到了完美平衡,而 MyBatis Generator 则进一步解放了开发者的生产力。

    鼓励行动

    • 立即尝试为你的项目引入 MyBatis Generator,感受自动化生成的便捷。
    • 在下一个需求中,尝试手写复杂 SQL 并优化其性能,体会 MyBatis 的灵活性。

    愿你在持久层开发的征途中,既能高效完成需求,又能深入技术本质,成为真正的“SQL 手艺人”!


    期待你的反馈与分享! 🌟

    相关文章:

    第四篇:[特殊字符] 深入理解MyBatis[特殊字符] 掌握MyBatis Generator ——入门与实战

    引言 什么是 MyBatis Generator&#xff1f; MyBatis Generator (MBG) 是一个代码生成工具&#xff0c;专为 MyBatis 框架设计。它可以根据数据库表结构自动生成 Java 实体类、Mapper 接口、Mapper XML 文件以及 Example 类。通过使用 MBG&#xff0c;开发者可以显著减少编写…...

    LeetCode算法题(Go语言实现)_48

    题目 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b; 值 1 代表新鲜橘子&#xff1b; 值 2 代表腐烂的橘子。 每分钟&#xff0c;腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回 直到单元格中…...

    ESP-ADF外设子系统深度解析:esp_peripherals组件架构与核心设计(核心API详解之单个外设管理)

    目录 单个外设管理APIesp_periph_createesp_periph_set_functionesp_periph_startesp_periph_stopesp_periph_set_dataesp_periph_get_dataesp_periph_get_stateesp_periph_get_idesp_periph_set_idesp_periph_initesp_periph_runesp_periph_destroy 单个外设管理API esp_peri…...

    基于vue2+ElementUI的el-tree封装一个带搜索的树形组件

    需求 实现一个如图带搜索框的下拉树形组件。 解决方案 利用el-inputel-tree实现自定义带搜索的下拉树形组件。 具体实现步骤 1、创建TreeSelect组件 <template><div class"tree-select-wrapper" v-clickoutside"handleClose"><el-inpu…...

    G2学习打卡

    &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 DCGAN实践 import torch, random, random, os import torch.nn as nn import torch.nn.parallel import torch.optim as optim import torch.utils.data im…...

    【广州华锐互动】汽车生产引入数字孪生系统,优化生产流程,提升汽车产品质量

    数字孪生系统的应用为企业带来了生产流程的革命性变革。以汽车制造企业为例&#xff0c;该企业在生产过程中引入数字孪生系统&#xff0c;实现了生产流程的全面优化和产品质量的显著提升 。​ 在生产流程优化方面&#xff0c;数字孪生系统对汽车生产线进行了全方位的模拟和实时…...

    从Gradio App创建Discord Bot/Slack Bot/Website Widget(2)——从Gradio App创建Slack Bot

    从Gradio App创建Discord Bot/Slack Bot/Website Widget&#xff08;2&#xff09;——从Gradio App创建Slack Bot 本篇摘要18. 从Gradio App创建Discord Bot/Slack Bot/Website Widget18.2 从Gradio App创建Slack Bot18.2.1 运作原理及前置条件1. 运作原理2. 前置条件 18.2.2 …...

    基于STM32G474的SPI获取MT6816编码器绝对角度配置指南

    前言&#xff1a;最近上手使用了一款编码器芯片&#xff0c;也是先艰难阅读了一下全英文版本的编码器的规格手册&#xff0c;然后通过SPI读取了一下绝对值角度。虽然发现使用起来还是挺简单的&#xff0c;但使用后还是会产生一个对其原理层面的好奇&#xff0c;比如磁编码器内部…...

    深入学习ReentrantLock

    ReentrantLock 0. 前言&#xff1a;为什么需要 ReentrantLock&#xff1f;1. 基础概念与核心特性1.1 什么是 ReentrantLock&#xff1f;1.2 ReentrantLock vs. synchronized1.3 核心特性详解1.3.1 可重入性 (Reentrancy)1.3.2 公平性选择 (Fairness Choice)1.3.3 可中断获取锁 …...

    Spring Boot 集成金蝶 API 演示

    ✨ Spring Boot 集成金蝶 API 演示&#xff1a;登录 / 注销 Cookie 保存 本文将通过 Spring Boot 完整实现一套金蝶接口集成模型&#xff0c;包括&#xff1a; ✅ 普通登录✅ AppSecret 登录✅ 注销✅ Cookie 保存与复用 &#x1f4c5; 项目结构 src/ ├── controller/ │…...

    适用于 HAL 的 AIDL

    目录 设计初衷 注意 编写AIDLHAL接口 查找AIDLHAL接口 扩展接口 将现有HAL从HIDL转换为AIDL AIDL与HIDL之间的主要差异 针对HAL的供应商测试套件(VTS)测试 Android 11 中引入了在 Android 中使用 AIDL 实现 HAL 的功能, 从而可以在不使用 HIDL 的情况下实现 Android 的部分…...

    49、Spring Boot 详细讲义(六)(SpringBoot2.x整合Mybatis实现CURD操作和分页查询详细项目文档)

    项目文档:银行借据信息CURD操作和分页查询 一、项目概述 1. 项目简介 本项目旨在使用Spring Boot框架整合MyBatis连接Mysql数据库实现借据信息的增加、删除、修改和查询功能,同时支持分页查询,并提供对应的Restful风格的接口。 2.环境准备 2.1.工具和软件准备 JDK(建议…...

    C# 运行web项目

    1、web项目直接点击顶部运行...

    GPU服务器声音很响可以怎么处理

    当GPU服务器运行时噪音过大&#xff0c;通常是由于高负载下散热风扇高速运转所致。以下是分步骤的解决方案&#xff0c;帮助您有效降低噪音并保持设备稳定运行&#xff1a; 一、排查噪音来源 定位声源 • 使用 声级计 或手机分贝检测APP&#xff0c;确定最大噪音位置&#xff0…...

    Java如何选择ojdbc驱动

    如何选择ojdbc驱动&#xff1f; 取决于短板。 如果JDK版本高&#xff0c;数据库版本低&#xff0c;根据Oracle数据库版本选择。如果JDK版本低&#xff0c;数据库版本高&#xff0c;根据Java版本选择。 Oracle官网OJDBC驱动和受支持的JDK版本 23ai 21c 19c 驱动类型选择 oj…...

    【微思就业推荐 】T岗位-北京,福州,厦门等地

    到微思学习&#xff0c;免费推荐就业&#xff01;学员内推&#xff01; 原创 厦门微思网络 2025年04月 有哪些大公司在招OCP认证人才&#xff1f; 有哪些大公司在招聘拥有HCIE认证的人才 ① 委托单位&#xff1a;润欣商业管理(厦门)有限公司 央企-华润资产的子公司 岗位&am…...

    Linux 命令全解析:从零开始掌握 Linux 命令行

    Linux 作为一款强大的开源操作系统&#xff0c;广泛应用于服务器、嵌入式系统以及超级计算机领域。掌握 Linux 命令行技能&#xff0c;是每一位开发者和系统管理员的必备能力。本文将从基础开始&#xff0c;为你详细介绍常用的 Linux 命令&#xff0c;以及它们的使用场景和示例…...

    2025年4月份生活有感

    今天在5000B培训的下午&#xff0c;一起入所来的小伙伴&#xff0c;有个申请了深圳大学的博士&#xff0c;已录取。哎&#xff0c;想起了当年申博时候信心和决心不足&#xff0c;导致后面匆匆的拿了offer去工作。看到同事的选择还是非常羡慕&#xff0c;想到自己5月份的婚礼&am…...

    鸿蒙系统开发状态更新字段区别对比

    在鸿蒙系统开发中&#xff0c;状态管理是构建响应式UI的核心机制&#xff0c;主要通过装饰器&#xff08;Decorators&#xff09;实现字段的状态观测与更新。根据鸿蒙的版本&#xff08;V1稳定版和V2试用版&#xff09;&#xff0c;支持的装饰器及其特性有所不同。以下是主要状…...

    CEPH OSD_SLOW_PING_TIME_FRONT/BACK 警告处理

    ceph config set mgr mon_warn_on_slow_ping_time 2000说明&#xff1a;mon_warn_on_slow_ping_time 该值默认为0&#xff0c;那么只要 osd 心跳超过 mon_warn_on_slow_ping_ratio of osd_heartbeat_grace. 也就是超过 mon_warn_on_slow_ping_ratio和mon_warn_on_slow_ping_rat…...

    HTML应用指南:利用POST请求获取全国小菜园门店位置信息

    小菜园作为一家以徽菜为主的快餐品牌&#xff0c;自2013年成立以来&#xff0c;凭借其独特的烹饪理念和精致的东方口味菜品&#xff0c;在中国市场上迅速崛起。该品牌强调少油少盐、减少调味品使用&#xff0c;旨在传承并发扬徽州风味的独特魅力。这种健康且不失美味的烹饪方式…...

    Python在去中心化物联网中的应用:数据安全、智能合约与边缘计算的融合

    Python在去中心化物联网中的应用:数据安全、智能合约与边缘计算的融合 在万物互联的时代,传统物联网(IoT)架构依赖于集中式服务器来管理数据、设备互联与身份认证。然而,随着设备数量激增,中心化架构的可扩展性、安全性和隐私问题逐渐暴露。去中心化物联网(DeIoT)通过…...

    CEPH配置优化建议

    一、硬件配置优化 磁盘选择&#xff1a; SSD 与 HDD 搭配&#xff1a;使用 SSD 作为 OSD 日志盘&#xff08;Journal&#xff09;或元数据存储&#xff0c;HDD 作为数据盘。推荐 SSD 与 HDD 的比例为 1:3~5&#xff0c;具体根据业务负载调整。 RAID 禁用&#xff1a;避免使用硬…...

    深度学习入门:神经网络的学习

    目录 1 从数据中学习1.1 数据驱动1.2 训练数据和测试数据 2损失函数2.1 均方误差2.2 交叉熵误差2.3 mini-batch学习2.4 mini-batch版交叉熵误差的实现2.5 为何要设定损失函数 3 数值微分3.1 数值微分3.3 偏导数 4 梯度4.1 梯度法4.2 神经网络的梯度 5 学习算法的实现5.1 2层神经…...

    机器学习_决策树

    决策树的特点 可以处理非线性的问题可解释强&#xff0c;没有θ模型简单&#xff0c;模型预测效率高 if else不容易显示的使用函数表达&#xff0c;不可微 决策树的生成和预测 生成&#xff1a;通过大量数据生成一颗非常好的树&#xff0c;用这棵树来预测新来的数据。 预测&…...

    深入理解UML动态图:系统行为建模全景指南

    目录 前言1. 动态图概述2. 用例图&#xff08;Use Case Diagram&#xff09;2.1 定义与作用2.2 应用价值2.3 实践建议 3. 顺序图&#xff08;Sequence Diagram&#xff09;3.1 定义与特征3.2 应用优势3.3 建模建议 4. 活动图&#xff08;Activity Diagram&#xff09;4.1 定义与…...

    Linux驱动开发进阶(九)- SPI子系统BSP驱动

    文章目录 1、前言2、SPI总线注册3、SPI设备注册4、SPI驱动注册5、SPI BSP驱动 1、前言 学习参考书籍以及本文涉及的示例程序&#xff1a;李山文的《Linux驱动开发进阶》本文属于个人学习后的总结&#xff0c;不太具备教学功能。 2、SPI总线注册 驱动源码文件&#xff1a;dri…...

    wabpack学习记录

    wabpack学习记录 前言 项目写了不少 对webpack了解甚少 只记住一些 必要的概念以及指令 所以像深究一下具体是什么 可以做什么 如何做等 package.json 文件详解 name: 项目的名称。 version: 项目的版本号。 description: 项目的描述。 author: 项目的作者或维护者信息。 l…...

    计算机视觉——基于 Yolov8 目标检测与 OpenCV 光流实现目标追踪

    1. 概述 目标检测&#xff08;Object Detection&#xff09;和目标追踪&#xff08;Object Tracking&#xff09;是计算机视觉中的两个关键技术&#xff0c;它们在多种实际应用场景中发挥着重要作用。 目标检测指的是在静态图像或视频帧中识别出特定类别的目标对象&#xff0…...

    React 更新 state 中的数组

    更新 state 中的数组 数组是另外一种可以存储在 state 中的 JavaScript 对象&#xff0c;它虽然是可变的&#xff0c;但是却应该被视为不可变。同对象一样&#xff0c;当你想要更新存储于 state 中的数组时&#xff0c;你需要创建一个新的数组&#xff08;或者创建一份已有数组…...

    [250415] OpenAI 推出 GPT-4.1 系列,支持 1M token

    目录 OpenAI 推出 GPT-4.1 系列 OpenAI 推出 GPT-4.1 系列 OpenAI 宣布&#xff0c;新一代 GPT-4.1 模型系列正式发布&#xff0c;包括 GPT-4.1, GPT-4.1 mini 和 GPT-4.1 nano 三款模型&#xff0c;该系列模型在各项性能指标上全面超越 GPT-4o 和 GPT-4o mini&#xff0c;尤其…...

    分布式锁+秒杀异步优化

    文章目录 问题思路setnx实现锁误删问题和解决方案Redis Lua脚本问题引出解决方案 setnx实现的问题Redission快速入门redission可重入锁原理 秒杀优化(异步优化)异步秒杀思路秒杀资格判断Redis消息队列 问题 比如我们两个机器都部署了我们项目&#xff0c;这里nginx使用轮询的方…...

    数据服务化 VS 数据中台:战略演进中的价值重构

    在企业数据战略的演进历程中&#xff0c;数据中台曾被视为解决数据孤岛的 “万能钥匙”&#xff0c;而数据服务化的兴起则标志着企业从 “数据资源囤积” 向 “数据价值释放” 的深刻转型。两者的核心差异不仅在于技术架构&#xff0c;更在于对数据资产的定位与使用理念的根本分…...

    PL/SQL登录慢,程序连接Oracle 提示无法连接或无监听

    PL/SQL登录慢&#xff0c;程序连接Oracle 提示无法连接或无监听 错误提示&#xff1a;ORA-12541: TNS: 无监听程序 的解决办法&#xff0c; 现象&#xff1a;PL/SQL登录慢&#xff0c;程序连接Oracle 提示无法连接或无监听 监听已经正常开起&#xff0c;但还是PL/SQL登录慢或…...

    【JAVAFX】自定义FXML 文件存放的位置以及使用

    情况 1&#xff1a;FXML 文件与调用类在同一个包中&#xff08;推荐&#xff09; 假设类 MainApp 的包是 com.example&#xff0c;且 FXML 文件放在 resources/com/example 下&#xff1a; 项目根目录 ├── src │ └── sample │ └── Main.java ├── src/s…...

    DDoS(分布式拒绝服务)攻击

    DDoS(分布式拒绝服务)攻击 这是一份全面系统的 DDoS&#xff08;分布式拒绝服务攻击&#xff09;知识总结&#xff0c;适合用于学习、报告、讲稿或者面试准备。内容涵盖定义、原理、危害、利用、工具、防护策略等。 一、什么是DDoS DDoS&#xff08;Distributed Denial of Se…...

    scikit-learn初探

    KFold k交叉验证&#xff0c;k-1个作为训练集&#xff0c;剩下的作为测试集 split split(X, yNone, groupsNone)X&#xff1a; (n_samples, n_features)的矩阵&#xff0c;行数为n_samples&#xff0c;列数为n_features y&#xff1a;(n_samples,)为列向量&#xff0c;表示监…...

    深入解析 sklearn 中的多种特征编码方式:功能、适用场景与选择建议

    标题&#xff1a;深入解析 sklearn 中的多种特征编码方式&#xff1a;功能、适用场景与选择建议 摘要&#xff1a; 在机器学习中&#xff0c;特征编码是数据预处理的重要环节&#xff0c;直接影响模型的性能和效果。本文详细介绍了 sklearn 及其生态中&#xff08;含第三方库…...

    windows10 wsl2 安装ubuntu和docker

    见 弃用Docker Desktop&#xff1a;在WSL2中玩转Docker之Docker Engine 部署与WSL入门-阿里云开发者社区 如果启动docker时报下面这个错&#xff0c; 那是因为systemctl没有启用 sudo systemctl start docker System has not been booted with systemd as init system (PID 1)…...

    一文读懂WPF系列之依赖属性与附加属性

    依赖属性与附加属性 依赖属性对比C#属性WPF依赖属性&#xff08;Dependency Properties&#xff09;优先级计算与值决策​​回调与验证机制​​WPF 自带的依赖属性自定义依赖属性 附加属性本质与定义​​与依赖属性的区别​​附加属性的典型应用场景自定义附加属性注意事项 属性…...

    1×1卷积与GoogleNet

    11卷积 卷积核的尺寸等于1的卷积核 11卷积有什么用 1. 通道混合与特征转换 背景&#xff1a;在卷积神经网络中&#xff0c;输入数据通常有多个通道&#xff08;例如RGB图像有3个通道&#xff0c;经过卷积层后通道数可能会增加&#xff09;。不同通道的特征图可能包含了不同的…...

    Handsontable 表格组件的使用

    文章目录 1. 安装 Handsontable2. 创建一个基本表格3. 主要配置3.1、 data 数据3.2、 columns 指定列配置 4. Handsontable 高级功能4.1、 添加排序4.2、 过滤数据4.3、 选中行高亮4.4、 只读单元格4.5、 校验数据 5. Handsontable 与 Vue结合6. 总结 Handsontable 是一个强大的…...

    消息中间件面试题

    前言 本章内容来自B站黑马程序员java大厂面试题与小林coding 如有侵权立即删除 博主学习笔记&#xff0c;如果有不对的地方&#xff0c;海涵。 如果这篇文章对你有帮助&#xff0c;可以点点关注&#xff0c;点点赞&#xff0c;谢谢你&#xff01; 1.通用篇 1.1 什么是消息…...

    数据结构与算法--1.判断数组中元素是否有重复

    在C语言中&#xff0c;我们可以使用类似的方法来实现判断数组中是否有重复值的功能。由于C语言没有内置的哈希集合&#xff08;如Python的set或C的unordered_set&#xff09;&#xff0c;我们需要自己实现一个简单的哈希表或使用其他方法。 方法一&#xff1a;暴力法&#xff…...

    硬件工程师面试常见问题(1)

    第一问&#xff1a;单片机上电后没有运转&#xff0c;首先要检查什么&#xff1f; &#xff08;1&#xff09;单片机供电是否正常& 电路焊接检查 用万用表测量对应引脚的供电电压&#xff0c;检查对不对。 &#xff08;2&#xff09;单片机复位是否释放 用万用表测量复位引…...

    测试100问:web测试和APP测试的区别

    哈喽&#xff0c;大家好&#xff0c;我是十二&#xff0c;那今天要为大家分享的是高频面试题&#xff1a;web测试和 App测试的区别。 从功能测试方面来讲&#xff0c;web测试和 App测试在测试的流程以及测试用例的设计上是没有区别的&#xff0c;那主要的区别包含以下三个方面&…...

    Leetcode 3518. Smallest Palindromic Rearrangement II

    Leetcode 3518. Smallest Palindromic Rearrangement II 1. 解题思路2. 代码实现 题目链接&#xff1a;Leetcode 3518. Smallest Palindromic Rearrangement II 1. 解题思路 这一题是题目Leetcode 3517. Smallest Palindromic Rearrangement I的升级版本&#xff0c;其主要的…...

    Golang|订单相关

    文章目录 秒杀写库策略确保缓存的订单数据不丢失 秒杀写库策略 在我们的抽奖函数中&#xff0c;抽中奖品、减库存成功返回给前端后就应该生成订单写入数据库 但是这里有问题&#xff0c;我们的抽奖函数是支持高并发的&#xff0c;并发量大的情况下mysql无法支持这么大并发量的写…...

    Python+Playwright:编写自动化测试的避坑策略

    PythonPlaywright&#xff1a;编写自动化测试的避坑策略 前言一、告别 time.sleep()&#xff0c;拥抱 Playwright 的智能等待二、选择健壮、面向用户的选择器&#xff0c;优先使用 data-testid三、严格管理环境与依赖&#xff0c;确保一致性四、分离测试数据与逻辑&#xff0c;…...

    P12130 [蓝桥杯 2025 省 B] 移动距离

    P12130 [蓝桥杯 2025 省 B] 移动距离 - 洛谷 题目描述 小明初始在二维平面的原点&#xff0c;他想前往坐标 (233, 666)。在移动过程中&#xff0c;他只能采用以下两种移动方式&#xff0c;并且这两种移动方式可以交替、不限次数地使用&#xff1a; 水平向右移动&#xff0c;…...