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

Mybatis---入门

1. 什么是MyBatis?

MyBatis是⼀款优秀的 持久层 框架,⽤于简化JDBC的开发。

MyBatis本是 Apache的⼀个开源项⽬iBatis,2010年这个项⽬由apache迁移到了google code,并且改名为MyBatis 。2013年11⽉迁移到Github.

官⽹:MyBatis中⽂⽹

在上⾯我们提到⼀个词:持久层

持久层:指的就是持久化操作的层, 通常指数据访问层(dao), 是⽤来操作数据库的

总而言之,Mybatis就是一个用于更加方便与数据库交互的框架

 2.MyBatis入门

Mybatis操作数据库的步骤:

1. 准备⼯作(创建springboot⼯程、引⼊Mybatis的相关依赖、数据库表准备、实体类)

2. 配置Mybatis(数据库连接信息)

3. 编写SQL语句(注解/XML)

4. 测试

2.1准备工作

2.1.1创建springboot⼯程

在pom文件中右键

没有的话可以去下载一下插件

点击OK

 

添加这两个完成导⼊ mybatis的起步依赖、mysql的驱动包 ,刷新Maven即可

 

2.1.2 数据准备 

创建数据库资源实体类

DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4; 
 -- 使⽤数据数据
USE mybatis_test;
-- 创建表
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (
 `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() ON UPDATE now(),
 PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 
-- 添加⽤⼾信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

创建对应实体类:名称要对应,这个也是知识点后面会提到

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;
}

(这里留了三个数据不一致,为后续展示做准备)

2.2 配置数据库连接字符串

Mybatis中要连接数据库,需要数据库相关参数配置

• MySQL驱动类

• 登录名

• 密码

• 数据库连接字符串

如果是application.yml⽂件, 配置内容如下:(以我的为例)


spring:
  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

数据库的密码记得更换!!

注意事项:

如果使⽤ MySQL 是 5.x 之前的使⽤的是"com.mysql.jdbc.Driver",如果是⼤于 5.x 使⽤的

是“com.mysql.cj.jdbc.Driver”

2.3创建持久层接口 

以Select查询为例

@Mapper
public interface UserInfoMapper {
    @Select("select `username`, `age`, `password` from user_info")
    public List<UserInfo> getAllUserInfo();
}

 @Mapper注解:用于标识是MyBatis中的Mapper接⼝,可以将类交给Spring容器管理

@Select注解:代表的就是select查询,也就是注解对应⽅法的具体实现内容

2.4单元测试

1.我们可以用自动创建的测试类直接进行测试

@SpringBootTest,该测试类在运⾏时,就会⾃动加载Spring的运⾏环境,在其他测试类中没有时一定要加!!!

点击运行,获得查询结果

2.也可以使⽤Idea ⾃动⽣成测试类

1. 在需要测试的Mapper接⼝中, 右键 -> Generate -> Test

2.选取要添加的测试方法

 3.Mybatis基础操作

3.1 打印⽇志

在Mybatis当中我们可以借助⽇志, 查看到sql语句的执⾏、执⾏传递的参数以及执⾏结果

在yml配置⽂件中进⾏配置即可:

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

再次运行查看日志:

多出三部分信息

①: 查询语句

②: 传递参数及类型

③: SQL执⾏结果

 

3.2 参数传递

需求: 查找id=4的⽤⼾,对应的SQL就是: select * from user_info where id=4

@Select("select username, `password`, age, gender, phone from user_info where 
id= 4 ")
UserInfo queryById();

但这样只能传递固定的参数,显然不能够满足我们的需求,我们可以使用#{}来获取参数

    //参数传递
    @Select("select * from user_info where id = #{id}")
    public UserInfo getUserInfoById(Integer id);

内部的  “id” 与方法中的名称保持一致(如果只有一个参数可以不必保持一致)

或者使用@Param注解,如果使⽤ @Param 设置别名, #{...}⾥⾯的属性名必须和

@Param 设置的⼀样

    @Select("select * from user_info where id = #{id666}")
    public UserInfo getUserInfoById(@Param("id666") Integer id);

添加测试用例:

    @Test
    void getUserInfoById() {
        UserInfo userInfo = userInfoMapper.getUserInfoById(1);
        System.out.println(userInfo);
    }

3.3@Insert

Mapper接⼝

    @Insert("Insert into user_info (`id`, `username`, `password`, `age`) values (#{id}," +
            " #{username}, #{password}, #{age})")
    Integer insert(UserInfo userInfo);

直接使⽤UserInfo对象的属性名来获取参数

如果设置了 @Param 属性, #{...} 需要使⽤ 参数.属性 来获取

//    @Insert("Insert into user_info (`id`, `username`, `password`, `age`) values (#{userInfo.id}, #{userInfo.username}, #{userInfo.password}, #{userInfo.age})")
//    Integer insert(@Param("userInfo") UserInfo userInfo);
测试用例:
    @Test
    void insert() {
        //new一个UserInfo传过去
        UserInfo userInfo = new UserInfo();
        userInfo.setId(8);
        userInfo.setUsername("888");
        userInfo.setPassword("123456");
        userInfo.setAge(18);
        //可以多传入参数,但接收不到,不能写入数据库中
        //userInfo.setGender(1);
        Integer count = userInfoMapper.insert(userInfo);
        System.out.println("影响行数:" + count);
    }

返回主键

Insert 语句默认返回的是 受影响的⾏数

但有些情况下, 数据插⼊之后, 还需要有后续的关联操作, 需要获取到新插⼊数据的id

⽐如订单系统

当我们下完订单之后, 需要通知物流系统, 库存系统, 结算系统等, 这时候就需要拿到订单ID

如果想要拿到⾃增id, 需要在Mapper接⼝的⽅法上添加⼀个Options的注解

    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("Insert into user_info (`id`, `username`, `password`, `age`) values (#{id}," +
            " #{username}, #{password}, #{age})")
    Integer insert(UserInfo userInfo);

 

    @Test
    void insert() {
        //new一个UserInfo传过去
        UserInfo userInfo = new UserInfo();
        userInfo.setId(8);
        userInfo.setUsername("888");
        userInfo.setPassword("123456");
        userInfo.setAge(18);
        //可以多传入参数,但接收不到,不能写入数据库中
        //userInfo.setGender(1);
        Integer count = userInfoMapper.insert(userInfo);
        System.out.println("影响行数:" + count + ", 数据ID:" + userInfo.getId());
    }

useGeneratedKeys:这会令 MyBatis 使⽤ JDBC 的 getGeneratedKeys ⽅法来取出由数据库内

部⽣成的主键(⽐如:像 MySQL 和 SQL Server 这样的关系型数据库管理系统的⾃动递增字

段),默认值:false.

keyProperty:指定能够唯⼀识别对象的属性,MyBatis 会使⽤ getGeneratedKeys 的返回值或

insert 语句的 selectKey ⼦元素设置它的值,默认值:未设置

使用 userInfo.getId()获取id

3.4@Delete

    @Delete("delete from user_info where id = #{id}")
    public void delete(Integer id);
    @Test
    void delete() {
        userInfoMapper.delete(8);
    }

3.5@Update

    @Update("update user_info set username = #{username} where id = #{id}")
    public void update(UserInfo userInfo);
    @Test
    void update() {
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername("zhaoliu666");
        userInfo.setId(5);
        userInfoMapper.update(userInfo);
    }

3.6属性名称映射

我们在上⾯查询时发现, 有⼏个字段是没有赋值的, 只有Java对象属性和数据库字段⼀模⼀样时, 才会进⾏赋值

明明查询到了数据库中的信息但没有打印出来

原因分析:

当⾃动映射查询结果时,MyBatis 会获取结果中返回的列名并在 Java 类中查找相同名字的属性(忽略⼤⼩写)。 这意味着如果发现了 ID 列和 id 属性,MyBatis 会将列 ID 的值赋给 id 属性

我们知道数据库属性命名方式通常为  小写字母  加  下划线  分割 

而Java属性命名规范是小驼峰

在Java中写数据库的属性就不太合适了

解决方法有三种:

1. 起别名

2. 结果映射

3. 开启驼峰命名

3.6.1 起别名

    //1.  as 起别名
    @Select("select create_time as createTime from user_info where id = #{id}")
    public UserInfo getUserInfoAsName(Integer id);

注意是将原数据库属性名as为Java属性名称

3.6.2结果映射

    //2. Results
    @Select("select * from user_info where id = #{id}")
    @Results( value ={
            @Result(property = "deleteFlag", column = "delete_flag"),
            @Result(property = "createTime", column = "create_time"),
            @Result(property = "updateTime", column = "update_time")
    })
    public UserInfo getUserInfoResults(Integer id);

如果只有括号内的内容value可以省略,加了id等就不可以省略了

如果其他SQL, 也希望可以复⽤这个映射关系, 可以给这个Results定义⼀个名称,加入id属性:

    //2. Results
    @Select("select * from user_info where id = #{id}")
    @Results(id = "resultMap", value ={
            @Result(property = "deleteFlag", column = "delete_flag"),
            @Result(property = "createTime", column = "create_time"),
            @Result(property = "updateTime", column = "update_time")
    })
    public UserInfo getUserInfoResults(Integer id);
    //复用results
    @Select("select * from user_info where id = #{id}")
    @ResultMap("resultMap")
    public UserInfo getUserInfoResultsMap(Integer id);

3.6.3开启驼峰命名(推荐)

这个方法可以直接将写的sql代码中像这种的“create_time”属性自动映射为小驼峰(不是转化)

在yml文件中配置:

mybatis:
 configuration:
   map-underscore-to-camel-case: true #配置驼峰⾃动转换

 代码:

    //3.配置驼峰⾃动转换  记得写的是原SQL语句
    @Select("select create_time from user_info where id = #{id}")
    public UserInfo getUserInfoCase(Integer id);

4. MyBatis XML配置⽂件

Mybatis的开发有两种⽅式:

1. 注解

2. XML

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

MyBatis XML的⽅式需要以下两步:

1. 配置数据库连接字符串和MyBatis

2. 写持久层代码

4.1 配置数据库连接字符串和MyBatis

在yml文件中配置:

# 数据库连接配置
spring:
  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
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml
  configuration: # 配置打印 MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true #3.配置驼峰⾃动转换

 图标中的小鸟插件是:

可以帮助绑定代码

4.2 写持久层代码

持久层代码分两部分

1. ⽅法定义 Interface(可见无论如何也要建立接口)

2. ⽅法实现: XXX.xml

 1.添加Mapper接口

2. 添加 UserInfoXMLMapper.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.cym.mybatis.mapper.UserInfoXmlMapper">
 
</mapper>

4.2.1Select

<?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.cym.mybatis.mapper.UserInfoXmlMapper">
    <select id="getAllUserInfo" resultType="com.cym.mybatis.model.UserInfo">
        select `username`, `age`, `password` from user_info
    </select>
</mapper>

<mapper> 标签:需要指定 namespace 属性,表⽰命名空间,值为 mapper 接⼝的全限定

名,包括全包名.类名。

<select> 查询标签:是⽤来执⾏数据库的查询操作的

id :是和 Interface (接⼝)中定义的⽅法名称⼀样的,表⽰对接⼝的具体实现⽅法

resultType :是返回的数据类型,也就是我们定义的实体类

同样进行单元测试:

 

 

在XML文件中仍然会出现参数不匹配的现象 

解决办法和注解类似:

1. 起别名

2. 结果映射

3. 开启驼峰命名

其中1,3的解决办法和注解⼀样,不再多说, 接下来看下xml如果来写结果映射

    <resultMap id="BaseMap" type="com.cym.mybatis.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>

 

4.2.2Insert 

    <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
        insert into user_info (`id`, `username`, `password`, `age`)values (#{userInfo.id},
        #{userInfo.username}, #{userInfo.password}, #{userInfo.age})
    </insert>

如果使⽤@Param设置参数名称的话, 使⽤⽅法和注解类似

同样也可以使用(useGeneratedKeys="true" keyProperty="id")获取自增id

4.2.3Delete

4.3.3Update

5.其他查询

5.1多表查询

其他(SQL, 映射关系和实体类)基本都一致,都是通过映射关系,把SQL运⾏结果和实体类关联起来,只是在写接口时写入多表查询的代码:

但我们通常不建议在开发环境中使用多表查询,为什么呢?

主要有两个原因:

1.生产环境中数据库资源非常宝贵

2.服务器扩容比MySQL扩容更加容易

生产环境中数据库资源非常宝贵:

首先环境分为:开发环境,测试环境,预发布环境(没上线),生产环境(上线)

预发布环境和生产环境使用的是同一个数据库,多表查询可能会导致越级访问等问题,不利于上线。

服务器扩容比MySQL扩容更加容易:

服务器扩容我们程序员就可以完成,也更加便宜,而数据库扩容就需要专业的人员了。

当我们要联合两张表进行查询时,假设使用多表查询消耗10ms,分别查询两张表后合并消耗7*2=14ms,看似多表查询快,但是查询两张表可以通过多线程完成,而多表查询只能单线程执行,会占用其他线程的时间,在真实生产中如果阻塞了其他线程服务,就会导致效率下降,我们要避免这种情况。

http://www.dtcms.com/a/112362.html

相关文章:

  • 音视频基础(音频常用概念)
  • zk基础—2.架构原理和使用场景一
  • python爬虫:小程序逆向实战教程
  • leetcode数组-有序数组的平方
  • 软件工程面试题(二十五)
  • 58.基于springboot老人心理健康管理系统
  • 网络:华为HCIA学习笔记:ICMP协议
  • List结构之非实时榜单实战
  • Nginx配置伪静态,URL重写
  • 通过 ModelScope 下载模型,解决sentence-transformers/all-MiniLM-L6-v2无法下载问题
  • 【leetcode100】数组中的第K个最大元素
  • Scala 面向对象编程总结
  • 【虚拟机VMware】银河麒麟系统虚拟机:网络异常处理
  • FrameWork基础案例解析(四)
  • HTTPS 之fiddler抓包--jmeter请求
  • Dynamics 365 Business Central Subscription Recurring Billing 订阅和分期付款详解
  • winRAR禁止广告弹窗
  • Elixir语言的消息队列
  • 进程和线程的概念及Linux操作
  • 解释区块链技术的应用场景和优势
  • 【实战】如何基于 Python Flask 快速开发一个支持 OpenAI 流式接口的 LLM Server
  • 【MySQL】01.MySQL环境安装
  • O(1) 时间复杂度数据设计题
  • 我考研拟录取=稳了吗?
  • Element-plus弹出框popover,使用自定义的图标选择组件
  • sqlalchemy查询json
  • STM32CubeMX-H7-11-IIC读写MPU6050模块(上)-软件IIC协议的解析、封装,实现基本功能获取MPU6050的ID
  • 结肠镜3D视频数据集-C3VD论文中文版
  • 构建自己的私有 Git 服务器:基于 Gitea 的轻量化部署实战指南
  • 2025年3月 Scratch 图形化(二级)真题解析 中国电子学会全国青少年软件编程等级考试