【JavaEE进阶】——Mybatis操作数据库(使用注解和XML方式)

目录

🚩三层架构 

🎈JDBC操作回顾

🚩什么是MyBatis

🚩MyBatis⼊⻔

🎈准备工作

📝创建⼯程

📝数据准备

🎈配置数据库连接字符串

🎈写持久层代码

🎈单元测试

🚩MyBatis的基础操作

🎈打印日志

🎈参数传递

🎈增(Insert)

📝返回主键(实现自增效果)

🎈删(delete)

🎈改(Update)

🎈查(Select)

📝起别名

📝结果映射

📝开启驼峰命名(推荐)

🚩MyBatis  XML配置文件

🎈配置连接字符串和MyBatis

🎈写持久层代码

📝添加 mapper 接⼝

📝添加 UserInfoXMLMapper2.xml

📝查询所有⽤⼾的具体实现 :

📝单元测试

🎈增删改查操作

📝增(Insert)

📝删(Delete)

📝改(Update)

📝查(Select)


本节⽬标
  • 1. 使⽤MyBatis完成简单的增删改查操作, 参数传递.
  • 2. 掌握MyBatis的两种写法: 注解 和 XML⽅式
  • 3. 掌握MyBatis 相关的⽇志配置

🚩三层架构 

在应⽤分层学习时, 我们 了解到web应⽤程序⼀般分为三层,即:Controller、Service、Dao .
  • 表现层:Controller  参数接收,参数校验,参数格式转换,结果格式转换,结果返回等等
  • 业务逻辑层:Service  介于表现层和数据层之间,业务逻辑相关的处理
  • 数据层:Dao  与数据相关的,数据的增删改查
之前的案例中,请求流程如下:
浏览器发起请求, 先请求Controller, Controller接收到请求之后, 调⽤ Service进⾏业务逻辑处理, Service再调⽤Dao, 但是Dao层的数据是Mock的, 真实的数据应该从数据库中读取.
我们学习MySQL数据库时,已经学习了JDBC来操作数据库, 但是JDBC操作太复杂了.

🎈JDBC操作回顾

我们先来回顾⼀下 JDBC 的操作流程:
  • 1. 创建数据库连接池 DataSource
  • 2. 通过 DataSource 获取数据库连接 Connection
  • 3. 编写要执⾏带 ? 占位符的 SQL 语句
  • 4. 通过 Connection 及 SQL 创建操作命令对象 Statement
  • 5. 替换占位符:指定要替换的数据库字段类型,占位符索引及要替换的值
  • 6. 使⽤ Statement 执⾏ SQL 语句
  • 7. 查询操作:返回结果集 ResultSet,更新操作:返回更新的数量
  • 8. 处理结果集
  • 9. 释放资源
展⽰了通过 JDBC 的 API 向数据库中添加⼀条记录,修改⼀条记录,查询⼀条记录的操作。
从上述的操作流程中可以看出,对于JDBC来说,整个操作非常的繁琐,不但要拼接每一个参数,而且还要按照模板代码的方式,一步步的操作数据库,并且在每次操作完,还要手动关闭连接等,而所有的这些操作步骤都需要在每个方法中重复书写,那有没有一种方法,可以更简单,更方便的操作数据库呢?
答案是肯定的,这就是我们要学习 MyBatis 的真正原因,它可以帮助我们更⽅便、更快速的操作数据库.

🚩什么是MyBatis

MyBatis是一款优秀的 持久层 框架,用于简化JDBC的开发
在上⾯我们提到⼀个词:持久层
持久层:指的就是持久化操作的层, 通常指数据访问层(dao), 是⽤来操作数据库的
简单来说 MyBatis是更简单完成程序和数据库交互的框架,也就是更简单的操作和读取数据库工具,接下来,我们就通过一个入门程序,让大家感受一下通过MyBatis如何来操作数据库

🚩MyBatis⼊⻔

Mybatis操作数据库的步骤:
  • 1. 准备⼯作(创建springboot⼯程、数据库表准备、实体类)
  • 2. 引⼊Mybatis的相关依赖,配置Mybatis(数据库连接信息)
  • 3. 编写SQL语句(注解/XML)
  • 4. 测试

🎈准备工作

📝创建⼯程

