【JavaWeb后端开发04】java操作数据库(JDBC + Mybatis+ yml格式)详解

news2025/4/25 19:18:41

文章目录

    • 1. 前言
    • 2. JDBC
      • 2.1 介绍
      • 2.2 入门程序
        • 2.2.1 DataGrip
        • 2.2.2 在IDEA执行sql语句
      • 2.3 查询数据案例
        • 2.3.1 需求
        • 2.3.2 准备工作
        • 2.3.3 AI代码实现
        • 2.3.4 代码剖析
          • 2.3.4.1 ResultSet
          • 2.3.4.2 预编译SQL
            • 2.3.4.2.1 SQL注入
            • 2.3.4.2.2 SQL注入解决
            • 2.3.4.2.3 性能更高
      • 2.4 增删改数据
        • 2.4.1 需求
        • 2.4.2 代码实现
    • 3. Mybatis
      • 3.1 介绍
        • 3.1.1 快速入门
        • 3.1.2 辅助配置
          • 3.1.2.1 配置SQL提示
          • 3.1.2.2 配置Mybatis日志输出
        • 3.1.3 JDBC VS Mybatis
        • 3.1.4 数据库连接池
          • 3.1.4.1 介绍
          • 3.1.4.2 产品
        • 3.1.5 增删改查操作
          • 3.1.5.1 删除
          • 3.1.5.2 新增
          • 3.1.5.3 修改
          • 3.1.5.4 查询(带条件)
        • 3.1.6 XML映射配置
          • 3.1.6.1 XML配置文件规范
          • 3.1.6.2 XML配置文件实现
          • 3.1.6.3 MybatisX的使用
    • 4. SpringBoot配置文件
      • 4.1 介绍
      • 4.2 语法
      • 4.3 案例


1. 前言

在前面我们学习MySQL数据库时,都是利用图形化客户端工具(如:idea、datagrip),来操作数据库的。

我们做为后端程序开发人员,通常会使用Java程序来完成对数据库的操作。Java程序操作数据库的技术呢,有很多啊,而最为底层、最为基础的就是JDBC。

JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。 【是操作数据库最为基础、底层的技术】

但是使用JDBC来操作数据库,会比较繁琐,所以现在在企业项目开发中呢,一般都会使用基于JDBC的封装的高级框架,比如:Mybatis、MybatisPlus、Hibernate、SpringDataJPA。

而这些技术,目前的市场占有份额如下图所示:

从上图中,我们也可以看到,目前最为主流的就是Mybatis,其次是MybatisPlus。

内容:

  1. JDBC

  2. Mybatis

  3. SpringBoot配置文件

2. JDBC

2.1 介绍

JDBC:(Java DataBase Connectivity),就是使用Java语言操作关系型数据库的一套API。

本质:

  • sun公司官方定义的一套操作所有关系型数据库的规范,即接口

  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包。

  • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

那有了JDBC之后,我们就可以直接在java代码中来操作数据库了,只需要编写这样一段java代码,就可以来操作数据库中的数据。 示例代码如下:

2.2 入门程序

需求:基于JDBC,执行更新数据库数据语句

image-20250421164903758

2.2.1 DataGrip

创建数据表

create table user(
    id int unsigned primary key auto_increment comment 'ID,主键',
    username varchar(20) comment '用户名',
    password varchar(32) comment '密码',
    name varchar(10) comment '姓名',
    age tinyint unsigned comment '年龄'
) comment '用户表';

insert into user(id, username, password, name, age) values (1, 'daqiao', '123456', '大乔', 22),
                                                           (2, 'xiaoqiao', '123456', '小乔', 18),
                                                           (3, 'diaochan', '123456', '貂蝉', 24),
                                                           (4, 'lvbu', '123456', '吕布', 28),
                                                           (5, 'zhaoyun', '12345678', '赵云', 27);
   

image-20250421171247331


2.2.2 在IDEA执行sql语句

导入依赖

    <dependencies>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.9.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
    </dependencies>
  1. mysql-connector-j (MySQL 连接器)

    用途:这是 MySQL 数据库的 JDBC 驱动程序,它允许 Java 程序与 MySQL 数据库进行连接和交互。

    功能:通过这个依赖,Java 程序可以使用 JDBC(Java Database Connectivity)接口与 MySQL 数据库进行数据操作(如查询、更新、删除等)。

  2. junit-jupiter (JUnit 测试框架)

    用途:这是 JUnit 5 的核心库,提供了用于编写和执行单元测试的功能。junit-jupiter 是 JUnit 5 框架的一部分,包含了新的测试注解和断言方法。

    功能:它允许开发人员编写单元测试,以确保代码的正确性。JUnit 5 允许使用如 @Test 注解标记测试方法,支持断言(如 assertEquals()assertTrue())来验证预期结果。

  3. lombok (Lombok 库)

用途:Lombok 是一个 Java 库,通过注解自动生成常见的 Java 代码(如 getter、setter、toString 方法等),减少了代码冗余。

功能:它通过注解(如 @Getter@Setter@ToString@EqualsAndHashCode)自动为类生成常见的方法,简化了 Java 类的编写。使用 Lombok,开发者不需要手动编写大量样板代码,可以让代码更加简洁、清晰。

更新代码

