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

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

文章目录

    • 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入门程序*/@Testpublic 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.执行SQLint 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() 来加载驱动。

    @Testpublic 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对象@Autowiredprivate UserMapper userMapper;@Testvoid 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 mapperPUBLIC "-//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 mapperPUBLIC "-//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 mapperPUBLIC "-//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: zhangsanage: 18password: 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.Driverurl: jdbc:mysql://localhost:3306/web01username: rootpassword: root@1234
#mybatis配置
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

image-20250422003700963


求关注2

相关文章:

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

文章目录 1. 前言2. JDBC2.1 介绍2.2 入门程序2.2.1 DataGrip2.2.2 在IDEA执行sql语句 2.3 查询数据案例2.3.1 需求2.3.2 准备工作2.3.3 AI代码实现2.3.4 代码剖析2.3.4.1 ResultSet2.3.4.2 预编译SQL2.3.4.2.1 SQL注入2.3.4.2.2 SQL注入解决2.3.4.2.3 性能更高 2.4 增删改数据…...

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;使值较小的元素逐步从后面移到前面…...

Java单例模式详解:实现线程安全的全局访问点

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 一、什么是单例模式&#xff1f; 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;它保证一个类仅有一个实例&#xff…...

React-组件和props

1、类组件 import React from react; class ClassApp extends React.Component {constructor(props) {super(props);this.state{};}render() {return (<div><h1>这是一个类组件</h1><p>接收父组件传过来的值&#xff1a;{this.props.name}</p>&…...

Java面试:从Spring Boot到微服务的全面考核

Java面试&#xff1a;从Spring Boot到微服务的全面考核 场景设定&#xff1a; 在一家互联网大厂的面试室内&#xff0c;严肃的面试官正准备开始对前来面试的赵大宝进行技术考核。赵大宝是一位自称在Java开发方面经验丰富的求职者&#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 版本查看具体的兼容性要…...

【AI 加持下的 Python 编程实战 2_10】DIY 拓展:从扫雷小游戏开发再探问题分解与 AI 代码调试能力(中)

文章目录 DIY 实战&#xff1a;从扫雷小游戏开发再探问题分解能力3 问题分解实战&#xff08;自顶向下&#xff09;3.2 页面渲染逻辑3.3 事件绑定逻辑 4 代码实现&#xff08;自底向上&#xff09;4.1 页面渲染部分4.2 事件绑定部分 写在前面 本篇将利用《Learn AI-assisted Py…...

使用PHP对接印度尼西亚股票市场

在本篇文章中&#xff0c;我们将介绍如何使用PHP语言与StockTV API接口对接&#xff0c;获取并处理印度尼西亚&#xff08;Indonesia&#xff09;的股票市场数据。我们将以查询IPO信息和查看涨跌排行榜为例&#xff0c;展示具体的操作流程。 准备工作 首先&#xff0c;确保您…...

如何在 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…...

系统重装——联想sharkbay主板电脑

上周给一台老电脑重装系统系统&#xff0c;型号是lenovo sharkbay主板的电脑&#xff0c;趁着最近固态便宜&#xff0c;入手了两块长城的固态&#xff0c;装上以后插上启动U盘&#xff0c;死活进不去boot系统。提示 bootmgr 缺失&#xff0c;上网查了许久&#xff0c;终于解决了…...

CentOS 7.9升级OpenSSH到9.9p2

初始版本 ssh -V OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017 1.安装编译依赖 yum install -y gcc perl make zlib-devel pam-devel openssl-devel wget 2.升级OpenSSL到1.1.1版本 2.1 备份当前OpenSSL配置 sudo cp -r /usr/bin/openssl /usr/bin/openssl.bak sudo …...

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…...

37、aiomysql实操习题

练习题1&#xff1a;慢查询优化 题目描述 将以下低效查询优化为索引查询&#xff1a; # 原始低效查询 await cursor.execute("SELECT * FROM orders WHERE YEAR(created_at)2023")参考答案 # 优化后查询&#xff08;使用索引范围扫描&#xff09; await cursor.e…...

Rust 2025:内存安全革命与异步编程新纪元

Rust 2025 Edition通过区域内存管理、泛型关联类型和零成本异步框架三大革新&#xff0c;重新定义系统级编程语言的能力边界。本次升级不仅将内存安全验证效率提升80%&#xff0c;更通过异步执行器架构优化实现微秒级任务切换。本文从编译器原理、运行时机制、编程范式转型三个…...

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

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

开关电源实战(六)STM32数控电源BuckBoost

文章目录 芯片手册详解栅极驱动器EG3112栅极驱动芯片2EDF7275K隔离式MOS栅极驱动器运放检测电流GS8558MCP6022打板测试硬件设计PID测试存在的问题参考:基于STM32的同步整流Buck-Boost数字电源 开源 芯片手册详解 栅极驱动器 EG3112栅极驱动芯片 (较低芯片,一个四五毛) …...

Vue3项目中 npm 依赖安装 --save 与 --save-dev 的区别解析

这两个命令的区别如下&#xff1a; bash npm install --save types/crypto-js # 安装到 dependencies&#xff08;生产依赖&#xff09; npm install --save-dev types/crypto-js # 安装到 devDependencies&#xff08;开发依赖&#xff09; 核心区别 依赖分类不同…...

Oracle 数据库中的 JSON:性能注意事项

本文为白皮书“JSON in Oracle Database: Performance Considerations”的翻译及阅读笔记。 目的 本文档概述了在 Oracle 数据库中存储和处理的 JavaScript 对象表示法 (JSON) 的性能调优最佳实践。应用这些最佳实践将使开发人员、数据库管理员和架构师能够主动避免性能问题&…...

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

在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…...

JavaScript 的“世界模型”:深入理解对象 (Objects)

引言&#xff1a;超越简单值&#xff0c;构建复杂实体 到目前为止&#xff0c;我们学习的变量大多存储的是单一的值&#xff0c;比如一个数字 (let age 30;​)、一个字符串 (let name "Alice";​) 或一个布尔值 (let isActive true;​)。这对于简单场景足够了&am…...