创建springboot⼯程,并导⼊ mybatis的起步依赖、mysql的驱动包
Mybatis 是⼀个持久层框架, 具体的数据存储和数据操作还是在MySQL中操作的, 所以需要添加MySQL驱动。

项⽬⼯程创建完成后,⾃动在pom.xml⽂件中,导⼊Mybatis依赖和MySQL驱动依赖 。
<!--Mybatis 依赖包--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><!--mysql驱动包-->
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope>
</dependency>

📝数据准备

创建⽤⼾表, 并创建对应的实体类User
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;
-- 使⽤数据数据
USE mybatis_test;
-- 创建表[⽤⼾表]
DROP TABLE IF EXISTS userinfo;
CREATE TABLE `userinfo` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 
-- 添加⽤⼾信息
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.userinfo ( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
创建对应的实体类 UserInfo
实体类的属性名与表中的字段名⼀⼀对应
package com.example.mybatis_test.model;import lombok.Data;import java.util.Date;@Data
public class UserInfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;private Integer deleteFlag;private Date createTime;private Date updateTime;
}

🎈配置数据库连接字符串

# 数据库连接配置
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
注意事项:
如果使⽤ MySQL 是 5.x 之前的使⽤的是"com.mysql.jdbc.Driver",如果是⼤于 5.x 使⽤的
是“com.mysql.cj.jdbc.Driver”.

🎈写持久层代码

在项⽬中, 创建持久层接⼝UserInfoMapper2.

package com.example.mybatis_test.mapper;import com.example.mybatis_test.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;import java.util.List;@Mapper
public interface UserInfoMapper2 {//查询所有用户的信息@Select("select * from userinfo")List<UserInfo>getUserInfoAll();
}
Mybatis的持久层接⼝规范⼀般都叫 XxxMapper   
  • @Mapper注解:表⽰是MyBatis中的Mapper接⼝ 程序运行时,框架会自动生成接口的实现类对象(代理对象),并交给Spring的IOC容器管理.(也就是在程序运行的时候,框架会自动生成UserInfoMapper2接口,然后交给了spring的ioc容器中让spring进行管理,等需要了就注入)
  • @Select注解:代表的就是select查询,也就是注解对应方法的具体实现内容(而select就是执行sql语句,注解里面的内容就是具体实现内容)

🎈单元测试

在创建出来的SpringBoot⼯程中,在src下的test⽬录下,已经⾃动帮我们创建好了测试类 ,我们可以直接使⽤这个测试类来进⾏测试.
package com.example.mybatis_test.mapper;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class UserInfoMapper2Test {@Testvoid getUserInfoAll() {}
}

此时的测试单元类就自动生成了,再src/test/java/Mapper里面自动生成了测试类。

package com.example.mybatis_test.mapper;import com.example.mybatis_test.model.UserInfo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;import static org.junit.jupiter.api.Assertions.*;@SpringBootTest
class UserInfoMapper2Test {@Autowiredprivate UserInfoMapper2 userInfoMapper2;@Testvoid getUserInfoAll() {List<UserInfo>userInfos=userInfoMapper2.getUserInfoAll();for (UserInfo userInfo:userInfos) {System.out.println(userInfo);}}
}
记得加 @SpringBootTest 注解, 加载Spring运⾏环境,否则会报错
测试类上添加了注解 @SpringBootTest,该测试类在运⾏时,就会⾃动加载Spring的运⾏环境.
我们通过@Autowired这个注解, 注⼊我们要测试的类, 就可以开始进⾏测试了
返回结果中, 可以看到, 只有SQL语句中查询的列对应的属性才有赋值。sql语句和查询的列属性不对应那么就默认为空值。

🚩MyBatis的基础操作

上⾯我们学习了Mybatis的查询操作, 接下来我们学习MyBatis的增, 删, 改操作 ,在学习这些操作之前, 我们先来学习MyBatis⽇志打印。

🎈打印日志

在Mybatis当中我们可以借助⽇志, 查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果 ,在配置⽂件中进⾏配置即可。
#配置mybatis日志,为了后续观察sql语句的执行
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

  • ①: 查询语句  preparing:select*from userinfo  
  • ②: 传递参数及类型   Parameters
  • ③: SQL执⾏结果  cloums以下
我们看到,配置日志文件后,我们就可以观察到,sql语句的执行,以及执行结果,每一行都标注的清清楚楚,并且标注影响的行数。