import com.mysql.cj.jdbc.Driver;
import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class JdbcTest {
    /**
     * Jdbc入门程序
     */
    @Test
    public void testUpdate() throws Exception {
        //1.注册驱动
        Class.forName("com.mysql.cj.jdbc.Driver");
        //2.获取数据库连接
        String url = "jdbc:mysql://localhost:3306/web01";
        String username = "root";
        String password = "0524";
        Connection connection = DriverManager.getConnection(url, username, password);
        //3.获取sql语句的执行对象
        Statement statement = connection.createStatement();
        //4.执行SQL
        int i = statement.executeUpdate("update user set age = 25 where id = 1");
        System.out.println("SQL执行完毕影响记录数为:" + i);

        //5.释放资源
        statement.close();
        connection.close();
    }
}

  1. 注册驱动

    Class.forName():是 Java 反射机制中的一个方法,作用是加载并初始化指定类。Class.forName() 会通过类的全限定名(包括包名)加载指定的类,并且会执行该类的静态初始化块。

    "com.mysql.cj.jdbc.Driver":是 MySQL JDBC 驱动类的全限定类名(包括包名)。它是 MySQL 的驱动程序类,负责将 Java 程序与 MySQL 数据库之间的通信进行处理。获取数据库连接

    connection = DriverManager.getConnection使用connection进行数据库连接,需要url地址、用户、密码

    "jdbc:mysql://localhost:3306/web01";:

    • jdbc:mysql://:这是 JDBC (Java Database Connectivity) 的协议部分,表示这是一个 MySQL 数据库连接。
    • localhost:这是数据库的主机名,表示数据库在本地计算机上运行。
    • 3306:这是 MySQL 数据库的默认端口号,表示数据库服务监听的端口。
    • web01:这是数据库的名称,表示要连接的数据库是名为 web01 的数据库。
  2. 获取sql语句执行对象

    statement执行更新sql语句,并返回影响几条记录(int)

  3. 执行SQL语句

    • executeUpdate用于执行修改数据库内容的 SQL 语句(如 INSERTUPDATEDELETE)。

    • executeQuery用于执行选择SELECT语句,查询数据库并返回结果集ResultSet,下一节会用到

      ResultSet rs = statement.executeQuery("SELECT * FROM users");
      
      
    • execute():执行任何 SQL 语句,无论是否返回结果集。该方法适用于 SELECTINSERTUPDATEDELETE 等多种语句。

      返回值:返回一个布尔值,指示执行的 SQL 是否返回一个结果集。

  4. 执行完毕释放资源

    statement.close();connection.close(); 用于关闭数据库连接和声明,以确保资源得到妥善释放。

    • 如果不关闭 statement,可能会导致资源泄漏,特别是对于数据库连接的声明,可能会影响性能和稳定性。
    • 数据库连接是宝贵的资源,如果不及时关闭connection,可能会耗尽数据库连接池的可用连接,导致系统性能下降或连接异常。

最终结果

image-20250421171441217


2.3 查询数据案例

2.3.1 需求

image-20250421174100658

需求:基于JDBC实现用户登录功能。用户登录就是你输入的账号名和密码可以在数据库中使用SELECT语句查询到,能查到就放你登录

本质:其本质呢,其实就是基于JDBC程序,执行如下select语句,并将查询的结果输出到控制台。SQL语句:

select * from user where username = 'linchong' and password = '123456';
2.3.2 准备工作

1). 创建一个maven项目

2). 创建一个数据库 web,并在该数据库中创建user表

create table user(
    id int unsigned primary key auto_increment comment 'ID,主键',
    username varchar(20) comment '用户名',
    password varchar(32) comment '密码',
    name varchar(10) comment '姓名',
    age tinyint unsigned comment '年龄'
) comment '用户表';

insert into user(id, username, password, name, age) values (1, 'daqiao', '123456', '大乔', 22),
                                                           (2, 'xiaoqiao', '123456', '小乔', 18),
                                                           (3, 'diaochan', '123456', '貂蝉', 24),
                                                           (4, 'lvbu', '123456', '吕布', 28),
                                                           (5, 'zhaoyun', '12345678', '赵云', 27);
2.3.3 AI代码实现

AI提示语句

你是一名java开发工程师,帮我基于JDBC程序来操作数据库,执行如下SQL语句:select id,username,password,name,age from user where username = ‘daqiao’ and password = ‘123456’;
并将查询的每一行记录,都封装到实体类User中,然后将User对象的数据输出到控制台中。
User 实体类属性如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id; //ID
private String username; //用户名
private String password; //密码
private String name; //姓名
private Integer age; //年龄
}

具体的代码为:

1). 在 pom.xml 文件中引入依赖

<dependencies>
    <!-- MySQL JDBC driver -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.30</version>
    </dependency>

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.9.3</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2). 在 src/main/test/java 目录下编写测试类,定义测试方法

从 JDBC 4.0 开始,Java 对 JDBC 驱动程序进行了改进,允许驱动程序自动注册。也就是说,只要你把适当的 JDBC 驱动 JAR 包(例如 mysql-connector-java)添加到项目的 classpath 中,JDBC 驱动会自动加载,无需显式地调用 Class.forName() 来加载驱动。

    @Test
    public void testSelect() throws Exception {
        //获取连接
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/web01","root","0524");
        //创建预编译的PreparedStatement对象
        PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM user WHERE username = ? and password = ?");
        //设置参数
        pstmt.setString(1,"daqiao");
        pstmt.setString(2,"123456");
        //执行查询
        ResultSet rs = pstmt.executeQuery();
        //处理解析返回的数据
        while(rs.next()){
            int id = rs.getInt("id");
            String username = rs.getString("username");
            String password = rs.getString("password");
            String name = rs.getString("name");
            int age = rs.getInt("age");
            System.out.println(id + " " + username + " " + password + " " + name + " " + age);
        }
        //释放资源
        rs.close();
        pstmt.close();
        connection.close();
    }

}

下一节会讲解返回值rs处理部分

输出结果

image-20250421182848463

而上述的单元测试中,我们在SQL语句中,将将 用户名 和密码的值都写死了,而这两个值应该是动态的,是将来页面传递到服务端的。 那么,我们可以基于前面所讲解的JUnit中的参数化测试进行单元测试,代码改造如下:

public class JDBCTest {

