MyBatis 入门

目录

[一. MyBatis 概述](#一. MyBatis 概述)

[二. MyBatis 入门](#二. MyBatis 入门)

[1. 创建工程, 导入依赖](#1. 创建工程, 导入依赖)

[2. 数据准备](#2. 数据准备)

[3. 配置数据库相关信息](#3. 配置数据库相关信息)

[4. 编写持久层代码](#4. 编写持久层代码)

[5. 编写测试代码](#5. 编写测试代码)

[三. MyBatis基础操作.](#三. MyBatis基础操作.)

[1. 打印日志](#1. 打印日志)

[2. 参数传递](#2. 参数传递)

[3. 增 (Insert)](#3. 增 (Insert))

[4. 删 (Delete)](#4. 删 (Delete))

[5. 改 (Update)](#5. 改 (Update))

[6. 查 (Select)](#6. 查 (Select))

[(1) 起别名](#(1) 起别名)

[(2) 结果映射](#(2) 结果映射)

[(3) 开启驼峰命名与蛇形命名转换](#(3) 开启驼峰命名与蛇形命名转换)

[四. MyBatis XML配置文件](#四. MyBatis XML配置文件)

[(1) 配置连接字符串和MyBatis](#(1) 配置连接字符串和MyBatis)

[(2) 编写持久层代码](#(2) 编写持久层代码)

[① 添加Mapper接口](#① 添加Mapper接口)

[② 添加UserInfoXMLMapper.xml](#② 添加UserInfoXMLMapper.xml)

[③ 单元测试](#③ 单元测试)

[(3) 增删改查操作](#(3) 增删改查操作)

[① 增 (Insert)](#① 增 (Insert))

[② 删 (Delete)](#② 删 (Delete))

[③ 改 (Update)](#③ 改 (Update))

[④ 查 (Select)](#④ 查 (Select))


一. MyBatis 概述

前面我们学习过使用JDBC编程对数据库进行操作. 不过JDBC对于数据库的操作过于麻烦, 所以我们在Spring中引入MyBatis框架, 来帮助我们对数据库进行操作.

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

持久层(Mapper/Dao), 就是用来操作数据库的.

简单来说, MyBatis 是一个能够更简单地完成程序和数据库交互的框架. 接下来,我们就通过一个入门程序,让大家感受一下通过Mybatis如何操作数据

二. MyBatis 入门

1. 创建工程, 导入依赖

MyBatis 是一个持久层框架, 具体的数据存储和数据操作还是在MySQL中进行的. 所以我们还需要添加MySQL驱动.

项目工程创建完成后, 我们就会发现: 在pom.xml文件中, 自动导入了Mybatis依赖和MySQL驱动依赖.

2. 数据准备

创建用户表:

sql 复制代码
-- 创建数据库 
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: (其中实体类的属性名 和表中的字段名 一一对应)

java 复制代码
package com.jrj.mybatis;

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

3. 配置数据库相关信息

MyBatis中 要连接数据库 需要配置数据库的相关参数, 包括数据库URL, 用户名, 密码, MySQL驱动类. 这些配置信息均在配置文件中完成.

java 复制代码
# 数据库连接配置 
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
	username: root
	password: root
	driver-class-name: com.mysql.cj.jdbc.Driver

如上代码, mybatis_test 就是数据库的名称.

[注意]: 如果password是纯数字的话, 需要在数字的的外围用单引号括起来.

4. 编写持久层代码

java 复制代码
package com.jrj.mybatis.mapper;

import com.jrj.mybatis.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")
    public List<UserInfo> selectAllUser();
}

@Mapper 注解: 表示MyBatis中的Mapper接口.

@Select 注解: 表示Select查询 (代表注解中方法的具体实现)

[注意]: 像上述代码这样返回多条数据的接口, 一定要用List来接收数据; MyBatis的持久层接口一般都叫 "xxxMapper".

5. 编写测试代码

自动生成:

在想要测试的接口中点击右键, 点击生成, 选择想要测试的方法, 即可生成测试代码.

三. MyBatis基础操作.

1. 打印日志

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

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

配置好之后, 重新运行程序, 即可看到SQL的执行内容.

2. 参数传递

如果我们现在需要查找 id=4 的用户, 对应的 sql语句 就是 select * from userinfo where id=4.

java 复制代码
@Select("select * form userinfo where id = 4")
public UserInfo selectUser();

但是这样的话, 就只能查询到 id为4 用户的数据. 所以我们不建议把sql语句写死 . 我们需要把 id 变为动态的数值.

解决办法就是在selectUser方法中添加一个参数(id), 将方法中的参数传递给sql语句 .使用**#{}**的方式在sql语句中获取方法中传递的参数.

java 复制代码
@Select("select * from userinfo where id = #{id}")
public UserInfo selectUser(Integer id);
java 复制代码
void selectUser() {
    System.out.println(userInfoMapper.selectUser(4));
}

[注意]:

  • 如果参数只有一个, #{ } 内的属性名称可以随便写.
  • 如果参数有多个 , 属性名和参数名必须保持一致; 或按照顺序对应(param1, param2...).

① 按名称对应

java 复制代码
@Select("select * from userinfo where username = #{name} and id = #{id}")
public UserInfo selectUser2(String name,Integer id);
java 复制代码
@Test
void selectUser2() {
    System.out.println(userInfoMapper.selectUser2("admin",1));
}

② 按顺序对应

java 复制代码
    @Select("select * from userinfo where username = #{param1} and id = #{param2}")
    public UserInfo selectUser3(String name,Integer id);
java 复制代码
    @Test
    void selectUser3() {
        System.out.println(userInfoMapper.selectUser3("admin",1));
    }

[注]: 也可以通过@Param注解, 设置参数的别名. 如果使用@Param设置别名, **注解中的别名必须和sql中的属性名保持一致.**举例如下:

java 复制代码
@Select("select * from userinfo where id = #{ID}")
public UserInfo selectUser4(@Param("ID") Integer id);
java 复制代码
@Test
void selectUser4() {
    System.out.println(userInfoMapper.selectUser4(1));
}

3. 增 (Insert)

sql语句:

insert into userinfo (username, `password`, age, gender, phone) values ("zhaoliu","zhaoliu",19,1,"15585133024")

把SQL中的常量换为动态的参数.

Mapper接口:

java 复制代码
@Insert("insert into userinfo (id,username,password,age,gender,phone) values (" +
        "#{id},#{username},#{password},#{age},#{gender},#{phone})")
public Integer insertUser1(UserInfo userInfo);

这里我们可以直接使用UserInfo对象的属性来获取参数:

java 复制代码
@Test
void insertUser1() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(5);
    userInfo.setUsername("zhaoliu");
    userInfo.setPassword("zhaoliu");
    userInfo.setAge(19);
    userInfo.setGender(1);
    userInfo.setPhone("15585133024");
    userInfoMapper.insertUser1(userInfo);
}

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

返回主键

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

但是有些情况下, 数据插入之后, 还需要有后续的关联操作, 需要获取到新插入的数据的id. 如果想要拿到自增id, 需要在Mapper接口的方法上添加一个Options的注解.

java 复制代码
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into userinfo (id,username,password,age,gender,phone) values (" +
        "#{id},#{username},#{password},#{age},#{gender},#{phone})")
public Integer insertUser2(UserInfo userInfo);

4. 删 (Delete)

sql语句:

delete from userinfo where id=6

把sql语句中的常量替换为动态参数.

Mapper接口:

java 复制代码
@Delete("delete from userinfo where id = #{id}")
public Integer deleteUser1(Integer id);
java 复制代码
@Test
void deleteUser1() {
    System.out.println(userInfoMapper.deleteUser1(6));
}

5. 改 (Update)

sql语句:

update userinfo set username="zhaoliu" where id=5

把SQL中的常量替换为动态的参数

Mapper接口:

java 复制代码
@Update("update userinfo set username = #{username} where id = #{id}")
public Integer updateUser(UserInfo userInfo);
java 复制代码
@Test
void updateUser() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(5);
    userInfo.setUsername("tianqi");
    System.out.println(userInfoMapper.updateUser(userInfo));
    }

6. 查 (Select)

只有Java对象属性和数据库字段⼀模⼀样时,才会进行赋值.

当自动映射查询结果的时候, MyBatis会获取结果中返回的列名并在Java类中查找相同名字的属性(忽略大小写). 这意味着如果发现了ID列和id属性, MyBatis会将 ID列的值 赋给 id属性. 但是我们的创建时间, 更新时间, 删除逻辑数字: 在数据库中是蛇形结构的名字, 而在Java类中是小驼峰的格式.

问题如上图, 那如何解决这个问题呢?

(1) 起别名

在sql语句中, 给列名起别名, 保持 别名实体类属性名一致.

java 复制代码
@Select("select id, username, `password`, age, gender, phone, " +
        "delete_flag as deleteFlag," +
        "create_time as createTime, update_time as updateTime from userinfo")
public List<UserInfo> selectAllUser2();

[注]: 当sql语句太长的时候,我们可以使用 + 进行拼接.

(2) 结果映射

java 复制代码
@Results({
        @Result(column = "delete_flag",property = "deleteFlag"),
        @Result(column = "create_time",property = "createTime"),
        @Result(column = "update_time",property = "updateTime")
})
@Select("select * from userinfo")
public List<UserInfo> selectAllUser3();
  • @Results 注解 中可以用大括号括起多个@Result映射.
  • @Result前面的参数 是表的字段名 , 后面是Java类的属性 . (字段与属性一一映射)

如果其他sql也想复用 这一组映射, 可以给这一组 @Results映射 自定义一个名称 . 之后在想要复用这个sql映射的地方使用 @ResultMap(vlaue="映射名称") 来实现映射的复用.

java 复制代码
@Results(id = "resultMap1",value = {
         @Result(column = "delete_flag",property = "deleteFlag"),
         @Result(column = "create_time",property = "createTime"),
         @Result(column = "update_time",property = "updateTime")
 })
 @Select("select * from userinfo")
 public List<UserInfo> selectAllUser3();

 @ResultMap(value = "resultMap1")
 @Select("select * from userinfo where id = #{id}")
 public UserInfo selectUser5(Integer id);

@ResultMap注解 中的 value 的值和上面映射的 id 名字必须相同.

我们也可以在xml文件中使用 <resultMap> 和 <result> 标签来完成.

XML 复制代码
<resultMap id="BaseResultMap" type="com.jrj.forums.model.Article">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="board_id" jdbcType="BIGINT" property="boardId" />
    <result column="user_id" jdbcType="BIGINT" property="userId" />
    <result column="title" jdbcType="VARCHAR" property="title" />
    <result column="visit_count" jdbcType="INTEGER" property="visitCount" />
    <result column="reply_count" jdbcType="INTEGER" property="replyCount" />
    <result column="like_count" jdbcType="INTEGER" property="likeCount" />
    <result column="state" jdbcType="TINYINT" property="state" />
    <result column="delete_state" jdbcType="TINYINT" property="deleteState" />
    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
 </resultMap>

指定好结果映射之后, 就可以在对应的sql标签之后使用 resultMap 来指定结果映射.

XML 复制代码
<select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
...
</select>

我们也可以使用 extends 来继承结果映射, 在继承过来的结果映射中添加还未存在的字段.

XML 复制代码
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.jrj.forums.model.Article">
  <result column="content" jdbcType="LONGVARCHAR" property="content" />
</resultMap>

(3) 开启驼峰命名与蛇形命名转换

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

为了在这两种命名方式之间启用自动映射 , 需要 **将mapUnderscoreToCamelCase设置为true .**我们需要在配置文件中配置.

XML 复制代码
mybatis: 
  configuration:
    map-underscore-to-camel-case: true #配置驼峰⾃动转换 

转换规则: abc_xyz --> abcXyz (蛇形转换为小驼峰).

而Java代码不用做任何处理:

java 复制代码
@Select("select * from userinfo")
public List<UserInfo> selectAllUser();

四. MyBatis XML配置文件

MyBatis 的开发方式有两种:

1. 注解

2. XML

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

前面我们学习了注解方式, 下面我们来看XML方式:

这种开发方式大致分为两步:

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

(2) 编写持久层代码

(1) 配置连接字符串和MyBatis

XML 复制代码
# 数据库连接配置 
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?
    characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 mybatis xml 的⽂件路径,在 resources/mapper 创建所有表的 xml ⽂件 
mybatis:
  mapper-locations: classpath:mapper/**Mapper.xml

mapper-locations 中的value值, classpath表示的是项目中的resource目录. mapper表示的是一个自定义目录. 一般我们使用xml操作数据库的代码都会单独放在一个mapper目录中, 之后**Mapper.xml表示的是以这个结尾的xml文件就是操作数据库的xml文件.

(2) 编写持久层代码

持久层代码分为两部分:

① 方法定义: Interface
② 方法实现: xxx.xml

① 添加Mapper接口

java 复制代码
package com.jrj.mybatis.mapper;

import com.jrj.mybatis.UserInfo;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;

@Mapper
public interface UserInfoXMLMapper {
    public List<UserInfo> selectAllUser1();
}

② 添加UserInfoXMLMapper.xml

java 复制代码
<?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.jrj.mybatis.mapper.UserInfoXMLMapper">
    
</mapper>

mapper标签 中加的是带有@Mapper注解接口的路径, 即想要通过MyBatis操作数据库的Mapper接口.

查询所有用户的具体实现:

java 复制代码
<?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.jrj.mybatis.mapper.UserInfoXMLMapper">
    <select id="selectAllUser1" resultType="com.jrj.mybatis.UserInfo">
        select * from userinfo
    </select>
</mapper>
  • 其中. select标签中 id="selectAllUser1" 代表的是Mapper中的方法名; resultType="com.jrj.mybatis.UserInfo" 代表的是sql查询之后返回的类型 (也就是我们开头定义的实体类)
  • 只有select类型的语句会有返回值的类型. [注意]: 是sql查询之后返回的类型, 不是接口返回值的类型. (sql查询之后返回的是UserInfo类型, 而接口返回的是List类型.)
  • 标签中间写的是sql语句.

我们还可以安装一个插件, 叫做MyBatisX, 这个插件可以自动帮助我们生成xml标签. 我们只需要写sql语句就行了.

③ 单元测试

进行单元测试时, 我们可以在Mapper上点击右键 --> 生成 --> 测试 --> 勾选想要测试的方法, 就会在test目录下自动生成测试类和测试方法 , 其中测试方法的返回值必须为void.

java 复制代码
@Test
void selectAllUser1() {
     List<UserInfo> list = userInfoXMLMapper.selectAllUser1();
     for (UserInfo userInfo: list){
         System.out.println(userInfo);
     }
 }

(3) 增删改查操作

① 增 (Insert)

UserInfoMapper接口:

java 复制代码
public Integer insertUser(UserInfo userInfo);

XML:

java 复制代码
<insert id="insertUser">
    insert into userinfo (id,username,password,age,gender,phone) values (#{id},#{username},#{password},#{age},#{gender},#{phone})
</insert>

测试代码:

java 复制代码
@Test
void insertUser() {
    UserInfo userInfo = new UserInfo();
    userInfo.setId(8);
    userInfo.setUsername("zhubajie");
    userInfo.setAge(22);
    userInfo.setPassword("6666666");
    userInfo.setGender(0);
    userInfo.setPhone("487362849326");
    userInfoXMLMapper.insertUser(userInfo);
}

与注解实现类似,要是在形参的前面加上 @Param注解 的话,在sql语句中的 #{ } 就必须使用对象名.属性名 来访问.

Mapper接口:

java 复制代码
public Integer insertUser(@Param("userinfo") UserInfo userInfo);

XML:

java 复制代码
<insert id="insertUser">
   insert into userinfo (id,username,password,age,gender,phone) values (#{userinfo.id},#{userinfo.username},#{userinfo.password},#{userinfo.age},#{userinfo.gender},#{userinfo.phone})
</insert>

② 删 (Delete)

③ 改 (Update)

④ 查 (Select)

删, 改, 查和增是同样的道理, 我们不再赘述.

相关推荐
浪遏1 小时前
NestJs👈 | 前端spring🤔| 项目创建与项目结构解析
前端·javascript·后端
magic 2451 小时前
Java继承中的静态方法隐藏与实例变量隐藏:深入解析与最佳实践
java·开发语言·javase
Java 第一深情2 小时前
JVM面试题解,垃圾回收之“垃圾回收器”剖析
java·jvm·面试
for622 小时前
一文读懂fgc之cms
java·jvm·实践
苹果醋33 小时前
Win10安装MySQL、Pycharm连接MySQL,Pycharm中运行Django
运维·vue.js·spring boot·nginx·课程设计
Kerwin要坚持日更3 小时前
一文讲解Java中的BIO、NIO、AIO之间的区别
java·开发语言
汤姆yu4 小时前
基于Springboot的社区药房管理系统
java·spring boot·后端·社区药房
程思扬4 小时前
Android笔记:android 动态设置backgroundTint
android·java·网络·笔记·android-studio
2的n次方_4 小时前
Eureka 服务注册和服务发现的使用
spring boot·spring cloud·云原生·eureka·服务发现