🎈参数传递

#{}动态参数传递

需求: 查找id=4的⽤⼾,对应的SQL就是: select * from userinfo where id=4
//查询id=4的用户@Select("select * from userinfo where id=#{id}")UserInfo queryById(Integer id);
如果给where id=4表示只能查找id=4 的数据, 所以SQL语句中的id值不能写成固定数值,需要变为动态的数值 解决⽅案:在queryById⽅法中添加⼀个参数(id), 将⽅法中的参数,传给SQL语句
使⽤ #{} 的⽅式获取⽅法中的参数,使静态数据转成动态数据
如果mapper接⼝⽅法形参只有⼀个普通类型的参数,#{…} ⾥⾯的属性名可以随便写,如:#{id}、# {value}。 建议和参数名保持⼀致
🍭添加测试样例:
  @Testvoid queryById() {UserInfo userInfo=userInfoMapper2.queryById(4);System.out.println(userInfo);}

🍭控制台结果

也可以通过 @Param , 设置参数的别名 , 如果使⽤ @Param 设置别名, #{...}⾥⾯的属性名必须和 @Param 设置的⼀样

🎈增(Insert)

   //增加一个用户@Insert("insert into userinfo (username,`password`,age,gender) values" +"(#{username},#{password},#{age},#{gender})")Integer insert(UserInfo userInfo);

如果语句过长,我们可以直接敲回车,idea会自动给你换行。

🍭添加测试样例

    @Testvoid insert() {UserInfo userInfo=new UserInfo();userInfo.setUsername("zyf");userInfo.setPassword("1005");userInfo.setAge(20);userInfo.setGender(1);Integer count=userInfoMapper2.insert(userInfo);System.out.println(count);}

🍭控制台结果

如果设置了 @Param 属性, #{...} 需要使⽤ 参数.属性 来获取
  //增加一个用户@Insert("insert into userinfo (username,`password`,age,gender) values" +"(#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender})")Integer insert(@Param("userinfo") UserInfo userInfo);

📝返回主键(实现自增效果)

自增id   @Options(useGeneratedKeys = true, keyProperty = "id")

  • useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内 部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字 段),默认值:false.
  • • keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置(unset)
Insert 语句默认返回的是 受影响的⾏数
但有些情况下, 数据插⼊之后, 还需要有后续的关联操作, 需要获取到新插⼊数据的id
⽐如订单系统
当我们下完订单之后, 需要通知物流系统, 库存系统, 结算系统等, 这时候就需要拿到订单ID
如果想要拿到⾃增id, 需要在Mapper接⼝的⽅法上添加⼀个Options的注解

 

 注意: 设置 useGeneratedKeys=true 之后, ⽅法返回值依然是受影响的⾏数, ⾃增id 会设置在上 述 keyProperty 指定的属性中.


🎈删(delete)

📝使用注解:

  @Delete("delete from userinfo where id=#{id}")Integer delete(Integer id);

📝添加测试样例

此时的表中就删除了id=4的用户。


🎈改(Update)

📝使用注解

//更新一个用户的姓名@Update("update userinfo set username=#{username} where id=#{id}")Integer update(String username,Integer id);

📝添加测试样例

   @Testvoid update() {Integer count=userInfoMapper2.update("zyf",5);System.out.println(count);}


🎈查(Select)

我们在上⾯查询时发现, 有⼏个字段是没有赋值的, 只有Java对象属性和数据库字段⼀模⼀样时, 才会进⾏赋值 ,接下来我们多查询⼀些数据
📝使用注解
    @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")List<UserInfo> queryAllUser();

📝添加测试样例

 @Testvoid queryAllUser() {List<UserInfo>infoList=userInfoMapper2.queryAllUser();for (UserInfo userInfo:infoList) {System.out.println(userInfo);}}

从运⾏结果上可以看到, 我们SQL语句中, 查询了delete_flag, create_time, update_time, 但是这⼏个属性却没有赋值.

原因分析:
当⾃动映射查询结果时, MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略⼤⼩写) 。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性
但是有三个属性和表的列名不一致,就不会进行赋值。

解决办法:
  • 1. 起别名
  • 2. 结果映射
  • 3. 开启驼峰命名