    /**
     * 编写JDBC程序, 查询数据
     */
    @ParameterizedTest
    @CsvSource({"daqiao,123456"})
    public void testJdbc(String _username, String _password) throws Exception {
        // 获取连接
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web", "root", "1234");
        // 创建预编译的PreparedStatement对象
        PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM user WHERE username = ? AND password = ?");
        // 设置参数
        pstmt.setString(1, _username); // 第一个问号对应的参数
        pstmt.setString(2, _password); // 第二个问号对应的参数
        // 执行查询
        ResultSet rs = pstmt.executeQuery();
        // 处理结果集
        while (rs.next()) {
            int id = rs.getInt("id");
            String uName = rs.getString("username");
            String pwd = rs.getString("password");
            String name = rs.getString("name");
            int age = rs.getInt("age");

            System.out.println("ID: " + id + ", Username: " + uName + ", Password: " + pwd + ", Name: " + name + ", Age: " + age);
        }
        // 关闭资源
        rs.close();
        pstmt.close();
        conn.close();
    }

}

如果在测试时,需要传递一组参数,可以使用 @CsvSource 注解。

image-20250421174319825

2.3.4 代码剖析
2.3.4.1 ResultSet

ResultSet(结果集对象):封装了DQL查询语句查询的结果

  • next():将光标从当前位置向前移动一行,并判断当前行是否为有效行,返回值为boolean。

    • true:有效行,当前行有数据

    • false:无效行,当前行没有数据

    • 所以可以while循环逐行读取数据,直到为空结束

  • getXxx(…):获取数据,可以根据列的编号获取,也可以根据列名获取(推荐)。

结果解析步骤:

2.3.4.2 预编译SQL

其实我们在编写SQL语句的时候,有两种风格:

  • 静态SQL(参数硬编码)
conn.prepareStatement("SELECT * FROM user WHERE username = 'daqiao' AND password = '123456'");
ResultSet resultSet = pstmt.executeQuery();

这种呢,就是参数值,直接拼接在SQL语句中,参数值是写死的。

  • 预编译SQL(参数动态传递)
conn.prepareStatement("SELECT * FROM user WHERE username = ? AND password = ?");
pstmt.setString(1, "daqiao");
pstmt.setString(2, "123456");
ResultSet resultSet = pstmt.executeQuery();

这种呢,并未将参数值在SQL语句中写死,而是使用 ? 进行占位,然后再指定每一个占位符对应的值是多少,而最终在执行SQL语句的时候,程序会将SQL语句(SELECT * FROM user WHERE username = ? AND password = ?),以及参数值(“daqiao”, “123456”)都发送给数据库,然后在执行的时候,会使用参数值,将?占位符替换掉。

那这种预编译的SQL,也是在项目开发中推荐使用的SQL语句。主要的作用有两个:

  • 防止SQL注入,更加安全

  • 性能更高

那接下来,我们就来介绍一下这两点。

2.3.4.2.1 SQL注入
  • SQL注入:通过控制输入来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法。

SQL注入最典型的场景,就是用户登录功能。

注入演示:

1). 打开资料中的文件夹 资料/02. SQL注入演示,运行其中的jar包 sql_Injection_demo-0.0.1-SNAPSHOT.jar,进入该目录后,执行命令:

java -jar sql_Injection_demo-0.0.1-SNAPSHOT.jar

2). 打开浏览器访问 http://localhost:9090/ ,必须登录后才能访问到系统。我们先测试正常的用户名和密码

3). 接下来,我们再来测试一下错误的用户名和密码 。

我们看到,如果用户名密码错误,是不能进入到系统中进行访问的,会提示 用户名和密码错误

4). 那接下来,我们就要演示一下SQL注入现象,我们可以通过控制表单输入,来修改事先定义好的SQL语句的含义。 从而来攻击服务器。

点击登录后,我们看到居然可以成功进入到系统中。

为什么会出现这种现象呢?

在进行登录操作时,怎么样才算登录成功呢? 如果我们查询到了数据,就说明用户名密码是对的。 如果没有查询到数据,就说明用户名或密码错误。

而出现上述现象,原因就是因为,我们我们编写的SQL语句是基于字符串进行拼接的 。 我们输入的用户名无所谓,比如:shfhsjfhja ,而密码呢,就是我们精心设计的,如:' or '1' = '1

那最终拼接的SQL语句,如下所示:

我们知道,or 连接的条件,是或的关系,两者满足其一就可以。 所以,虽然用户名密码输入错误,也是可以查询返回结果的,而只要查询到了数据,就说明用户名和密码是正确的。

2.3.4.2.2 SQL注入解决

而通过预编译SQL(select * from user where username = ? and password = ?),就可以直接解决上述SQL注入的问题。 接下来,我们再来演示一下,通过预编译SQL是否能够解决SQL注入问题。

1). 打开资料中的文件夹 资料/02. SQL注入演示,运行其中的jar包 sql_prepared_demo-0.0.1-SNAPSHOT.jar,进入该目录后,执行命令:

java -jar sql_prepared_demo-0.0.1-SNAPSHOT.jar

2). 打开浏览器访问 http://localhost:9090/ ,必须登录后才能访问到系统 。我们先测试正常的用户名和密码

3). 那接下来,我们就要演示一下是否可以基于上述的密码 ' or '1' = '1,来完成SQL注入 。

通过控制台,可以看到输入的SQL语句,是预编译SQL语句。

而在预编译SQL语句中,当我们执行的时候,会把整个' or '1'='1作为一个完整的参数,赋值给第2个问号(' or '1'='1进行了转义,只当做字符串使用)

那么此时再查询时,就查询不到对应的数据了,登录失败。

注意:在以后的项目开发中,我们使用的基本全部都是预编译SQL语句。

2.3.4.2.3 性能更高

数据库会把以前用过的sql语句直接到缓存里面拿(数据库内存),不需要在重新进行语法检查 — 编译。

2.4 增删改数据

2.4.1 需求
  • 需求:基于JDBC程序,执行如下update语句。

  • SQL:

update user set password = '123456', gender = 2 where id = 1;
2.4.2 代码实现

AI提示词(prompt):

你是一名java开发工程师,帮我基于JDBC程序来操作数据库,执行如下SQL语句:

update user set password = ‘123456’, gender = 2 where id = 1;

代码实现如下:

