MyBatis与其使用方法讲解

在讲解Mybatis之前,我们需了解一个概念ORM(Object-Relational Mapping)对象关系映射,其是数据库与Java对象进行映射的一个技术.通过使用ORM,我们可以不用编写负责的Sql语句,而是通过操作对象来实现增删改查操作

缺优分析

  • 优点提高开发效率,减少代码的重复性和维护成本增加代码的可读性,降低复杂度对数据库查询的细节进行抽象,隐藏了sql语句
  • 缺点在进行多表联查时,或存在where条件时,ORM语句会变得复杂

MyBatis

  • mybatis是一个支持自定义SQL的持久层框架,通过XML文件来实现SQL配置和数据映射,MyBatis允许开发者手动编写SQL语句,提高灵活性

Mybatis通过**mapper**文件,将sql查询和Java对象绑定到一起,简化了JDBC代码的编写,手动设置参数,获取结果集的工作

MyBatis的工作流程

  • 其分为以下几步

MyBatis的基本使用

环境准备

  • 引入依赖包:
xml 复制代码
<!--springboot的mybatis >
<dependency>    
		<groupId>org.mybatis.spring.boot</groupId>    
		<artifactId>mybatis-spring-boot-starter</artifactId>   
		<version>3.0.3</version>
</dependency>

<!-- MySQL 连接器 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
  • 创建mybatis配置文件(mybatis-config.xml)
xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- mybatis环境 -->
    <environments default="mysql">
        <environment id="mysql">
            <!-- 配置事务的类型 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置数据源(连接池) -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/数据库名称?userSSL=false&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="帐号"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>
    <!-- mybatis映射配置位置 -->
    <!-- 按模块映射不同的配置文件,让配置文件看起来更简洁 -->
    <mappers>
        <mapper resource="映射配置文件全路径"></mapper>
    </mappers>
</configuration>
  • springboot中的**application.yml**