MyBatis 会根据⽅法的返回结果进⾏赋值.
  • ⽅法⽤对象 UserInfo接收返回结果, MySQL 查询出来数据为⼀条, 就会⾃动赋值给对象.
  • ⽅法⽤List<UserInfo>接收返回结果, MySQL 查询出来数据为⼀条或多条时, 也会⾃动赋值给List.
  • 但如果MySQL 查询返回多条, 但是⽅法使⽤UserInfo接收, MyBatis执⾏就会报错

📝起别名

在SQL语句中, 给列名起别名,保持别名和实体类属性名⼀样。  
delete_flag as deleteFlag, create_time as createTime, update_time as updateTime 
🍭使用注解
    @Select("select id, username, `password`, age, gender, phone, delete_flag as deleteFlag, create_time as createTime, update_time as updateTime from userinfo")List<UserInfo> queryAllUser2();
SQL语句太⻓时, 使⽤加号 + 进⾏字符串拼接(直接按回车idea自动给你换行)
🍭添加测试
  @Testvoid queryAllUser2() {List<UserInfo>infoList=userInfoMapper2.queryAllUser2();for (UserInfo userInfo:infoList) {System.out.println(userInfo);}}

📝结果映射

 @Select("select id, username, `password`, age, gender, phone, delete_flag, create_time, update_time from userinfo")@Results({@Result(column = "delete_flag",property = "deleteFlag"),@Result(column = "create_time",property = "createTime"),@Result(column = "update_time",property = "updateTime")})List<UserInfo> queryAllUser();
如果其他SQL, 也希望可以复⽤这个映射关系, 可以给这个Results定义⼀个名,这样我们再queryById方法中我们要想得到id=4的用户,他查询之后的结果也是那三个属性不对应,我们就可以复用下面的@Results注解,用@RestultMap注解定位到@Results注解中id。
使⽤ id 属性给该 Results 定义别名, 使⽤ @ResultMap 注解来复⽤其他定义的 ResultMap
🍭测试结果

📝开启驼峰命名(推荐)

通常数据库列使⽤蛇形命名法进⾏命名(下划线分割各个单词),  Java 属性⼀般遵循驼峰命名法约定.

驼峰命名规则: abc_xyz => abcXyz
  • • 表中字段名:abc_xyz
  • • 类中属性名:abcXyz
为了在这两种命名⽅式之间启⽤⾃动映射,需要将 mapUnderscoreToCamelCase 设置为 true。
mybatis:configuration:map-underscore-to-camel-case: true #配置驼峰⾃动转换

 🍭配置驼峰自动转换

   //查询所有用户的信息@Select("select * from userinfo")List<UserInfo>getUserInfoAll();

🍭添加测试样例

    @Testvoid getUserInfoAll() {List<UserInfo>userInfos=userInfoMapper2.getUserInfoAll();for (UserInfo userInfo:userInfos) {System.out.println(userInfo);}}


相比于起别名和结果映射,开启驼峰命名更加的简单,只需要再配置文件中配置一下,即可。


🚩MyBatis  XML配置文件

上⾯学习了注解的⽅式, 接下来我们学习XML的⽅式
使⽤Mybatis的注解⽅式,主要是来完成⼀些简单的增删改查功能. 如果需要实现复杂的SQL功能,建议使⽤XML来配置映射语句,也就是将SQL语句写在XML配置⽂件中.
MyBatis XML的⽅式需要以下两步:
  • 1. 配置数据库连接字符串和MyBatis
  • 2. 写持久层代码

🎈配置连接字符串和MyBatis