@ParameterizedTest
@CsvSource({"1,123456,25"})
public void testUpdate(int userId, String newPassword, int newAge) throws Exception {
    // 建立数据库连接
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web", "root", "1234");
    // SQL 更新语句
    String sql = "UPDATE user SET password = ?, age = ? WHERE id = ?";
    // 创建预编译的PreparedStatement对象
    PreparedStatement pstmt = conn.prepareStatement(sql);

    // 设置参数
    pstmt.setString(1, newPassword); // 第一个问号对应的参数
    pstmt.setInt(2, newAge);      // 第二个问号对应的参数
    pstmt.setInt(3, userId);         // 第三个问号对应的参数

    // 执行更新
    int rowsUpdated = pstmt.executeUpdate();

    // 输出结果
    System.out.println(rowsUpdated + " row(s) updated.");

    // 关闭资源
    pstmt.close();
    conn.close();
}
  • JDBC程序执行DML语句:int rowsUpdated = pstmt.executeUpdate(); //返回值是影响的记录数

  • JDBC程序执行DQL语句:ResultSet resultSet = pstmt.executeQuery(); //返回值是查询结果集

image-20250421175619256

3. Mybatis

3.1 介绍

什么是MyBatis?

  • MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发。

  • MyBatis本是 Apache的一个开源项目iBatis,2010年这个项目由apache迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

  • 官网:https://mybatis.org/mybatis-3/zh/index.html

在上面我们提到了两个词:一个是持久层,另一个是框架。

  • 持久层:指的是就是数据访问层(dao),是用来操作数据库的。

  • 框架:是一个半成品软件,是一套可重用的、通用的、软件基础代码模型。在框架的基础上进行软件开发更加高效、规范、通用、可拓展。

通过Mybatis就可以大大简化原生的JDBC程序的代码编写,比如 通过 select * from user 查询所有的用户数据,通过JDBC程序操作呢,需要大量的代码实现,而如果通过Mybatis实现相同的功能,只需要简单的三四行就可以搞定。

3.1.1 快速入门

需求:使用Mybatis查询所有用户数据 。

image-20250421213027553

1). 创建springboot工程,并导入 mybatis的起步依赖、mysql的驱动包、lombok。

项目工程创建完成后,自动在pom.xml文件中,导入Mybatis依赖和MySQL驱动依赖。如下所示:

2). 数据准备:创建用户表user,并创建对应的实体类User。

image-20250421212934118

//User类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Integer age;
}

3). 配置Mybatis

application.properties 中配置数据库的连接信息,数据库连接四要素,只需定义一次。

#数据库访问的url地址
spring.datasource.url=jdbc:mysql://localhost:3306/web01
#数据库驱动类类名
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#访问数据库-用户名
spring.datasource.username=root
#访问数据库-密码
spring.datasource.password=root@0524

上述的配置,可以直接复制过去,不要敲错了。 全部都是 spring.datasource.xxxx 开头。

4). 编写Mybatis程序:编写Mybatis的持久层接口,定义SQL语句(注解)

在创建出来的springboot工程中,在引导类所在包下,在创建一个包 mapper 。在 mapper 包下创建一个接口 UserMapper ,这是一个持久层接口(Mybatis的持久层接口规范一般都叫 XxxMapper,也叫做Mapper接口)。

UserMapper接口的内容如下:

import com.cyanm.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

@Mapper  // 应用程序在运行时,会自动的为该接口创建一个实现类对象(动态代理对象),并且会自动地将该实现类对象存入IOC容器中 - bean
public interface UserMapper {
    @Select("select * from user")
    public List<User> findAll();
}

注解说明:

  • @Mapper注解:表示是mybatis中的Mapper接口

程序运行时,框架会自动生成接口的实现类对象(代理对象),并给交Spring的IOC容器管理

  • @Select注解:代表的就是select查询,用于书写select查询语句

5). 单元测试

在创建出来的SpringBoot工程中,在src下的test目录下,已经自动帮我们创建好了测试类 ,并且在测试类上已经添加了注解 @SpringBootTest,代表该测试类已经与SpringBoot整合。

该测试类在运行时,会自动通过引导类加载Spring的环境(IOC容器)。我们要测试那个bean对象,就可以直接通过@Autowired注解直接将其注入进行,然后就可以测试了。

测试类代码如下:

import com.cyanm.mapper.UserMapper;
import com.cyanm.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

@SpringBootTest // SpringBoot中单元测试的注解 - 当前测试类中的测试方法运行时,会启动springboot项目 - IOC容器就创建好了
class SpringbootMybatisQuickstartApplicationTests {
    //注入UserMapper对象
    @Autowired
    private UserMapper userMapper;

    @Test
    void contextLoads() {
        //调用方法
        List<User> userList = userMapper.findAll();
        userList.forEach(System.out::println);
    }
}

运行结果:

注意:测试类所在包,需要与引导类/启动类所在包相同。

image-20250421215529711

image-20250421215025356

Spring Boot的包扫描机制

Spring Boot的核心特性之一是其自动配置和组件扫描机制。在应用启动时,Spring Boot会根据引导类的位置进行包扫描。具体来说:

  • 扫描范围:Spring Boot会从引导类所在的包开始,递归扫描该包及其所有子包。
  • 扫描目标:扫描过程中,Spring Boot会查找并注册所有带有特定注解的类,例如:
    • @Component(及其派生注解,如@Service@Repository@Controller等)
    • @Mapper(MyBatis中用于标记Mapper接口的注解)
    • 其他Spring支持的注解
  • 目的:通过这种机制,Spring Boot能够自动将这些类注册为Spring容器中的Bean,从而在应用运行时可以直接注入和使用。

例如,如果引导类位于com.example.demo包中,Spring Boot会扫描com.example.demo及其子包(如com.example.demo.mappercom.example.demo.service等),但不会扫描com.example.test这样的外部包。


3.1.2 辅助配置
3.1.2.1 配置SQL提示

默认我们在UserMapper接口上加的 @Select 注解中编写SQL语句是没有提示的。 如果想让idea给我们提示对应的SQL语句,我们需要在IDEA中配置与MySQL数据库的链接。

默认我们在UserMapper接口上的 @Select 注解中编写SQL语句是没有提示的。如果想让idea给出提示,可以做如下配置:

配置完成之后,发现SQL语句中的关键字有提示了,但还存在不识别表名(列名)的情况:

  • 产生原因:Idea和数据库没有建立连接,不识别表信息

  • 解决方案:在Idea中配置MySQL数据库连接

按照如下方如下方式,来配置当前IDEA关联的MySQL数据库(必须要指定连接的是哪个数据库)。

在配置的时候指定连接那个数据库,如上图所示连接的就是mybatis数据库(自己的数据库名是什么就指定什么)。

注意:该配置的目的,仅仅是为了在编写SQL语句时,有语法提示(写错了会报错),不会影响运行,即使不配置也是可以的。

3.1.2.2 配置Mybatis日志输出

默认情况下,在Mybatis中,SQL语句执行时,我们并看不到SQL语句的执行日志。 在application.properties加入如下配置,即可查看日志:

#mybatis的配置
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

打开上述开关之后,再次运行单元测试,就可以看到控制台输出的SQL语句是什么样子的。

3.1.3 JDBC VS Mybatis

JDBC程序的缺点

  • url、username、password 等相关参数全部硬编码在java代码中。

  • 查询结果的解析、封装比较繁琐。

  • 每一次操作数据库之前,先获取连接,操作完毕之后,关闭连接。 频繁的获取连接、释放连接造成资源浪费。

分析了JDBC的缺点之后,我们再来看一下在mybatis中,是如何解决这些问题的:

  • 数据库连接四要素(驱动、链接、用户名、密码),都配置在springboot默认的配置文件 application.properties中,配置文件不用重新编译

  • 查询结果的解析及封装,由mybatis自动完成映射封装,我们无需关注

  • 在mybatis中使用了数据库连接池技术,从而避免了频繁的创建连接、销毁连接而带来的资源浪费。

使用SpringBoot+Mybatis的方式操作数据库,能够提升开发效率、降低资源浪费

而对于Mybatis来说,我们在开发持久层程序操作数据库时,需要重点关注以下两个方面:

  1. application.properties
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://localhost:3306/web01
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=1234-
  • Mapper接口(编写SQL语句)
@Mapper
public interface UserMapper {
    @Select("select * from user")
    public List<User> list();
}
3.1.4 数据库连接池

在前面我们所讲解的mybatis中,使用了数据库连接池技术,避免频繁的创建连接、销毁连接而带来的资源浪费。

下面我们就具体的了解下数据库连接池。

3.1.4.1 介绍

1). 没有数据库连接池的情况

客户端执行SQL语句:要先创建一个新的连接对象,然后执行SQL语句,SQL语句执行后又需要关闭连接对象从而释放资源,每次执行SQL时都需要创建连接、销毁链接,这种频繁的重复创建销毁的过程是比较耗费计算机的性能。

2). 有数据库连接池的情况

数据库连接池是个容器,负责分配、管理数据库连接(Connection)

  • 程序在启动时,会在数据库连接池(容器)中,创建一定数量的Connection对象

允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

  • 客户端在执行SQL时,先从连接池中获取一个Connection对象,然后在执行SQL语句,SQL语句执行完之后,释放Connection时就会把Connection对象归还给连接池(Connection对象可以复用)

释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏

  • 客户端获取到Connection对象了,但是Connection对象并没有去访问数据库(处于空闲),数据库连接池发现Connection对象的空闲时间 > 连接池中预设的最大空闲时间,此时数据库连接池就会自动释放掉这个连接对象

数据库连接池的好处:

  • 资源重用

  • 提升系统响应速度

  • 避免数据库连接遗漏

3.1.4.2 产品

要怎么样实现数据库连接池呢?

  • 官方(sun)提供了数据库连接池标准(javax.sql.DataSource接口)

  • 功能:获取连接

    public Connection getConnection() throws SQLException;
    
  • 第三方组织必须按照DataSource接口实现

常见的数据库连接池:C3P0 、DBCP 、Druid 、Hikari (springboot默认)

现在使用更多的是:Hikari、Druid (性能更优越)

1). Hikari(追光者) [默认的连接池]

从控制台输出的日志,我们也可以看出,springboot底层默认使用的数据库连接池就是 Hikari。

2). Druid(德鲁伊)

  • Druid连接池是阿里巴巴开源的数据库连接池项目

  • 功能强大,性能优秀,是Java语言最好的数据库连接池之一

如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要完成以下两步操作即可:

参考官方地址:https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

①. 在pom.xml文件中引入依赖

<dependency>
    <!-- Druid连接池依赖 -->
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.19</version>
</dependency>

②. 在application.properties中引入数据库连接配置

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.druid.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://localhost:3306/web
spring.datasource.druid.username=root
spring.datasource.druid.password=1234

配置完毕之后,我们再次运行单元测试,大家会看到控制台输出的日志中,已经将连接池切换为了 Druid连接池。


3.1.5 增删改查操作
3.1.5.1 删除
  • 需求:根据ID删除用户信息

  • SQL:delete from user where id = 5;

  • Mapper接口方法:

    • 方式一:
    /**
     * 根据id删除
     */
    @Delete("delete from user where id = 5")
    public void deleteById();
    

这种方式执行删除操作,调用deleteById方法只能删除id为5的用户信息,因为将id直接写死在代码中了,不可取。

在Mybatis中,我们可以通过参数占位符号 #{...} 来占位,在调用deleteById方法时,传递的参数值,最终会替换占位符。

@Delete("delete from user where id = #{id}")
public void deleteById(Integer id);
  • 编写单元测试方法进行测试

    在单元测试类中,增加如下测试方法.

    @Test
    public void testDeleteById(){
        userMapper.deleteById(36);
    }
    

运行单元测试,结果如下:

运行之后,我们发现,#{...} 占位符,其实最终被替换成了**?占位符** ,生成的是预编译的SQL语句。【推荐】

  • DML语句执行完毕,是有返回值的,我们可以为Mapper接口方法定义返回值来接收,如下:

    /**
     * 根据id删除
     */
    @Delete("delete from user where id = #{id}")
    public Integer deleteById(Integer id);
    