yaml 复制代码
mybatis:
  # mapper配置文件
  mapper-locations: classpath:mapper/*.xml
  # resultType别名,没有这个配置resultType包名要写全,配置后只要写类名
  type-aliases-package: com.mashang.xiaomistore.domain
  configuration:
    #下划线自动转驼峰
    map-underscore-to-camel-case: true
  • 创建Mapper映射文件
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.company.mapper.StudentMapper">
    <select id="queryAll" resultType="com.company.entity.Student">
        SELECT * FROM student
    </select>
</mapper>
  • 创建Mapper接口:
csharp 复制代码
public interface StudentMapper {
    List<Student> queryAll();
}

MyBatis日志配置

  • 引入SpringBoot中的log4j
xml 复制代码
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-log4j2 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-log4j2</artifactId>
    <version>3.4.3</version>
</dependency>
  • 在SpringBoot中在**application.yml中 mybatis**配置项中进行配置
yaml 复制代码
mybatis:
  configuration:
    log-impl: org.apache.ibatis.logging.log4j.Log4jImpl
  • 配置**log4j.properties**文件
ini 复制代码
### 设置###
log4j.rootLogger = debug,stdout,D,E

### 输出信息到控制抬 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

### 输出DEBUG 级别以上的日志到=D://logs/error.log ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = D://logs/log.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG 
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n

### 输出ERROR 级别以上的日志到=D://logs/error.log ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =D://logs/error.log 
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR 
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss}  [ %t:%r ] - [ %p ]  %m%n
  • 一个基本的mybatis的XML模板如下
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.mapper.UserMapper">
    <!-- CRUD 配置 -->
</mapper>

CURD实现

select查询

  • 使用 <select> 标签实现基本查询
sql 复制代码
<select id ="getUserById" resultType="com.company.domain.entity.User">
		SELECT * FORM user 
</select>

*

  • id:对应Mapper接口中的方法名,必须一致

    resultType:指定返回结果映射到哪个Java类

  • 传参 #{} 与 ${} 的区别

    #{} 的特点事先进行预编译:使用 #{} 的参数会被Mybatis当作JDBC中的 ? 占位符防止sql注入:由于会事先进行预编译,Mybatis能够防止Sql注入类型转换:会根据参数类型进行适当的类型转换

    ${} 的特点字符串拼接: &{} 直接将字符串进行替换,相当于在Sql中直接拼接传入的参数存在sql注入的风险:没有预编译,会引发sql注入问题

  • 多条件查询

sql 复制代码
<select id="getUserByNameAndAge" resultType="User">
    SELECT * FROM user 
    WHERE name = #{name} AND age = #{age}
</select>
  • 模糊查询
sql 复制代码
<select>
        SELECT *
        FROM user
        WHERE name LIKE CONCAT('%', #{name}, '%')
</select>
  • 使用LIKE关键字和CONCAT()函数进行查询

insert插入

  • 使用 <insert> 标签实现基本插入操作
sql 复制代码
    <insert id="insertUser" parameterType="User">
        INSERT INTO user(name, age)
        VALUES (#{name}, #{age})
    </insert>
  • parameterType:表示入参类型

  • 实现回填自增主键

    使用**userGeneratedKeys和 keyProperty**实现

sql 复制代码
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    INSERT INTO user (name, age) 
    VALUES (#{name}, #{age})
</insert>
  • userGeneratedKeys:表示是否启动自增

    keyProperty :表示将生成的主键赋值给哪个java对象的哪个属性如**user.id**

update更新

  • 使用 <update> 标签实现基本更新
bash 复制代码
	 <update id="updateUser" parameterType="User">
        UPDATE user
        SET name=#{name},
            age =#{age}
        WHERE id = #{id}
    </update>

delete删除

  • 使用 <delete> 标签基本查询
sql 复制代码
    <delete id="deleteUserById" parameterType="Integer">
        DELETE
        FROM user
        WHERE id = #{id}
    </delete>

传参方式

  • 多参数传参(使用@Param)

    当方法有多个参数时,使用 **@Param**注解明确参数名

sql 复制代码
<select id="getUserByNameAndAge" resultType="User">
    SELECT * FROM user 
    WHERE name = #{name} AND age = #{age}
</select>
  • Mapper接口
less 复制代码
    User getUserByNameAndAge(
            @Param("name") String name,
            @Param("age") Integer age);

对象参数

  • 当参数为一个Java对象时,MyBatis自动将对象属性映射到Sql语句中的占位符
sql 复制代码
<insert id="insertUser" parameterType="User">
    INSERT INTO user (name, age) 
    VALUES (#{name}, #{age})
</insert>
arduino 复制代码
void insertUser(User user);

Map参数

  • 通过Map传递多个参数或动态参数
sql 复制代码
<select id="getUserByMap" resultType="User">
    SELECT * FROM user 
    WHERE name = #{name} AND age = #{age}
</select>
  • Mapper接口
javascript 复制代码
User getUserByMap(Map<String, Object> params);

集合/数组参数

  • 适用于批量查询,比如WHERE id IN (...)
sql 复制代码
<select id="getUsersByIds" resultType="User">
    SELECT * FROM user 
    WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>
  • <foreach> 是动态sql中的知识点等下会系统讲解
  • Mapper接口
less 复制代码
List<User> getUsersByIds(@Param("ids") List<Integer> ids);

动态sql

与标签

  • <where> :生成WHERE子句,并自动判断去掉开头多余的**AND/OR**关键字,使sql更简洁
  • <if> :用于判断传参条件,根据条件决定是否拼接某段SQL语句,适用于传参条件不固定,只有在满足条件时接入某个子串
bash 复制代码
<select id="getUserByCondition" resultType="User">
    SELECT * FROM user
    <where>
        <if test="name != null and name != ''">
            AND name LIKE CONCAT('%', #{name}, '%')
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>
  • 当**name为非空,会添加 AND name LIKE CONCAT('%', #{name}, '%')** 当**age**为非空时会添加 AND age = #{age}
  • 结合标签使用,能自动处理首个AND,使得SQL语句正确
  • 其作用在于动态拼接SQL片段前添加或去除特点字符,比如前缀,后缀,以及多余的分隔符如 ,
  • 常用于INSERT和UPDATE语句,避免出现多余逗号

INSERT语句

ini 复制代码
<insert id="insertUserSelective" parameterType="User">
    INSERT INTO user
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="name != null">name,</if>
        <if test="age != null">age,</if>
        <if test="email != null">email,</if>
    </trim>
    VALUES
    <trim prefix="(" suffix=")" suffixOverrides=",">
        <if test="name != null">#{name},</if>
        <if test="age != null">#{age},</if>
        <if test="email != null">#{email},</if>
    </trim>
</insert>
  • 标签包裹字段列表和对应值部分
  • suffixOverrides="," 表示自动去除多余的逗号,确保sql语法正确

UPDATE语句

  • <set> 标签是 <trim> 的特性化
bash 复制代码
<update id="updateUserDynamic" parameterType="User">
    UPDATE user
    <set>
        <if test="name != null">name = #{name},</if>
        <if test="age != null">age = #{age},</if>
        <if test="email != null">email = #{email},</if>
    </set>
    WHERE id = #{id}
</update>
  • <set> 标签内部原理类似 <trim> ,会自动去除多余逗号
  • <foreach> 用于遍历集合,数组和Map,常用于批量操作或动态生成IN子句
  • 其主要属性collection:集合或数组名称(可用 @Param() 指定对应名称,默认为**list或 array**)item:循环时每个元素的别名open:循环生成sql片段的前缀separator:循环时的分隔符close:循环生成sql片段的后缀
bash 复制代码
<select id="getUsersByIds" resultType="User">
    SELECT * FROM user
    <where>
        <if test="ids != null">
            AND id IN
            <foreach collection="ids" item="id" open="(" separator="," close=")">
                #{id}
            </foreach>
        </if>
    </where>
</select>
  • 当ids不为null时,进入 <if test="ids != null"> 生成的sql片段为 SELECT * FROM AND WHERE id IN(#{id},#{id},...)
  • 其中标签遍历集合ids,用逗号进行分隔,并在开头添加 ( 括号,结尾添加 ) 括号
  • 最终标签会去除第一个AND,使sql合法**SELECT * FROM id WHERE IN(#{id},#{id},...)**

MyBatis的映射

基本映射

用于单一的字段对应

  • 假设有一个user表,其中有字段**id,name,age其在Java中有个简单的对应类User,其属性分别也是 id,name,age**那么在Mapper.xml进行select查询时
sql 复制代码
SELECT id, name, age FROM user WHERE id = #{id}

*

  • MyBatis会将查询的结果中每一列值自动赋值给User对象中相同的属性

    数据库列表的id→User对象的id

    数据库列表的name→User对象的name

    数据库列表的age→User对象的age

  • 这样可能就会出现一种情况,数据库列表的列名与对象的属性名不一致,通常使用开启驼峰转换来解决→在**application.yml**的mybatis配置中添加如下配置:

vbnet 复制代码
mybatis:
    map-underscore-to-camel-case: true

一对一映射

当查询中需要查询一个对象时

  • 现假设,数据库有两张表一个user(用户)表,另一个user_detail(用户详细信息)表,在Java中我们可以创建两个类User和UserDetail类
  • 然后再创建一个UserVo类,其中包含User的属性和一个UserDatail对象
vbnet 复制代码
public class User {
    private Integer id;
    private String name;
    private Integer age;
}

public class UserDetail {
    private Integer detailId;
    private String address;
    private String phone;
}

public class UserVo {
    private Integer id;
    private String name;
    private Integer age;
    private UserDetail userDetail;  // 一对一关系:一个用户对应一份详细信息 
}

XML配置如下:

xml 复制代码
<resultMap id="userVoMap" type="com.example.UserVo">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <result property="age" column="age"/>
    <!-- 一对一映射 -->
    <association property="userDetail" javaType="com.example.UserDetail">
        <id property="detailId" column="detail_id"/>
        <result property="address" column="address"/>
        <result property="phone" column="phone"/>
    </association>
</resultMap>

<select id="getUserVoById" resultMap="userVoMap" parameterType="int">
    SELECT u.id, u.name, u.age, ud.detail_id, ud.address, ud.phone
    FROM user u
    LEFT JOIN user_detail ud ON u.id = ud.user_id
    WHERE u.id = #{id}
</select>
  • <resultMap> 标签用于定义一组映射规则,将查询的结果转换为一个指定类型的Java对象属性id:为该映射指定一个唯一标识,供其在XML中引用使用,如 <resultMap id="userResultMap" type="com.example.User"> type:指定映射结果对应的Java类型(对象的全路径)
  • <result> 标签用于将数据库列映射到Java对象的属性,在 <resultMap> 中使用属性property:Java对象中的属性名称,如 <result property="userName" column="user_name"/> 其表示将查询到的user_name列的值赋值给userName属性cloumn:数据库查询结果中的列名,如**column="user_name"** 表示sql查询列名为user_name的值
  • <id> 标签 <id> 类似于 <result> 主要用于映射主键字段属性property:与 <result> 相同,映射到Java对象的主键属性 column:对应数据库中的主键列名
  • <association> 标签表示一个一对一关连当查询到结果时,MyBatis会将用户的基本字段 {id,name,age} 直接映射到UserVo中,同时将详细信息 {detail_id,address,phone} 封装为一个UserDetail对象,并赋值到UserVo的**userDetail**对象中

一对多映射

提供用于有列表对象的查询

  • 现假设一个老师(Teacher)类和一个学生(student)类,一个老师可以对应多个学生,在Java中我们可以设计Teacher类, 使用List属性来存放老师的所有学生
vbnet 复制代码
public class Teacher {
    private Integer id;
    private String teacherName;
    private Integer age;
    private List<Student> students; // 一对多关系:一个老师对应多个学生
}

public class Student {
    private Integer id;
    private String name;
    private Integer age;
}

XML配置如下:

xml 复制代码
<resultMap id="teacherMap" type="com.example.Teacher">
    <id property="id" column="teacher_id"/>
    <result property="teacherName" column="teacher_name"/>
    <result property="age" column="teacher_age"/>
    <!-- 一对多映射 -->
    <collection property="students" ofType="com.example.Student">
        <id property="id" column="student_id"/>
        <result property="name" column="student_name"/>
        <result property="age" column="student_age"/>
    </collection>
</resultMap>

<select id="getTeacherWithStudents" resultMap="teacherMap" parameterType="int">
    SELECT t.id as teacher_id, t.teacher_name, t.age as teacher_age,
           s.id as student_id, s.name as student_name, s.age as student_age
    FROM teacher t
    LEFT JOIN student s ON t.id = s.teacher_id
    WHERE t.id = #{id}
</select>
  • <collection> 标签:用于表示一对多关系,把查询结果中的学生记录封装成一个列表,并赋值到Teacher对象中的**student**属性

文章转载自: ihav2carryon

原文链接: www.cnblogs.com/ihave2carry...

体验地址: www.jnpfsoft.com/?from=001YH

相关推荐
wljt1 天前
公司二-面试题
java·开发语言·mybatis
VimorphTech1 天前
文本已经改了,旧的音频生成结果还能回写吗?
java·数据库·mybatis
麻瓜code1 天前
双写一致性:为什么是“删缓存“,而不是“改缓存“
java·缓存·mybatis
郭小李2 天前
mybatis 动态 sql
java·sql·mybatis
知守观2 天前
技术考古:iBATIS 2.3.4 时代的持久层,是如何用 Map 玩转 307 个存储过程的?
java·后端·mybatis
captain3762 天前
MyBatis Plus(1)
java·服务器·mybatis
代码不停2 天前
MyBatis进阶
spring boot·mybatis
captain3763 天前
MyBatis(入门5)其他查询操作
java·数据库·spring boot·mybatis
captain3763 天前
MyBatis(进阶1)
mybatis
郭小李3 天前
mybatis的 Mapper.xml语法
xml·java·mybatis