写点什么

MyBatis 与其使用方法讲解

  • 2025-03-07
    福建
  • 本文字数:7053 字

    阅读完需:约 23 分钟

ORM


在讲解 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 的基本使用


环境准备


  • 引入依赖包:


<!--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 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


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 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 接口:


public interface StudentMapper {    List<Student> queryAll();}
复制代码



MyBatis 日志配置


  • 引入 SpringBoot 中的 log4j


<!-- 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.ymlmybatis配置项中进行配置


mybatis:  configuration:    log-impl: org.apache.ibatis.logging.log4j.Log4jImpl
复制代码


  • 配置log4j.properties文件


### 设置###log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制抬 ###log4j.appender.stdout = org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.Target = System.outlog4j.appender.stdout.layout = org.apache.log4j.PatternLayoutlog4j.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.DailyRollingFileAppenderlog4j.appender.D.File = D://logs/log.loglog4j.appender.D.Append = truelog4j.appender.D.Threshold = DEBUG log4j.appender.D.layout = org.apache.log4j.PatternLayoutlog4j.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.DailyRollingFileAppenderlog4j.appender.E.File =D://logs/error.log log4j.appender.E.Append = truelog4j.appender.E.Threshold = ERROR log4j.appender.E.layout = org.apache.log4j.PatternLayoutlog4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
复制代码


  • 一个基本的 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.mapper.UserMapper">    <!-- CRUD 配置 --></mapper>
复制代码


CURD 实现


select 查询


  • 使用<select>标签实现基本查询


<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 注入问题

  • 多条件查询


<select id="getUserByNameAndAge" resultType="User">    SELECT * FROM user     WHERE name = #{name} AND age = #{age}</select>
复制代码


  • 模糊查询


<select>        SELECT *        FROM user        WHERE name LIKE CONCAT('%', #{name}, '%')</select>
复制代码


  • 使用 LIKE 关键字和 CONCAT()函数进行查询


insert 插入


  • 使用<insert>标签实现基本插入操作


    <insert id="insertUser" parameterType="User">        INSERT INTO user(name, age)        VALUES (#{name}, #{age})    </insert>
复制代码


  • parameterType:表示入参类型

  • 实现回填自增主键

    使用userGeneratedKeyskeyProperty实现


<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">    INSERT INTO user (name, age)     VALUES (#{name}, #{age})</insert>
复制代码


  • userGeneratedKeys:表示是否启动自增

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


update 更新


  • 使用<update>标签实现基本更新


	 <update id="updateUser" parameterType="User">        UPDATE user        SET name=#{name},            age =#{age}        WHERE id = #{id}    </update>
复制代码


delete 删除


  • 使用<delete>标签基本查询


    <delete id="deleteUserById" parameterType="Integer">        DELETE        FROM user        WHERE id = #{id}    </delete>
复制代码


传参方式


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

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


<select id="getUserByNameAndAge" resultType="User">    SELECT * FROM user     WHERE name = #{name} AND age = #{age}</select>
复制代码


  • Mapper 接口


    User getUserByNameAndAge(            @Param("name") String name,            @Param("age") Integer age);
复制代码


对象参数


  • 当参数为一个 Java 对象时,MyBatis 自动将对象属性映射到 Sql 语句中的占位符


<insert id="insertUser" parameterType="User">    INSERT INTO user (name, age)     VALUES (#{name}, #{age})</insert>
复制代码


  • #{name}对应 user.name,#{age}对应 user.age

  • Mapper 接口


void insertUser(User user);
复制代码


Map 参数

  • 通过 Map 传递多个参数或动态参数


<select id="getUserByMap" resultType="User">    SELECT * FROM user     WHERE name = #{name} AND age = #{age}</select>
复制代码


  • Mapper 接口


User getUserByMap(Map<String, Object> params);
复制代码


集合/数组参数

  • 适用于批量查询,比如 WHERE id IN (…)

<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 接口


List<User> getUsersByIds(@Param("ids") List<Integer> ids);
复制代码


动态 sql


与标签


  • <where>:生成 WHERE 子句,并自动判断去掉开头多余的AND/OR关键字,使 sql 更简洁

  • <if>:用于判断传参条件,根据条件决定是否拼接某段 SQL 语句,适用于传参条件不固定,只有在满足条件时接入某个子串


<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 语句


<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>的特性化


<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()指定对应名称,默认为listarray)item:循环时每个元素的别名 open:循环生成 sql 片段的前缀 separator:循环时的分隔符 close:循环生成 sql 片段的后缀


<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 查询时


SELECT id, name, age FROM user WHERE id = #{id}
复制代码


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

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

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

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

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


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


一对一映射


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


  • 现假设,数据库有两张表一个 user(用户)表,另一个 user_detail(用户详细信息)表,在 Java 中我们可以创建两个类 User 和 UserDetail 类

  • 然后再创建一个 UserVo 类,其中包含 User 的属性和一个 UserDatail 对象


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 配置如下:


<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 属性来存放老师的所有学生

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 配置如下:


<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

原文链接:https://www.cnblogs.com/ihave2carryon/p/18756129

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

用户头像

还未添加个人签名 2023-06-19 加入

还未添加个人简介

评论

发布
暂无评论
MyBatis与其使用方法讲解_mybatis_不在线第一只蜗牛_InfoQ写作社区