Integer类型的返回值,表示DML语句执行完毕影响的记录数。

  • Mybatis的提供的符号,有两个,一个是 #{...},另一个是 ${...},区别如下:

    image-20250421224804148
符号作用用法说明安全性性能
#{...}预编译参数占位符将参数值通过 JDBC 的 PreparedStatement 设置到 SQL 中,使用预编译方式防止 SQL 注入。高(因为使用了预编译)
${...}字符串替换占位符将参数值直接拼接到 SQL 字符串中,不进行预编译,适用于动态表名、列名等场景,但容易引发 SQL 注入问题。低(不进行预编译,直接拼接)

那在企业项目开发中,强烈建议使用 #{…} 。

预编译原理:MyBatis 使用 #{...} 进行预编译时,会将 SQL 语句和参数分开处理。这样,MyBatis 会把参数值绑定到 SQL 语句中的占位符,而不会直接插入到 SQL 语句的结构中(例如表名、列名、运算符等)。这意味着,#{...} 只能用于动态值(如字符串、数字等),而不能修改 SQL 的结构。


3.1.5.2 新增
  • 需求:添加一个用户

  • SQL:insert into user(username,password,name,age) values(‘zhouyu’,‘123456’,‘周瑜’,20);

  • Mapper接口:

/**
 * 添加用户
 */
@Insert("insert into user(username,password,name,age) values(#{username},#{password},#{name},#{age})")
public void insert(User user);

如果在SQL语句中,我们需要传递多个参数,我们可以把多个参数封装到一个对象中。然后在SQL语句中,我们可以通过#{对象属性名}的方式,获取到对象中封装的属性值。注意不是字段名

  • 单元测试:

在测试类中添加测试方法,代码如下:

@Test
public void testInsert(){
    User user = new User();
    user.setUsername("admin");
    user.setPassword("123456");
    user.setName("管理员");
    user.setAge(30);
    userMapper.insert(user);
}

运行结果如下:


3.1.5.3 修改
  • 需求:根据ID更新用户信息

  • SQL:update user set username = ‘zhouyu’, password = ‘123456’, name = ‘周瑜’, age = 20 where id = 1;

  • Mapper接口方法:注意是属性名!!!跟字段名没关系

/**
 * 根据id更新用户信息
 */
@Update("update user set username = #{username},password = #{password},name = #{name},age = #{age} where id = #{id}")
public void update(User user);
  • 单元测试:

在测试类中添加测试方法,代码如下:

@Test // 全参构造也可以
public void testUpdate(){
    User user = new User();
    user.setId(6);
    user.setUsername("admin666");
    user.setPassword("123456");
    user.setName("管理员");
    user.setAge(30);
    userMapper.update(user);
}

运行结果如下:


3.1.5.4 查询(带条件)
  • 需求:根据用户名和密码查询用户信息

  • SQL:select * from user where user name = ‘zhouyu’ and password = ‘123456’;

  • Mapper接口方法:

/**
 * 根据用户名和密码查询用户信息
 */
@Select("select * from user where username = #{username} and password = #{password}") //注意这里是为形参起的名字而不是方法形参名称
public User findByUsernameAndPassword(@Param("username") String username, @Param("password") String password);

@param注解的作用是为接口的方法形参起名字的。(由于用户名唯一的,所以查询返回的结果最多只有一个,可以直接封装到一个对象中)

在默认的情况下,Java 编译器会去除方法参数的名称,只保留参数的类型。这意味着编译后的字节码中可能没有方法参数的原始名字(例如 usernamepassword),因此 MyBatis 无法直接通过这些参数名称来引用它们。之前增删改只有一个形参,现在不止一个形参

  • 单元测试:

在测试类中添加测试方法,代码如下:

@Test
public void testFindByUsernameAndPassword(){
    User user = userMapper.findByUsernameAndPassword("admin666", "123456");
    System.out.println(user);
}

运行结果如下:

image-20250421234601767

