MyBatis 使用入门

news2024/10/7 7:34:07

1. 什么是MyBatis

MyBatis是一款持久层框架,用于简化JDBC的开发(持久层指的就是持久化操作的层,通常指数据访问层(dao),即用于操作数据库),简单来说MyBatis 是更简单完成程序和数据库交互的框架。下面我们通过一个例子来简单了解MyBatis

1.1 创建项目

创建Spring Boot 项目,并导入mybatis依赖和mysql驱动包:

1.2 数据准备

创建用户表和对应的实体类,并在配置文件中配置数据的的信息(url,用户名,密码等)

创建用户表:

-- 创建数据库
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.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:
  application:
    name: J20240402-MyBatis
#数据库连接配置
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

driver-class-name用于指定数据库驱动程序的类名 

1.3 使用示例

创建一个接口:UserInfoMapper, 用于执行各种SQL语句:

package com.example.mybatis.mapper;

import com.example.mybatis.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;
@Mapper
public interface UserInfoMapper {
    @Select("select * from userinfo")
    List<UserInfo> getUserInfoAll();
}

注意:

  • 数据库相关操作一般放在mapper包下。
  • @Mapper注解的作用是将一个接口标记为MyBatis的Mapper接口,告诉MyBatis框架需要为这个接口生成对应的实现类,用于执行数据库操作。
  • @Select注解代表这个SQL语句是用于查询操作。

 接下来我们通过单元测试来测试我们的代码能否正常运行:

我们生成项目时会自动生成一个测试版本:

我们在这里写测试代码:

package com.example.mybatis;

import com.example.mybatis.mapper.UserInfoMapper;
import com.example.mybatis.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;

@SpringBootTest
class J20240402MyBatisApplicationTests {
    @Autowired()
    private UserInfoMapper userInfoMapper;
    @Test
    void contextLoads() {
        List<UserInfo> userInfos = userInfoMapper.getUserInfoAll();
        System.out.println(userInfos);
    }

注意:被@Mapper注解注解的接口会在项目启动时由MyBatis框架生成对应的实现类,并将该实现类作为Bean交给Spring容器管理。这样,在Spring容器中就可以使用@Autowired注解来注入Mapper接口的实例,从而在代码中直接调用Mapper接口中定义的方法来执行数据库操作。

接下来我们执行代码:

点击方法左边的绿色三角形然后点击Run即可运行:

我们可以看到成功打印出了信息。

接下来我们在正式项目中编写代码:

我们同样使用三层架构的模式:

package com.example.mybatis.controller;

import com.example.mybatis.model.UserInfo;
import com.example.mybatis.servise.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
    @Autowired
    private UserService userService;
    @RequestMapping("/getUserInfoAll")
    public List<UserInfo> getUserInfoAll() {
        return userService.getUserInfoAll();
    }
}
package com.example.mybatis.servise;

import com.example.mybatis.mapper.UserInfoMapper;
import com.example.mybatis.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserInfoMapper userInfoMapper;
    public List<UserInfo> getUserInfoAll() {
        return userInfoMapper.getUserInfoAll();
    }
}

运行代码,在浏览器访问:

可以看到返回的json格式的数据 ,我们发现返回的数据中后三个字段的值都为null,原因我们下面再讲,接下来先说一下单元测试。

1.4 单元测试

上面我们已经使用过单元测试,但是如果我们要测试的方法很多,如果全部写在一个类里的话看起来会非常的杂乱,所以我们可以对应我们正式项目中的代码“照搬”进Test项目中,我们可以使用Idea提供的快捷方式来快速生成这一代码:

在要测试的类点击鼠标右键,点击generate

然后点击Test:

把下面我们要测试的方法打上勾点击OK :

我们发现下面就已经生成了一个对应的Test代码:

package com.example.mybatis.mapper;

import org.junit.jupiter.api.Test;

class UserInfoMapperTest {
    @Test
    void getUserInfoAll() {
        
    }
}

我们在其中注入对应的依赖即可测试:

package com.example.mybatis.mapper;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void getUserInfoAll() {
        System.out.println(userInfoMapper.getUserInfoAll());
    }
}

注意要加上@SpringBootTest注解,不然无法通过@Autowried注入,同样点击绿色三角形运行指定方法:

运行成功。 

2. MyBatis 基础操作

2.1 打印日志

在MyBatis中我们可以借助日志查看sql语句的执行,传递的参数以及执行结果,只需在配置文件中进行配置即可:

mybatis:
configuration: # 配置打印 MyBatis⽇志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

我再运行单元测试:

可以看到多出了MySql返回的结果

2.2 参数传递