此步骤需要进⾏两项设置,数据库连接字符串设置和 MyBatis 的 XML ⽂件配置。 如果是application.yml⽂件, 配置内容如下:
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:mapper-locations: classpath:mapper/**Mapper.xml
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 105528clzyf.driver-class-name: com.mysql.cj.jdbc.Driver
#配置mybatis日志,为了后续观察sql语句的执行
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
##配置驼峰⾃动转换map-underscore-to-camel-case: true    
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件mapper-locations: classpath:mapper/UserInfoMapper2.xml

配置mybatis.xml文件,我们需要在src/main/resources/mapper目录下创建xml文件。


🎈写持久层代码

持久层代码分两部分
  • 1. ⽅法定义 Interface
  • 2. ⽅法实现: UserInfoMapper2.xml
Interface用于方法定义,xxx.xml用于方法的实现,实现sql语句。

📝添加 mapper 接⼝

数据持久层的接⼝定义:
package com.example.mybatis_test.mapper;import com.example.mybatis_test.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface UserInfoXmlMapper2 {List<UserInfo>queryAllUser();
}

📝添加 UserInfoXMLMapper2.xml

数据持久成的实现,MyBatis 的固定 xml 格式
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis_test.mapper.UserInfoXmlMapper2"></mapper>

创建UserInfoXMLMapper2.xml, 路径参考yml中的配置
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件mapper-locations: classpath:mapper/UserInfoMapper2.xml


📝查询所有⽤⼾的具体实现 :

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mybatis_test.mapper.UserInfoXmlMapper2"><select id="queryAllUser">select username,`password`,age,gender,phone, from userinfo</select>
</mapper>
以下是对以上标签的说明:
  • <mapper> 标签:需要指定 namespace 属性,表⽰命名空间,值为 mapper 接⼝的全限定名,包括全包名.类名。
  • <select> 查询标签:是⽤来执⾏数据库的查询操作的:
        ◦ id :是和 Interface (接⼝)中定义的⽅法名称⼀样的 ,表⽰对接⼝的具体实现⽅法。
        ◦ resultType :是返回的数据类型,也就是开头我们定义的实体类.

📝单元测试

@SpringBootTest
class UserInfoMapper2Test {@Autowiredprivate UserInfoMapper2 userInfoMapper2;@Testvoid getUserInfoAll() {List<UserInfo>userInfos=userInfoMapper2.getUserInfoAll();for (UserInfo userInfo:userInfos) {System.out.println(userInfo);}}
}


🎈增删改查操作

📝增(Insert)

🍭UserInfoMapper2接⼝:
 ///增Integer insertUser(UserInfo userInfo);
🍭UserInfoMapper.xml实现
 <insert id="insertUser">insert into userinfo (username,`password`,age,gender,phone)values (#{username},#{password},#{age},#{gender},#{phone})</insert>
如果使⽤@Param设置参数名称的话, 使⽤⽅法和注解类似
🍭UserInfoMapper接⼝:
   ///增Integer insertUser(@Param("userinfo") UserInfo userInfo);
🍭UserInfoMapper.xml实现:
<insert id="insertUser">insert into userinfo (username,`password`,age,gender,phone)values (#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})</insert>
返回⾃增 id
接⼝定义不变, Mapper.xml 实现 设置useGeneratedKeys 和keyProperty属性
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into userinfo (username,`password`,age,gender,phone)values (#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})</insert>


📝删(Delete)

🍭UserInfoMapper接⼝

  //删Integer deleteUser(Integer id);

🍭UserInfoMapper.xml实现:

<delete id="deleteUser">delete from userinfo where id=#{id};</delete>

🍭测试

  @Testvoid deleteUser() {Integer count=userInfoXmlMapper2.deleteUser(2);System.out.println(count);}


📝改(Update)

🍭UserInfoMapper接⼝
//改Integer updateUser(String username,Integer id);

🍭UserInfoMapper.xml实现:

   <update id="updateUser">update userinfo set username=#{username} where id=#{id}</update>

🍭测试

  @Testvoid updateUser() {Integer count=userInfoXmlMapper2.updateUser("zzzzz",7);System.out.println(count);}


📝查(Select)

同样的, 使⽤XML 的⽅式进⾏查询, 也存在数据封装的问题 ,我们把SQL语句进⾏简单修改, 查询更多的字段内容
🍭UserInfoMapper接⼝
  //查List<UserInfo>selectUser();

🍭UserInfoMapper.xml实现:

  <select id="selectUser">select id, username,`password`, age, gender, phone, delete_flag,create_time, update_time from userinfo</select>

🍭测试

 @Testvoid selectUser() {List<UserInfo>infoList=userInfoXmlMapper2.selectUser();for (UserInfo userInfo:infoList) {System.out.println(userInfo);}}


结果显⽰: deleteFlag, createTime, updateTime 也没有进⾏赋值.
解决办法和注解类似
  • 1. 起别名
  • 2. 结果映射
  • 3. 开启驼峰命名
其中1,3的解决办法和注解⼀样,不再多说, 接下来看下xml如果来写结果映射

🍭结果映射

<resultMap id="BaseMap" type="com.example.mybatis_test.model.UserInfo"><id column="id" property="id"></id><result column="delete_flag" property="deleteFlag"></result><result column="create_time" property="createTime"></result><result column="update_time" property="updateTime"></result></resultMap><select id="selectUser" resultMap="BaseMap">select id, username,`password`, age, gender, phone, delete_flag,create_time, update_time from userinfo</select>


注解方式和XML方式结果映射区别



六一快乐~今天吃了自助餐,几年没有穿裙子今天买了个裙子,给张老师买了白色上袖为it文化节准备上台。

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

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

相关文章

插入排序(直接插入排序、折半插入排序、希尔排序)的性能分析

目录 前言 插入排序 直接插入排序性能分析 折半插入排序性能分析 希尔排序性能分析 前言 本篇文章主要是总结插入排序的性能分析&#xff0c;具体的概念、算法、排序过程&#xff0c;我前面的文章有写&#xff0c;在这里就不再过多赘述了。 插入排序 插入排序是一种简单直…

如何从Windows的硬盘中恢复丢失或删除的照片

你有没有不小心删除了一张你再也找不回来的重要照片&#xff1f;如果是您的公司或家庭照片、婚礼或童年回忆&#xff0c;或亲人的照片怎么办&#xff1f; 根据我们的经验&#xff0c;用户通常会在清理计算机的存储/速度时遇到这样的事故&#xff0c;并最终删除包含重要图片的文…

PVE虚拟机 安装 OpenWrt

1、创建虚拟机 2、操作系统 3、磁盘&#xff0c;先删除 4、网络 5、其它默认 6、在 local 分区上传镜像 7、登录PVE虚拟机 # 切换到镜像目录 cd /var/lib/vz/template/iso/# 把镜像导入磁盘 qm importdisk 102 openwrt-buddha-version-v7_2022_-x86-64-generic-squashfs-uefi…

22 、系统安全

新的服务器到手&#xff0c;部署服务器初始化。 1、配置ip地址 网关dns解析&#xff08;static&#xff09;内网和外网。 2、安装源&#xff0c;外网&#xff08;在线即可&#xff09;&#xff0c;内网&#xff08;只能用源码包编译安装&#xff09;。 3、磁盘分区&#xff…

Nvidia Jetson/Orin +FPGA+AI大算力边缘计算盒子:轨道交通监控系统

株洲中车时代电气股份有限公司&#xff08;下称中车时代电气&#xff09;是中国中车旗下股份制企业&#xff0c;其前身及母公司——中车株洲电力机车研究所有限公司创立于1959年。中车时代电气扎根株洲&#xff0c;走好两条钢轨&#xff0c;走出两条钢轨。中车时代电气秉承“双…

Sentinel与Nacos强强联合,构建微服务稳定性基石的重要实践

一、简介 Sentinel 作为一款强大的流量控制组件&#xff0c;能够对系统入口流量进行精准控制&#xff0c;有效防止服务因突发流量冲击引起服务雪崩&#xff0c;进而导致服务瘫痪&#xff0c;确保服务的稳定性和可靠性。 Nacos 作为配置管理和服务发现平台&#xff0c;实现了配置…

高斯混合模型聚类算法的实现

目录 1. 作者介绍2. 聚类简介2.1 K-Means聚类简介2.2 高斯混合聚类简介 3. 实验过程3.1 数据集介绍3.2 代码思路3.3 算法评价3.4 代码实现3.5 实验结果 4. 参考链接 1. 作者介绍 赵子仪&#xff0c;女&#xff0c;西安工程大学电子信息学院&#xff0c;2023级研究生 研究方向&…

深度网络学习笔记(一)——self-attention机制介绍和计算步骤

self-attention机制介绍及其计算步骤 前言一、介绍和意义二、 计算细节2.1 计算Attention Score2.2 计算value2.3 计算关联结果b2.4 统一计算 三、总结 前言 Transformer是一种非常常见且强大的深度学习网络架构&#xff0c;尤其擅长处理输出为可变长度向量序列的任务&#xf…

网络原理———TCP/IP—网络层IP协议

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 目录 网络层IP协议4位版本号4位首部长度8位服务类型16位总长度16位标识 3位标志 13位片偏移8位生存时间8位协议16位首部校验和32位源IP地址 和 32位目的IP地址方案1:动态分配IP地址方案2:NAT机…

小白跟做江科大32单片机之旋转编码器计次

原理部分按照下面这个链接理解即可y小白跟做江科大32单片机之对射式红外传感器计次-CSDN博客https://blog.csdn.net/weixin_58051657/article/details/139350487https://blog.csdn.net/weixin_58051657/article/details/139350487 实验过程 1.按照江科大老师给的电路图进行连接…

C语言(内存函数)

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸各位能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎~~ &#x1f4a5;个人主页&#xff1a;小羊在奋斗 &#x1f4a5;所属专栏&#xff1a;C语言 本系列文章为个人学习笔记&#xff0c;在这里撰写成文一…

springboot+vue+mybatis博物馆售票系统+PPT+论文+讲解+售后

如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统博物馆售票系统信息管理难度大&#xff0c;容错率低&#xff0c;…

sqoop操作

介绍 sqoop是隶属于Apache旗下的, 最早是属于cloudera公司的,是一个用户进行数据的导入导出的工具, 主要是将关系型的数据库(MySQL, oracle...)导入到hadoop生态圈(HDFS,HIVE,Hbase...) , 以及将hadoop生态圈数据导出到关系型数据库中 操作 将数据从mysql中导入到HDFS中 1.全量…

Pytest框架中的Setup和Teardown功能

在 pytest 测试框架中&#xff0c;setup 和 teardown是用于在每个测试函数之前和之后执行设置和清理的动作&#xff0c;而pytest 实际上并没有内置的 setup 和 teardown 函数&#xff0c;而是使用了一些装饰器或钩子函数来实现类似的功能。 学习目录 钩子函数&#xff08;Hook…

SAP PP学习笔记14 - MTS(Make-to-Stock) 按库存生产(策略10),以及生产计划的概要

上面讲了SAP里面的基础知识&#xff0c;BOM&#xff0c;作业手顺&#xff08;工艺路线&#xff09;&#xff0c;作业区&#xff08;工作中心&#xff09;&#xff0c;MRP&#xff0c;MPS等概念&#xff0c;现在该到用的时候了。 SAP PP学习笔记07 - 简单BOM&#xff0c;派生BO…

STC8增强型单片机进阶开发--独立按键

知不足而奋进 望远山而前行 文章目录 目录 文章目录 前言 目标 内容 原理图 按键消抖 软件设计 要求 分析 实现单个按钮 实现多个按钮 使用位操作存储状态 总结 前言 本次学习旨在探索按键操作及按键消抖的原理和实现方法。通过学习原理图、按键消抖的三种方法以及软件设计的要…

如何选择D类音频放大器(数字功率放大器)

1 简介 多年来&#xff0c;音频内容一直在不断发展。从当地唱片店购买 12 英寸 LP 黑胶唱片的时代已经成为过去&#xff0c;现在我们通过流式传输几乎可即时播放云端的任何内容。虽然一些音频爱好者会为了获得新奇体验而重拾黑胶唱片&#xff0c;但今天绝大多数的音频都是以数…

JVM学习笔记(持续更新)

JDK、JRE、JVM区别&#xff1f; 类加载过程 装载 验证 准备 解析 初始化 类加载器分类 双亲委派模型 如何打破双亲委派模型&#xff1f; 自定义类加载器&#xff0c;集成ClassLoader类重写loadClass,如Tomcat JVM内存模型 JVM 需要使用计算机的内存&#xff0c;Java 程序…

【LeetCode 101】对称二叉树

1. 题目 2. 分析 这道题比较经典。我又一次做错了&#xff0c;这次是花了20min都没有做出来。 最开始我的思想就是&#xff0c;递归比较左根节点的左子树和右根节点的右子树是否对称即可&#xff0c;然后觉得能解决问题了&#xff0c;便动手coding。哪知道&#xff0c;又碰到了…

电源滤波器怎么选用

电源滤波器怎么选用 滤波器应用场景及作用第一步&#xff1a;第二步&#xff1a;第三步&#xff1a;第四步&#xff1a; 滤波器应用场景及作用 可以有效解决EMC测试无法通过、端口防护、滤除干扰、设备保护等问题 主要功能有: 1、降低主电源谐波; 2、保护驱动装置电力电子元件…