说明:基于官方骨架创建的springboot项目中,接口编译时会保留方法形参名,@Param注解可以省略 (#{形参名})。

这里直接写形参名即可

如果用阿里框架还不给起名字,报错如下

字节码文件:形参名没有被保留,只保留类型

image-20250421234736514

起了名字之后的字节码文件

image-20250421234904963

注意报错不要从上往下读,直接找Caused by

image-20250421234721900

image-20250421234938104


3.1.6 XML映射配置

Mybatis的开发有两种方式:

  1. 注解: 如@Select @Update等等

  2. XML

3.1.6.1 XML配置文件规范

使用Mybatis的注解方式,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中。

image-20250421235320303

在Mybatis中使用XML映射文件方式开发,需要符合一定的规范:

  1. XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下**(同包同名)**

  2. XML映射文件的namespace属性为Mapper接口全限定名一致

  1. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致(注意是单条返回类型)。

<select>标签:就是用于编写select查询语句的。

  • resultType属性,指的是查询返回的单条记录所封装的类型。
  • id属性:这个sql语句的唯一标识,且与方法名命名一致
3.1.6.2 XML配置文件实现

第1步: 创建XML映射文件

这里不要用 .

第2步:编写XML映射文件

xml映射文件中的dtd约束,直接从mybatis官网复制即可; 或者直接AI生成。这个是固定的,不用记

官方:https://mybatis.net.cn/getting-started.html

image-20250421235646668

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="">
 
</mapper>

第3步:配置

a. XML映射文件的namespace属性为Mapper接口全限定名

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.UserMapper">

</mapper>

b. XML映射文件中sql语句的id与Mapper接口中的方法名一致,并保持返回类型一致

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.mapper.EmpMapper">

    <!--查询操作-->
    <select id="findAll" resultType="com.itheima.pojo.User">
        select * from user
    </select>
    
</mapper>

resultType 属性的值,与查询返回的单条记录封装的类型一致。

运行测试类,执行结果:

image-20250422000924130

匹配规则

  1. 一旦调用了UserMapper中的方法,就会去查询要执行的sql语句在哪个映射文件中定义,就回去查找哪份XML文件的namesapce属性是我Mapper接口的全类名,进行匹配
  2. 一份XML文件中可以有多条sql语句,那我们怎么知道调用那条呢?
    根据方法名和id名匹配来调用,

注意:一个接口方法对应的SQL语句,要么使用注解配置,要么使用XML配置,切不可同时配置。

开发规范

image-20250422001134894


3.1.6.3 MybatisX的使用

1. 指定配置XML映射文件位置

mybatis.mapper-locations=classpath:mapper/*.xml

java目录和resources目录在编译后都会放在class目录下,所以先指定一下最后位置


2.MybatisX是一款基于IDEA的快速开发Mybatis的插件,为效率而生。

MybatisX的安装:

可以通过MybatisX快速定位:

MybatisX的使用在后续学习中会继续分享。

  • 学习了Mybatis中XML配置文件的开发方式了,大家可能会存在一个疑问:到底是使用注解方式开发还是使用XML方式开发?

官方说明:https://mybatis.net.cn/getting-started.html。下面是官方说明:

结论:使用Mybatis的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的SQL功能,建议使用XML来配置映射语句。


4. SpringBoot配置文件

4.1 介绍

前面我们一直使用springboot项目创建完毕后自带的application.properties进行属性的配置,而如果在项目中,我们需要配置大量的属性,采用properties配置文件这种 key=value 的配置形式,就会显得配置文件的层级结构不清晰,也比较臃肿。

那其实呢,在springboot项目当中是支持多种配置方式的,除了支持properties配置文件以外,还支持另外一种类型的配置文件,就是我们接下来要讲解的yml格式的配置文件。yml格式配置文件名字为:application.yaml , application.yml 这两个配置文件的后缀名虽然不一样,但是里面配置的内容形式都是一模一样的。

我们可以来对比一下,采用 application.propertiesapplication.yml 来配置同一段信息(数据库连接信息),两者之间的配置对比:yml格式冗余部分简洁化了

在项目开发中,我们推荐使用application.yml配置文件来配置信息,简洁、明了、以数据为中心。

4.2 语法

简单的了解过springboot所支持的配置文件,以及不同类型配置文件之间的优缺点之后,接下来我们就来了解下yml配置文件的基本语法:

  • 大小写敏感
  • key和value用冒号分开,但value前必须有空格,作为分隔符
  • 使用缩进表示层级关系,缩进时,不允许使用Tab键,只能用空格(idea中会自动将Tab转换为空格,所以正常用)
  • 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
  • #表示注释,从这个字符一直到行尾,都会被解析器忽略

了解完yml格式配置文件的基本语法之后,接下来我们再来看下yml文件中常见的数据格式。在这里我们主要介绍最为常见的两类:

  1. 定义对象或Map集合

  2. 定义数组、list或set集合

  • 对象/Map集合
user:
  name: zhangsan
  age: 18
  password: 123456
  • 数组/List/Set集合 -后面加各个元素的值
hobby: 
  - java #元素1
  - game #元素2
  - sport #元素3

在yml格式的配置文件中,如果配置项的值是以 0 开头的,值需要使用 ‘’ 引起来,因为以0开头在yml中表示8进制的数据。

4.3 案例

熟悉完了yml文件的基本语法后,我们修改下之前案例中使用的配置文件,变更为application.yml配置方式:

  1. 修改application.properties名字为:_application.properties(名字随便更换,只要加载不到即可)

  2. 创建新的配置文件: application.yml

  • 原有的 application.properties 配置文件

  • 新建的 application.yml 配置文件

配置文件的内容如下:

#数据源配置
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/web01
    username: root
    password: root@1234
#mybatis配置
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

image-20250422003700963


求关注2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2342648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

postman 删除注销账号

一、删除账号 1.右上角找到 头像&#xff0c;view profile https://123456-6586950.postman.co/settings/me/account 二、找回账号 1.查看日志所在位置 三、postman更新后只剩下history 在 Postman 中&#xff0c;如果你发现更新后只剩下 History&#xff08;历史记录&…

Java发展史及版本详细说明

Java发展史及版本详细说明 1. Java 1.0&#xff08;1996年1月23日&#xff09; 核心功能&#xff1a; 首个正式版本&#xff0c;支持面向对象编程、垃圾回收、网络编程。包含基础类库&#xff08;java.lang、java.io、java.awt&#xff09;。支持Applet&#xff08;浏览器嵌入…

React 5 种组件提取思路与实践

在开发时,经常遇到一些高度重复但略有差异的 UI 模式,此时我们当然会把组件提取出去,但是组件提取的方式有很多,怎么根据不同场景选取合适的方式呢?尤其时在复杂的业务场景中,组件提取的思路影响着着代码的可维护性、可读性以及扩展性。本文将以一个[详情]组件为例,探讨…

[java八股文][Java基础面试篇]I/O

Java怎么实现网络IO高并发编程&#xff1f; 可以用 Java NIO &#xff0c;是一种同步非阻塞的I/O模型&#xff0c;也是I/O多路复用的基础。 传统的BIO里面socket.read()&#xff0c;如果TCP RecvBuffer里没有数据&#xff0c;函数会一直阻塞&#xff0c;直到收到数据&#xf…

数据结构-冒泡排序(Python)

目录 冒泡排序算法思想 冒泡排序算法步骤 冒泡排序代码实现 冒泡排序算法分析 冒泡排序算法思想 冒泡排序&#xff08;Bubble Sort&#xff09;基本思想&#xff1a; 经过多次迭代&#xff0c;通过相邻元素之间的比较与交换&#xff0c;使值较小的元素逐步从后面移到前面…

深入理解React高阶组件(HOC):原理、实现与应用实践

组件复用的艺术 在React应用开发中&#xff0c;随着项目规模的增长&#xff0c;组件逻辑的复用变得越来越重要。传统的组件复用方式如组件组合和props传递在某些复杂场景下显得力不从心。高阶组件&#xff08;Higher-Order Component&#xff0c;简称HOC&#xff09;作为React中…

Neo4j社区版在win下安装教程(非docker环境)

要在 Windows 10 上安装 Neo4j 社区版数据库并且不使用 Docker Desktop&#xff0c;你可以按照以下步骤操作&#xff1a; 1. 安装 Java Development Kit (JDK) Neo4j 需要 Java 运行环境。推荐安装 JDK 17 或 JDK 11&#xff08;请根据你下载的 Neo4j 版本查看具体的兼容性要…

如何在 Odoo 18 中配置自动化动作

如何在 Odoo 18 中配置自动化动作 Odoo是一款多功能的业务管理平台&#xff0c;旨在帮助各种规模的企业更高效地处理日常运营。凭借其涵盖销售、库存、客户关系管理&#xff08;CRM&#xff09;、会计和人力资源等领域的多样化模块&#xff0c;Odoo 简化了业务流程&#xff0c…

node.js 实战——(Http 知识点学习)

HTTP 又称为超文本传输协议 是一种基于TCP/IP的应用层通信协议&#xff1b;这个协议详细规定了 浏览器 和万维网 服务器 之间互相通信的规则。协议中主要规定了两个方面的内容&#xff1a; 客户端&#xff1a;用来向服务器发送数据&#xff0c;可以被称之为请求报文服务端&am…

新市场环境下新能源汽车电流传感技术发展前瞻

新能源革命重构产业格局 在全球碳中和战略驱动下&#xff0c;新能源汽车产业正经历结构性变革。国际清洁交通委员会&#xff08;ICCT&#xff09;最新报告显示&#xff0c;2023年全球新能源汽车渗透率突破18%&#xff0c;中国市场以42%的市占率持续领跑。这种产业变革正沿着&q…

fastjson使用parseObject转换成JSONObject出现将字符特殊字符解析解决

现象&#xff1a;将字符串的${TARGET_VALUE}转换成NULL字符串了问题代码&#xff1a; import com.alibaba.fastjson.JSON;JSONObject config JSON.parseObject(o.toString()); 解决方法&#xff1a; 1.更换fastjson版本 import com.alibaba.fastjson2.JSON;或者使用其他JS…

【安装neo4j-5.26.5社区版 完整过程】

1. 安装java 下载 JDK21-windows官网地址 配置环境变量 在底下的系统变量中新建系统变量&#xff0c;变量名为JAVA_HOME21&#xff0c;变量值为JDK文件夹路径&#xff0c;默认为&#xff1a; C:\Program Files\Java\jdk-21然后在用户变量的Path中&#xff0c;添加下面两个&am…

机器人项目管理新风口:如何高效推动智能机器人研发?

在2025年政府工作报告中&#xff0c;“智能机器人”首次被正式纳入国家发展战略关键词。从蛇年春晚的秧歌舞机器人惊艳亮相&#xff0c;到全球首个人形机器人马拉松的热议&#xff0c;智能机器人不仅成为科技前沿的焦点&#xff0c;也为产业升级注入了新动能。而在热潮背后&…

【Linux】网络基础和socket(4)

1.网络通信&#xff08;app\浏览器、小程序&#xff09; 2.网络通信三要素&#xff1a; IP&#xff1a;计算机在网络上唯一标识&#xff08;ipv4:4个字段&#xff0c;每段最大255 IPV6:16进制&#xff09; 端口&#xff1a;计算机应用或服务唯一标识 ssh提供远程安全连接…

大数据可能出现的bug之flume

一、vi /software/flume/conf/dir_to_logger.conf配置文件 问题的关键: Dir的D写成了小写 另一个终端里面的东西一直在监听状态下无法显示 原来是vi /software/flume/conf/dir_to_logger.conf里面的配置文件写错了 所以说不是没有source参数的第三行的原因 跟这个没关系 …

图解Mysql原理之全局锁,表级锁,行锁了解吗?

前言 大家好&#xff0c;我是程序蛇玩编程。 Mysql中的锁大家都用过吗&#xff0c;那全局锁&#xff0c;表锁&#xff0c;行锁哪个用的频率最多呢? 正文 全局锁: 全局锁就是对整个数据库实例加锁。 MySQL 提供了一个加全局读锁的方法&#xff0c;命令是 Flush tables wi…

Java集成【邮箱验证找回密码】功能

目录 1.添加依赖 2.选择一个自己的邮箱&#xff0c;作为发件人角色。 3.编写邮箱配置【配置发件人邮箱】 4.编写邮箱配置类 5.编写controller业务代码 6.演示效果 7.总结流程 8.注意 结语 一.发送邮箱验证码 1.添加依赖 <!--导入邮箱依赖--> <dependency&g…

HarmonyOS 5.0应用开发——MVVM模式的应用

【高心星出品】 文章目录 MVVM模式的应用ArkUI开发模式图架构设计原则案例运行效果项目结构功能特性开发环境model层viewmodel层view层 MVVM模式的应用 MVVM&#xff08;Model-View-ViewModel&#xff09;模式是一种广泛用于应用开发的架构模式&#xff0c;它有助于分离应用程…

程序员鱼皮最新项目-----AI超级智能体教程(一)

文章目录 1.前言1.什么是AI大模型2.什么是多模态3.阿里云百炼平台介绍3.1文本调试展示3.2阿里云和dashscope的关系3.3平台智能体应用3.4工作流的创建3.5智能体编排应用 1.前言 最近鱼皮大佬出了一套关于这个AI 的教程&#xff0c;关注鱼皮大佬很久了&#xff0c;鱼皮大佬确实在…

【AI模型学习】双流网络——更强大的网络设计

文章目录 一 背景1.1 背景1.2 研究目标 二 模型2.1 双流架构2.2 光流 三 实验四 思考4.1 多流架构4.2 fusion策略4.3 fusion的early与late 先简单聊了双流网络最初在视频中的起源&#xff0c;之后把重点放在 “多流结构"和"fusion” 上。 一 背景 1.1 背景 Two-Str…