很多时候我们的SQL语句是不能写死的,于是就需要把某些可能会改变的部分SQL作为参数传入:

@Mapper
public interface UserInfoMapper {
    @Select("select * from userinfo where id = #{id}")
    List<UserInfo> getUserInfoId(Integer id);
}

我们同样生成单元测试代码来测试

@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void getUserInfoId() {
        System.out.println(userInfoMapper.getUserInfoId(2));
    }
}

我们查询id为2的数据:

可以看到MyBatis帮我们转为了对应的JDBC语句,注意编写代码时,#{ }中的字段名要和方法中的参数名对应,否则有多个参数时会出错。

传递多个参数:

@Mapper
public interface UserInfoMapper {
    @Select("select * from userinfo where id = #{id} and age = #{age}")
    List<UserInfo> getUserInfoIdAndAge(Integer id, Integer age);
}

传递多个参数时也可以根据参数位置来传:

@Mapper
public interface UserInfoMapper {
    @Select("select * from userinfo where id = #{param1} and age = #{param2}")
    List<UserInfo> getUserInfoIdAndAge(Integer id, Integer age);
}

也可以使用@Param 注解指定参数对应的位置:

@Mapper
public interface UserInfoMapper {
    @Select("select * from userinfo where username = #{userName} and id = {id}")
    List<UserInfo> getUserInfoNameAndId(@Param("userName")String name, @Param("id") Integer id);
}

注意:@Param注解中 对应的是 #{ } 中的字段名,使用时推荐既要保证#{}中字段名和参数名一致,同时也要加上@Param注解。

2.3 Insert操作

增加操作需要使用@Insert注解

@Mapper
public interface UserInfoMapper {
    @Insert("insert  into userinfo(id, username, password, age) values (#{id}, #{userName}, #{password}, #{age})")
    Integer insert(UserInfo userInfo);
}

这是我们借助UserInfo对象来传递参数,userinfo(id, username, password, age) 中的字段对应的时userinfo表中的字段,#{ }中对应的是UserInfo对象中的属性名。

单元测试:

@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("liHua");
        userInfo.setPassword("liHua");
        userInfo.setAge(20);
        System.out.println(userInfoMapper.insert(userInfo));
    }
}

返回了1表示影响了一行, 我们在数据库中查询:

插入成功。 

注意:这里我们没有给id赋值,因为我们建表时标识了让id自增,所以id会自动自增,很多场景我们需要根据id的值做一些业务,所以我们需要获取到id。

@Mapper
public interface UserInfoMapper {
    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert  into userinfo(id, username, password, age) values (#{id}, #{userName}, #{password}, #{age})")
    Integer insert(UserInfo userInfo);
}

@Options(useGeneratedKeys = true, keyProperty = "id"): 这是 MyBatis 的一个注解,用于指示生成主键并将其赋值给指定的属性。useGeneratedKeys = true 表示要生成主键,keyProperty = "id" 表示将生成的主键值赋给 UserInfo 对象中的 id 属性。于是我们就可以从UserInfo的对象中获取到id:

@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void insert() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUserName("liHua");
        userInfo.setPassword("liHua");
        userInfo.setAge(20);
        System.out.println(userInfoMapper.insert(userInfo));
        System.out.println("id = " + userInfo.getId());
    }
}

注意:

调用insert方法之后UserInfo对象中的id才会被赋值。

如果这里给参数加上 @Param注解 会把 userInfo对象整体当作一个参数,需要写成如下形式:

    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert  into userinfo(id, username, password, age) values (#{userInfo.id}, #{userInfo.userName}, #{userInfo.password}, #{userInfo.age})")
    Integer insert(@Param("userInfo") UserInfo userInfo);

2.4 Delete 操作

与前面相似,我们需要使用@Delete注解:

@Mapper
public interface UserInfoMapper {
    @Delete("delete from userinfo where id = #{id}")
    Integer delete(Integer id);
}
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void delete() {
        System.out.println(userInfoMapper.delete(5));
    }
}

删除id为5的数据:

2.5 Update 操作

@Mapper
public interface UserInfoMapper {
    @Update("update userinfo set password = #{password}, age = #{age}, gender = #{gender} where id = #{id}")
    Integer update(UserInfo userInfo);
}
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Test
    void update() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(1);
        userInfo.setPassword("666");
        userInfo.setAge(19);
        userInfo.setGender(2);
        System.out.println(userInfoMapper.update(userInfo));
    }
}

2.6 Select 操作

Select操作前面我们已经演示过,但在途中遇到了一些问题:

查询到的后三个字段的值都为null,这是因为我们是使用UserInfo对象来接收的数据,当字段名相同时,会自动赋值,我们对比我们的数据库字段和UserInfo类:

我们发现我们没有接收到的三个字段,都是字段名对应不上的字段。

解决方法:

1. 起别名

我们知道了赋值失败的原因是字段名对不上,那么我们就可以通过SQL语句中的取别名的方式来,使字段名能对应得上:

@Mapper
public interface UserInfoMapper {
    @Select("select id, username, password, age, dender, phone, " +
            "delete_flag as deleteFlag, create_time as createTime, " +
            "update_time as updateTime from userinfo")
    List<UserInfo> getUserInfoAll();
}

2.  结果映射

使用@Results 和 @Result注解对数据库字段和对应类的属性进行结果映射:

@Mapper
public interface UserInfoMapper {
    @Results({
            @Result(column = "delete_flag", property = "deleteFlag"),
            @Result(column = "create_time", property = "creatTime"),
            @Result(column = "update_time", property = "updateTime")
    })
    @Select("select * from userinfo")
    List<UserInfo> getUserInfoAll();
}

在此基础上,我们可以给@Results 的id属性赋值,当有其他地方需要用到这个映射关系时,可以直接使用@ResultMap注解使用这个映射关系,而不用再重新写一遍映射关系:

@Mapper
public interface UserInfoMapper {
    @Results(id = "resultMap", value = {
            @Result(column = "delete_flag", property = "deleteFlag"),
            @Result(column = "create_time", property = "createTime"),
            @Result(column = "update_time", property = "updateTime")
    })
    @Select("select * from userinfo")
    List<UserInfo> getUserInfoAll();

    @ResultMap("resultMap")
    @Select("select * from userinfo")
    List<UserInfo> getUserInfoAll2();
}

3. 驼峰自动转换

数据库字段和Java类字段对应不上的原因是因为命名规范不同导致的,Java是驼峰法命名,而SQL是以蛇形命名,所以我们可以在配置文件中添加驼峰自动转换配置,把接收到的字段自动转为驼峰形式:

mybatis:
  configuration: # 配置打印MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true #配置驼峰⾃动转换
@Mapper
public interface UserInfoMapper {
    @Select("select * from userinfo")
    List<UserInfo> getUserInfoAll();
}

现在我们直接使用最开始的代码也能正常获取到值:

 

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

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

相关文章

C++入门4.引用

目录 1.引用概念&#xff1a; 2.引用特性&#xff1a; 3.常引用&#xff1a; 4.使用场景&#xff1a; 引用和指针的区别&#xff1a; 1.引用概念&#xff1a; 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空…

【C++】模拟实现红黑树(插入)

目录 红黑树的概念 红黑树的性质 红黑树的调整情况 红黑树的模拟实现 枚举类型的定义 红黑树节点的定义 插入函数的实现 旋转函数的实现 左旋 右旋 自检函数的实现 红黑树类 红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储…

详解protected访问限定符

1.同一个包中的同一类 package demo1;public class Test1 {protected int a 10;protected void b() {System.out.println("这是protected修饰的成员方法");}public static void main(String[] args) {Test1 test new Test1();System.out.println(test.a);test.b()…

燃气管网安全运行监测系统功能介绍

燃气管网&#xff0c;作为城市基础设施的重要组成部分&#xff0c;其安全运行直接关系到居民的生命财产安全和城市的稳定发展。然而&#xff0c;随着城市规模的不断扩大和燃气使用量的增加&#xff0c;燃气管网的安全运行面临着越来越大的挑战。为了应对这些挑战&#xff0c;燃…

华媒舍:3个科学指导,协助油管大V写下爆款文章

油管&#xff08;YouTube&#xff09;作为一个重要的视频分享平台&#xff0c;吸引了很多的观众和原创者。作为一位油管大V&#xff0c;你可能会一直在努力提升自己的文章质量以吸引更多的观众和订阅者。下面我们就为您提供三个科学指导&#xff0c;帮助自己写下更具有爆品发展…

可视化图表组件:仪表盘,监控数据关键指标信息,海量示例。

仪表盘组件&#xff08;Dashboard Component&#xff09;是一种常见的可视化设计组件&#xff0c;用于展示和监控数据的关键指标和信息。它通常以仪表盘的形式呈现&#xff0c;类似于汽车仪表盘&#xff0c;可以通过各种图表、指示器和控件来展示数据&#xff0c;并提供交互和操…

Linux安装JDK17等通用教程

一、查看Linux系统是否有自带的jdk 1、查看当前是否有jdk版本&#xff0c;命令如下&#xff1a; java -version2、检测jdk的安装包&#xff0c;命令如下&#xff1a; rpm -qa | grep java3、接着进行一个个删除包&#xff0c;命令如下&#xff1a; rpm -e --nodeps 包名4、…

数据结构day2--双向链表

双向链表: 即可以从头遍历到尾部和从尾部遍历到头部的链表&#xff0c;每个结点包括两个链域&#xff1a;前驱指针域和后继指针域&#xff0c;所以比起单向链表&#xff0c;其可以在任意一个结点访问前后两个结点 关于双向链表的一个完整步骤为&#xff1a; 创建一个表头结构…

基于SSM的邮票鉴赏系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的邮票鉴赏系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

VBA数据库解决方案第九讲:把数据库的内容在工作表中显示

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…

get请求搜索功能爬虫

<!--爬虫仅支持1.8版本的jdk--> <!-- 爬虫需要的依赖--> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.2</version> </dependency>…

Unity开发者3D模型基础

术语“3D 建模”是指使用特殊软件创建对象或表面的 3D 数字表示的过程。 3D 模型可用于各种不同的目的&#xff0c;包括电影、视频游戏、建筑和工程。 3D 建模也是创建虚拟现实 (VR) 和增强现实 (AR) 体验工作的重要组成部分。 我们通常通过构建或获取 3D 模型并将其导入 Unit…

2024/4/5 AT24C02 总线(I²C总线)

存储器的介绍&#xff1a; 一、易失性存储器RAM&#xff1a;存储速度快&#xff0c;掉电丢失 SRAM&#xff08;静态RAM&#xff09;&#xff1a;极快DRAM&#xff08;动态RAM&#xff09;&#xff1a;需要配一个扫描电路&#xff0c;进行“补电”&#xff08;动态刷新&#x…

【数据库】主流数据库及其常用工具简单科普

主流数据库及其常用工具 数据库分类关系型数据库&#xff08;RDBMS&#xff09;非关系型数据库&#xff08;NoSQL&#xff09;混合型数据库&#xff08;Hybrid Databases&#xff09;对象关系数据库&#xff08;ORDBMS&#xff09;多维数据库&#xff08;Multidimensional Data…

MySQL介绍和安装

MySQL介绍和安装 文章目录 MySQL介绍和安装1.MySQL介绍2.MySQL安装2.1 主机初始化2.1.1 设置网卡名和ip地址2.1.2 配置镜像源2.1.3 关闭防火墙2.1.4 禁用SELinux2.1.5 设置时区 2.2 包安装2.2.1 Rocky和CentOS 安装 MySQL2.2.2 Ubuntu 安装 MySQL 2.3 二进制安装安装MySQL2.3.1…

解决windows下Qt Creator显示界面过大的问题

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;QT❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 问题描述 解决方法 1、右击此电脑--->属性 2、点击高级系统设置--->点击环境变量 3、 找到系…

Zookeeper学习二集群搭建

Zookeeper 集群介绍 Leader选举&#xff1a; Serverid&#xff1a;服务器ID 比如有三台服务器&#xff0c;编号分别是1,2,3。 编号越大在选择算法中的权重越大。 Zxid&#xff1a;数据ID 服务器中存放的最大数据ID.值越大说明数据 越新&#xff0c;在选举算法中数据…

【价格表】2024年统计大厂云服务器实时优惠活动,推荐最具性价比的云服务器,最便宜,华为云 京东云 阿里云 腾讯云低至50元/年

写作初衷&#xff1a; 作为一个购买多年云服务器经历的爱好者&#xff0c;最喜欢看各厂商的优惠活动&#xff0c;反复比较各厂商的优惠&#xff0c;找到最具性价比的那一款。 我就像一个互联网的小人物&#xff0c;在京东云、阿里云、腾讯云的官网里反复对比、反复横跳…

电子邮件的优点和缺点

没有任何一种通信方式能像电子邮件一样长期如此受欢迎。当你想到忙碌的职业人士在企业或办公室环境中工作时&#xff0c;你可能会想象他们正专心致志地给某人写邮件&#xff0c;按照指示传递信息。电子邮件的优点和缺点是什么&#xff1f;优点包括易于访问、透明度高&#xff0…

达梦disql登录数据库显示“未连接”

问题&#xff1a;达梦数据库在使用disql登录时&#xff0c;显示“未连接”。 指定了IP和端口号还是连接异常。 [dmdbatest ~]$ disql sysdba/Dameng123 disql V8 SQL> select * from v$instances; 未连接 SQL> exit [dmdbatest ~]$ disql sysdba/Dameng123localhost:52…