MyBatis

本文详细介绍了MyBatis,一个优秀的持久层框架,旨在简化JDBC开发。文章讨论了JDBC的缺点,如硬编码和操作繁琐,并展示了MyBatis如何通过配置文件和Mapper代理来简化这些过程。内容包括MyBatis快速入门,Mapper代理开发,核心配置文件解析,以及通过Mapper.xml文件完成的增删改查操作,涵盖单条件和多条件动态查询。此外,还探讨了MyBatis的参数传递和使用注解进行增删改查的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是MyBatis?

  • MyBatis是一款优秀的持久层框架,用于简化JDBC开发。
  • MyBatis 本来是 Apache 的一个开眼项目iBatis,2010年这个项目由 apache software foundation 迁移到 google code ,并且改名为MyBatis,2013年11月迁移到 GitHub
  •  中文网:MyBatis中文网

什么是持久层

  • 持久层主要负责将数据保存到数据库的那一层代码。
  • JavaEE有三层架构,分别是表现层业务层持久层

什么是框架

  • 框架就是一个半成品软件,是一套可重用的、通用的、软件基础代码模型
  • 在框架的基础之上构建软件更加高效、规范、通用、可扩展

为什么要使用MyBatis?

使用MyBatils可以简化JDBC开发。

JDBC缺点

        因为传统的JDBC开发效率低、操作繁琐,并且有些需要硬编码,JDBC缺点如下:

1、硬编码

  • 需要注册驱动,获取连接
  • 编写SQL语句

2、操作繁琐

  • 手动设置参数
  • 手动封装结果集 

MyBatis 简化 JDBC

        MyBatis 简化 JDBC,通过MyBatis可以将硬编码通过配置文件的方式处理,然后一些操作比较繁琐的代码由MyBatis自动完成,如下图所示: 

MyBatis快速入门

需求:通过MyBatis查询user表中的所有数据,并且封装到结果集中

实现步骤:

1、创建user表,并添加数据(通过执行sql语句来完成)

tb_user.sql 文件内容如下:

create database mybatis;
use mybatis;

drop table if exists tb_user;

create table tb_user(
	id int primary key auto_increment,
	username varchar(20),
	password varchar(20),
	gender char(1),
	addr varchar(30)
);



INSERT INTO tb_user VALUES (1, 'zhangsan', '123', '男', '北京');
INSERT INTO tb_user VALUES (2, '李四', '234', '女', '天津');
INSERT INTO tb_user VALUES (3, '王五', '11', '男', '西安');

 通过navicat 执行以上sql文件,执行结果如下:        

2、创建模块,配置MyBatis相关的Mvean依赖

archettype  选择 maven-archetype-quickstart

配置相关依赖


<!--   添加mybatis依赖  -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.5</version>
    </dependency>

<!--   添加mysql依赖 -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>


    <!-- 添加slf4j日志api -->
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.25</version>
    </dependency>

    <!-- 添加logback-classic依赖 -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>

    <!-- 添加logback-core依赖 -->
    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.2.3</version>
    </dependency>

 

添加  logback 所需的配置文件 logbacl.xml

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
        CONSOLE :表示当前的日志信息是可以输出到控制台的。
    -->
    <appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>[%level]  %cyan([%thread]) %boldGreen(%logger{15}) - %msg %n</pattern>
        </encoder>
    </appender>

    <logger name="com.itheima" level="DEBUG" additivity="false">
        <appender-ref ref="Console"/>
    </logger>


    <!--

      level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF
     , 默认debug
      <root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
      -->
    <root level="DEBUG">
        <appender-ref ref="Console"/>
    </root>
</configuration>

3、编写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>

    <typeAliases>
        <package name="com.itheima.pojo"/>
    </typeAliases>

    <!--
    environments:配置数据库连接环境信息。可以配置多个environment,通过default属性切换不同的environment
    -->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="12345678"/>
            </dataSource>
        </environment>

        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--加载sql映射文件-->
       <mapper resource="com/itheima/mapper/UserMapper.xml"/>


    </mappers>


</configuration>

4、编写SQL映射文件。

编写该文件主要是为了统一管理SQL语句,解决硬编码问题

UserMapper.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">

<!--
    namespace:名称空间
-->

<mapper namespace="com.itheima.mapper.UserMapper">

    <!--statement-->

<!--
resultType="user" 表示返回的结构类型,user表示返回User类对象
-->
    <select id="selectAll" resultType="user">
        select *
        from tb_user;
    </select>
<!--    <select id="selectById" resultType="user">
        select *
        from tb_user where id = #{id};

    </select>-->


    <select id="select" resultType="user">
        select *
        from tb_user
        where
            username = #{arg0}
        and password = #{param2}
    </select>


</mapper>

UserMapper.class
package com.itheima.mapper;

import com.itheima.pojo.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

public interface UserMapper {

    List<User> selectAll();

    @Select("select * from tb_user where id  = #{id}")
    User selectById(int id);

    /*

      MyBatis 参数封装:
        * 单个参数:
            1. POJO类型:直接使用,属性名 和 参数占位符名称 一致
            2. Map集合:直接使用,键名 和 参数占位符名称 一致
            3. Collection:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
                map.put("arg0",collection集合);
                map.put("collection",collection集合);
            4. List:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
                map.put("arg0",list集合);
                map.put("collection",list集合);
                map.put("list",list集合);
            5. Array:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
                map.put("arg0",数组);
                map.put("array",数组);
            6. 其他类型:直接使用
        * 多个参数:封装为Map集合,可以使用@Param注解,替换Map集合中默认的arg键名
            map.put("arg0",参数值1)
            map.put("param1",参数值1)
            map.put("param2",参数值2)
            map.put("agr1",参数值2)
            ---------------@Param("username")
            map.put("username",参数值1)
            map.put("param1",参数值1)
            map.put("param2",参数值2)
            map.put("agr1",参数值2)

     */
    User select(@Param("username") String username,String password);
    User select(Collection collection);













}

5、定义POJO类

该类对应的就是user表

User.class文件内容如下

package com.itheima.pojo;


// alt + 鼠标左键 整列编辑
public class User {

    private Integer id;
    private String username;
    private String password;
    private String gender;
    private String addr;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", gender='" + gender + '\'' +
                ", addr='" + addr + '\'' +
                '}';
    }
}

6、加载核心配置文件,获取SqlSessionFactory对象

7、获取SqlSession对象,执行SQL语句

8、释放资源

package com.itheima;


import com.itheima.pojo.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * Mybatis 快速入门代码
 */
public class MyBatisDemo {

    public static void main(String[] args) throws IOException {

        //1. 加载mybatis的核心配置文件,获取 SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象,用它来执行sql
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //3. 执行sql
        List<User> users = sqlSession.selectList("test.selectAll");
        System.out.println(users);
        //4. 释放资源
        sqlSession.close();

    }
}

效果图: 

示例代码参见:https://download.csdn.net/download/qq_35366269/87610565

Mapper代理开发

        Mapper代理是为了让Mybatis开发更简单。

        Mapper代理开发的目的主要是解决原声方式中的硬编码,简化后期执行SQL,如下截图:

使用Mapper代理的方式的具体步骤:

1、首先定义与SQL映射文件同名的Mapper接口,并且将Mapper接口和SQL映射文件放置在同一目录下

注意:在resources目录下创建文件夹,例如:com.zhbe.mybatis  ,需要用斜杠 /  作为分隔符

2、设置SQL映射文件的namespace属性为Mapper接口的全路径名称

3、在Mapper接口中定义方法,方法名就是SQL映射文件中SQL语句的id,并保持参数类型和返回值类型一致

4、在mybatis-config.xml文件中设置mapper路径

5、然后通过 SqlSession 中的getMapper方法获取 Mapper 接口的代理对象,然后调用自定义的方法完成sql的执行

MyBatis核心配置文件

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>

<!--
注意:配置各个标签时,需要遵守前后顺序!!!
顺序参见:https://mybatis.org/mybatis-3/zh/configuration.html
-->

<!--
 typeAliases 别名
 在AreaMapper.xml文件中,getAreaById查询中,resultType(查询返回值)指定的是Area类路径,如果不设置别名,那么类路径为绝对路径(com.itheima.pojo.Area)
 如果在此处package标签中设置了name属性为为返回值的父路径(com.itheima.pojo),那么resultType就只需要设置相对路径即可,也就是area
 -->
    <typeAliases>
        <package name="com.itheima.pojo"/>
    </typeAliases>

    <!--
    environments:配置数据库连接环境信息。可以配置多个environment,通过default属性切换不同的environment
    default="development" 表示默认为开发环境
    -->
    <environments default="development">

<!--      开发环境相关配置  -->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="12345678"/>
            </dataSource>
        </environment>

<!--       测试环境相关配置 -->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--加载sql映射文件-->
       <!-- <mapper resource="com/itheima/mapper/UserMapper.xml"/>-->

        <!--Mapper代理方式-->
        <package name="com.itheima.mapper"/>

    </mappers>


</configuration>

官网核心配置文件介绍:mybatis – MyBatis 3 | 配置        

environments:配置数据库连接环境信息。可以配置多个environment,通过default属性切换不同的environment,default="development" 表示默认为开发环境,如下图所示:

       

typeAliases:typeAliases 表示别名。 在AreaMapper.xml文件中,getAreaById查询中,resultType(查询返回值)指定的是Area类路径,如果不设置别名,那么类路径为绝对路径(com.itheima.pojo.Area) 如果在此处package标签中设置了name属性为为返回值的父路径(com.itheima.pojo),那么resultType就只需要设置相对路径即可,也就是Area

注意:配置各个标签时,需要遵守前后顺序!!!

通过配置文件(Mapper.xml文件)完成增删改查

1、查询

1.1、查询所有数据

具体步骤如下图所示: 

核心的点在于:

1、需要根据业务的不同分析出SQL语句该怎么写?

2、完成这个功能需不需要参数?

3、完成之后返回什么结果? 

例如:操作区域表 area

area表如下:

        

AreaMapper.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">

<!--
    namespace:名称空间
-->

<mapper namespace="com.itheima.mapper.AreaMapper">




    <!--  添加单个区域  -->
    <insert id="add">
        INSERT INTO tb_area (areaName,areaCode) VALUES (#{areaName},#{areaCode})
    </insert>


    <!--  根据id删除区域  -->
    <delete id="deleteAreaById">
        DELETE FROM tb_area WHERE id = #{id}
    </delete>


    <!--  删除所有数据  -->
    <delete id="deleteAll">
        DELETE FROM tb_area
    </delete>

<!--  修改  -->
    <update id="update">
        UPDATE tb_area
        <set>
            <if test="areaName != null and areaName != ''">
                areaName = #{areaName},
            </if>
            <if test="areaCode != null and areaCode != ''">
                areaName = #{areaCode}
            </if>
        </set>
        WHERE id = #{id}
    </update>


<!-- 查询所有区域数据  -->
    <select id="selectAll" resultType="area">
        SELECT * FROM tb_area
    </select>


    <!--
其中 #{id} 表示要传递的数据
-->
    <select id="getAreaById" resultType="com.itheima.pojo.Area">
        SELECT * FROM tb_area WHERE id = #{id}
    </select>


</mapper>

AreaMapper.java文件如下:

package com.itheima.mapper;

import com.itheima.pojo.Area;
import com.itheima.pojo.Brand;

import java.util.List;

/**
 * @program: mybatis-demo
 * @author: 郭宝
 * @create: 2023-04-26 07:37
 * @description: 区域maper
 **/
public interface AreaMapper {




    // 添加单个区域
    void add(Area area);

    // 根据id删除区域
    void deleteAreaById(int id);

    // 删除所有数据
    void deleteAll();

    // 修改
    int update(Area area);


    // 查询所有区域
    List<Area> selectAll();

    // 根据id查询区域数据
    Area getAreaById(int id);





}

测试代码如下:

package com.itheima.test;

import com.itheima.mapper.AreaMapper;
import com.itheima.pojo.Area;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @program: mybatis-demo
 * @author: 郭宝
 * @create: 2023-04-26 07:44
 * @description:
 **/
public class AreaBatisTest {


    /**
     * 测试获取所有
     * @throws IOException
     */
    @Test
    public void testSelectAll() throws IOException {

        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


        SqlSession sqlSession = sqlSessionFactory.openSession();
        AreaMapper areaMapper = sqlSession.getMapper(AreaMapper.class);
        List<Area> areas = areaMapper.selectAll();

        System.out.println(areas);

        sqlSession.close();


    }

    /**
     * 测试根据id获取区域
     * @throws IOException
     */
    @Test
    public void testGetAreaById() throws IOException {

        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


        SqlSession sqlSession = sqlSessionFactory.openSession();
        AreaMapper areaMapper = sqlSession.getMapper(AreaMapper.class);
        // 根据id获取区域数据
        Area area = areaMapper.getAreaById(1);

        System.out.println(area);

        sqlSession.close();

    }


    /**
     * 测试添加
     * @throws IOException
     */
    @Test
    public void testAdd() throws IOException {

        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);


        SqlSession sqlSession = sqlSessionFactory.openSession();
        AreaMapper areaMapper = sqlSession.getMapper(AreaMapper.class);
        // 根据id获取区域数据
        Area area = new Area();
        area.setAreaName("夷陵区");
        area.setAreaCode("003");

        areaMapper.add(area);

        System.out.println(area);

        // 提交事务   注意:只有提交了事务才能将数据添加到数据库中
        sqlSession.commit();

        sqlSession.close();

    }

    @Test
    public void testDeleteAreaById() throws IOException {
        String resource = "mybatis-config.xml";

        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        AreaMapper areaMapper = sqlSession.getMapper(AreaMapper.class);

        areaMapper.deleteAreaById(1);

        // 提交事务
        sqlSession.commit();

        // 释放资源
        sqlSession.close();


    }

    @Test
    public void testDeleteAll() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        AreaMapper areaMapper = sqlSession.getMapper(AreaMapper.class);


        areaMapper.deleteAll();

        // 提交事务
        sqlSession.commit();

        sqlSession.close();
    }


    /**
     * 测试修改
     * @throws IOException
     */
    @Test
    public void testUpdate() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);

        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        AreaMapper areaMapper = sqlSession.getMapper(AreaMapper.class);

        Area area = new Area();
        area.setId(9);
        area.setAreaName("猇亭区");
        areaMapper.update(area);

        // 提交事务
        sqlSession.commit();

        // 释放资源
        sqlSession.close();

    }



}

结果映射

在开发过程中,表中设计的字段名称为area_name ,java类中的属性名称为areaName,数据库中表的字段名称和实体类的属性名称不一致,则不能自动封装数据。

方案一:

对SQL语句的查询字段名称设置一个别名,让别名与实体类的属性名一样,也就是通过AS关键字来实现

SELECT 
 字段名 AS 别名
FROM 数据表;

 示例代码如下:

<!--
查询所有区域数据
area_name AS areaName 设置别名。其中area_name为字段名,areaName为别名
  -->
    <select id="selectAll" resultType="area">
        SELECT id, area_name AS areaName,area_code AS areaCode FROM tb_area
    </select>

结果图: 

通过别名的方式可以解决该问题,但是缺点是每次查询都要定义一次别名,操作繁琐

那么我们可以通过sql片段标签将相同的语句进行抽取封装,来简化代码

<!-- sql 片段   -->
    <sql id="area_column">
        id, area_name AS areaName,area_code
    </sql>

<!--
查询所有区域数据
area_name AS areaName 设置别名。其中area_name为字段名,areaName为别名
  -->
    <select id="selectAll" resultType="area">
        SELECT
        <include refid="area_column"></include>
        FROM tb_area
    </select>

效果图: 

方案二:

通过 resultMap 属性和标签可以解决列名不匹配的问题。

select 标签中的resultMap属性是对外部resultMap标签的命名引用。

注意:resultType和resultMap属性之间只能同时使用一个。

AreaMapper.xml 文件

    <resultMap id="areaResultMap" type="area">
        <id property="id" column="id"></id>
        <result property="areaName" column="area_name"></result>
        <result property="areaCode" column="area_code"></result>
    </resultMap>

    <select id="selectAll2" resultMap="areaResultMap">
        SELECT * FROM tb_area
    </select>

结果图:


 

1.2、查询-查看详情

参数占位符:

 

定义:

1、#{ } :会将其替换为 ? ,为了防止SQL注入。 

2、${ } :拼SQL,会存在SQL注入问题。

使用场景:

参数传递的时候使用 #{ } 

表名或者列名不固定的情况下,使用 ${ } 进行SQL拼接

#{ } 示例代码如下:

    <!--
    其中 #{id} 表示要传递的数据
    -->
    <select id="getAreaById" resultType="com.itheima.pojo.Area">
        SELECT * FROM tb_area WHERE id = #{id}
    </select>

${ } 示例代码如下 

    <select id="selectAll3" resultMap="areaResultMap">
        SELECT ${tableName} FROM tb_area
    </select>

parameterType: 用于设置参数类型,该参数可以省略。

SQL语句中特殊字符处理:

例如:WHERE 后面的条件是小于号时,代码就会报错,如下报错代码:

    <select id="selectAll4" resultMap="areaResultMap">
        SELECT * FROM tb_area WHERE tb_area.area_code < 100
    </select>

解决办法:

1、通过转移字符来处理该问题

 通过转义字符处理如下代码

    <select id="selectAll4" resultMap="areaResultMap">
        SELECT * FROM tb_area WHERE tb_area.area_code &lt; 100
    </select>

常见转移字符如下:

转义字符符号说明
&lt ;<小于号
&gt ;>大于号
&lt ;&gt ;<>不等号

2、通过 CDATA区 来处理。输入大写CD,然后回车,然后输入条件

    <select id="selectAll4" resultMap="areaResultMap">
        SELECT * FROM tb_area WHERE tb_area.area_code
        <![CDATA[
           这里输入条件,例如:<
        ]]>
        100
    </select>

1.3、查询-多条件查询

需求:根据当前状态、企业名称、品牌名称进行条件查询,如下图所示:

分析: 

 在上述列表条件查询需求中, 首选需要分析出

  1. 条件表达式是什么?
  2. 如何连接?是使用AND关键字来进行连接,还是通过OR关键字来进行连接?

具体分析结果如下图所示:

具体编写步骤:

方式一:

参数接收为散装参数,如果方法中有多个参数,需要使用@Param("SQL参数占位符名

1、编写Mapper接口方法,参数为查询条件,结果为List<Brand>称")

    /**
     * 方式一:
     * Param中的 status 对应的就是select语句中的 #{status} 占位符
     */
    List<Brand> select(@Param("status") int status,@Param("companyName") String companyName,@Param("brandName") String brandName);

 2、编写SQL语句,设置参数占位符

    <!--
        id:唯一标识
        type:映射的类型,支持别名
    -->
    <resultMap id="brandResultMap" type="brand">
        <!--
            id:完成主键字段的映射
                column:表的列名
                property:实体类的属性名
            result:完成一般字段的映射
                column:表的列名
                property:实体类的属性名
        -->
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>


    <select id="select" resultMap="brandResultMap">
        SELECT * FROM tb_brand WHERE status = #{status} AND company_name LIKE #{companyName} AND brand_name LIKE #{brandName}
    </select>

3、执行方法进行测试

    @Test
    public void testBrandList() throws IOException {

        // 模拟查询条件
        int status = 0;
        String companyName = "松鼠";
        String brandName = "松鼠";


        // 处理模糊查询
        companyName = "%"+companyName+"%";
        brandName = "%"+brandName+"%";


        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
        List<Brand> select = brandMapper.select(status, companyName, brandName);

        System.out.println(select.toString());


        sqlSession.close();
    }

tb_brand表如下图所示: 

执行结果如下图所示: 

方式二:

参数为对象参数,对象的属性名称要和参数占位符名称一致。 

1、编写Mapper接口方法,参数为对象,结果为List<Brand>

    /**
     * 方式二:
     * 如果这三个参数都是Brand类中的属性,那么就可以使用Brand对象传递的方式,#{status} 占位符会自动在Brand对象中查找getStatus()方法,然后设置值
     * @param brand
     * @return
     */
    List<Brand> select(Brand brand);

 2、编写SQL语句,设置参数占位符

    <!--
        id:唯一标识
        type:映射的类型,支持别名
    -->
    <resultMap id="brandResultMap" type="brand">
        <!--
            id:完成主键字段的映射
                column:表的列名
                property:实体类的属性名
            result:完成一般字段的映射
                column:表的列名
                property:实体类的属性名
        -->
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>


    <select id="select" resultMap="brandResultMap">
        SELECT * FROM tb_brand WHERE status = #{status} AND company_name LIKE #{companyName} AND brand_name LIKE #{brandName}
    </select>

3、执行方法进行测试

    /**
     * 通过对象参数来查询
     * @throws IOException
     */
    @Test
    public void testBrandList2() throws IOException {
        // 模拟查询条件
        int status = 0;
        String companyName = "松鼠";
        String brandName = "松鼠";

        // 处理模糊查询
        companyName = "%"+companyName+"%";
        brandName = "%"+brandName+"%";

        // 将参数封装成对象
        Brand brand = new Brand();
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
        brand.setStatus(status);

        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        List<Brand> select = brandMapper.select(brand);
        System.out.println(select.toString());

        sqlSession.close();
    }

执行结果如下图所示: 

方式三:

map中键的名称需要和SQL语句中的参数占位符相同。

1、编写Mapper接口方法,参数为对象,结果为List<Brand>

    /**
     * 方式三:
     * 通过map集合参数查询
     * @param map
     * @return
     */
    List<Brand> select(Map map);

  2、编写SQL语句,设置参数占位符

    <!--
        id:唯一标识
        type:映射的类型,支持别名
    -->
    <resultMap id="brandResultMap" type="brand">
        <!--
            id:完成主键字段的映射
                column:表的列名
                property:实体类的属性名
            result:完成一般字段的映射
                column:表的列名
                property:实体类的属性名
        -->
        <result column="brand_name" property="brandName"/>
        <result column="company_name" property="companyName"/>
    </resultMap>


    <select id="select" resultMap="brandResultMap">
        SELECT * FROM tb_brand WHERE status = #{status} AND company_name LIKE #{companyName} AND brand_name LIKE #{brandName}
    </select>

3、执行方法测试

    /**
     * 通过对象参数来查询
     * @throws IOException
     */
    @Test
    public void testBrandList3() throws IOException {
        // 模拟查询条件
        int status = 0;
        String companyName = "松鼠";
        String brandName = "松鼠";

        // 处理模糊查询
        companyName = "%"+companyName+"%";
        brandName = "%"+brandName+"%";

        // 将参数封装成map
        HashMap hashMap = new HashMap();
        hashMap.put("status",status);
        hashMap.put("companyName",companyName);
        hashMap.put("brandName",brandName);



        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        List<Brand> select = brandMapper.select(hashMap);
        System.out.println(select.toString());

        sqlSession.close();
    }

运行结果:

总结:

SQL语句设置多个参数有几种方式?

 

  • 散装参数:需要使用@param("SQL中的参数占位符名称")
  • 实体类封装参数:只需要保证SQL中的参数名与实体类中的属性名一致即可
  • map集合:只需要保证SQL中的参数名与map集合中的键名称一致即可        

  

1.4、查询-多条件-动态条件查询  

动态条件查询指的是SQL语句会随着用户的输入或外部条件的变化而变化,我们称之为动态SQL。

在上述条件查询中,会出现只输入品牌名称来进行查询的情况,那么通过固定的SQL语句来进行查询就无法满足需求了,那么这个时候就需要用到动态SQL来进行查询

MyBatis中的提供动态SQL的标签如下:

  •  if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

固定SQL代码如下:

    <!--   多条件查询 -->
    <select id="select" resultMap="brandResultMap">
        SELECT *
        FROM tb_brand
        WHERE status = #{status}
          AND company_name LIKE #{companyName}
          AND brand_name LIKE #{brandName}
    </select>

动态SQL 代码如下:

   <!--
        动态条件查询
            * if: 条件判断
                * test:逻辑表达式
            * 如何解决当status未传入该参数,后边出现SQL语法的问题(SELECT * FROM tb_brand WHERE AND company_name LIKE ?),也就是WHERE后面跟的是AND:
                1、通过恒等式( where 1 = 1)来过度一下,最终拼接的SQL语句为:SELECT * FROM tb_brand WHERE 1=1 AND company_name LIKE ?
                2、通过 <where>标签来替换 where 关键字,在最终拼接SQL语句时,如果出现上述问题,该标签会自动将AND关键字去除,最终得出的SQL语句为SELECT * FROM tb_brand WHERE company_name LIKE ?
                推荐方式二
    -->
    <select id="selectByCondition" resultMap="brandResultMap">
        select *
        from tb_brand
        /* where 1 = 1*/
        <where>

            <if test="status != null">
                and status = #{status}
            </if>
            <if test="companyName != null and companyName != '' ">
                and company_name like #{companyName}
            </if>
            <if test="brandName != null and brandName != '' ">
                and brand_name like #{brandName}
            </if>
        </where>

    </select>

总结:

if 用于判断参数是否有值,使用test属性来进行条件判断,但是存在一个问题,就是第一个条件不需要逻辑运算符,解决方案如下两种:

  • 使用恒等式让所有条件格式都一样
  • 使用<where>标签替换where关键字

1.5、查询-单条件-动态条件查询 

单条件动态查询指的是从多个条件中选择一个,例如根据不同的状态来查询数据

MyBais提供了 choose (when, otherwise) 标签,类似于Java中的switch语句,其中choose就类似于switch关键字,when就类似于case关键字,otherwise就类似于default关键字,示例如下:

    <select id="selectByConditionSingle" resultMap="brandResultMap">
        select *
        from tb_brand
        where
        <choose><!--相当于switch-->
            <when test="status != null"><!--相当于case-->
                status = #{status}
            </when>
            <when test="companyName != null and companyName != '' "><!--相当于case-->
                company_name like #{companyName}
            </when>
            <when test="brandName != null and brandName != ''"><!--相当于case-->
                brand_name like #{brandName}
            </when>
            <otherwise>
                1 = 1
            </otherwise>
        </choose>
    </select>

通过where标签再次优化代码,使用where标签的可以去除相关的语法错误,例如: SELECT * FROM tb_brand WHERE

    <select id="selectByConditionSingle" resultMap="brandResultMap">
        select *
        from tb_brand
        <where>
            <choose><!--相当于switch-->
                <when test="status != null"><!--相当于case-->
                    status = #{status}
                </when>
                <when test="companyName != null and companyName != '' "><!--相当于case-->
                    company_name like #{companyName}
                </when>
                <when test="brandName != null and brandName != ''"><!--相当于case-->
                    brand_name like #{brandName}
                </when>

            </choose>
        </where>
    </select>

2、添加 

2.1、表单添加

具体步骤:

1、编写Mapper接口方法:

    /**
     * 添加
     */
    void add(Brand brand);

2、编写SQL语句

<!--
添加SQL语句
-->
    <insert id="add" >
        insert into tb_brand (brand_name, company_name, ordered, description, status)
        values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
    </insert>

3、执行方法测试

注意:SqlSessionFactory中的 openSession()函数默认是开启事务的,进行增删改查操作后需要使用 sqlSession.commit(); 手动提交事务。也可以设置为自动提交事务(关闭事务),单代码为 openSession(true);

    @Test
    public void testAdd() throws IOException {
        //接收参数
        int status = 1;
        String companyName = "波导手机";
        String brandName = "波导";
        String description = "手机中的战斗机";
        int ordered = 100;


        //封装对象
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
        brand.setDescription(description);
        brand.setOrdered(ordered);

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 执行方法

        brandMapper.add(brand);

        //提交事务
        sqlSession.commit();

        //5. 释放资源
        sqlSession.close();

    }

2.2、表单添加-主键返回

主键返回指的是在数据添加完成以后,需要获取当前数据的主键id

其实只需要在insert标签中添加如下属性即可

useGeneratedKeys="true" keyProperty="id"

useGeneratedKeys="true" 表示使用生成的秘钥 

keyProperty="id" 表示主键的名称

<!--
添加SQL语句
-->
    <insert id="add" useGeneratedKeys="true" keyProperty="id">
        insert into tb_brand (brand_name, company_name, ordered, description, status)
        values (#{brandName}, #{companyName}, #{ordered}, #{description}, #{status});
    </insert>

3、修改

3.1、修改全部字段

具体步骤:

① 编写Mapper接口

    /**
     * 修改
     */
    int update(Brand brand);

② 编写SQL语句

<!--  更新 -->
    <update id="update">
        update tb_brand
        set brand_name = #{brandName},
            company_name = #{companyName},
            ordered = #{ordered},
            description = #{description},
            status = #{status}
        where id = #{id};
    </update>

③ 执行方法进行测试

    @Test
    public void testUpdate() throws IOException {
        //接收参数
        int status = 0;
        String companyName = "波导手机";
        String brandName = "波导";
        String description = "波导手机,手机中的战斗机";
        int ordered = 200;
        int id = 6;


        //封装对象
        Brand brand = new Brand();
        brand.setStatus(status);
        brand.setCompanyName(companyName);
        brand.setBrandName(brandName);
        brand.setDescription(description);
        brand.setOrdered(ordered);
        brand.setId(id);

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 执行方法
        int count = brandMapper.update(brand);
        System.out.println(count);
        //提交事务
        sqlSession.commit();

        //5. 释放资源
        sqlSession.close();

    }

3.2、修改动态字段

也就是修改部分字段

① 编写Mapper 接口

    /**
     * 修改
     */
    int update(Brand brand);

② 编写SQL语句

在编写动态SQL语句时,可以使用<set>标签来代替set关键字,防止出现SET后面没有SQL语句,或者SQL语句最后面有一个多余的逗号等等问题

    <update id="update">
        update tb_brand
        <set>
            <if test="brandName != null and brandName != ''">
                brand_name = #{brandName},
            </if>
            <if test="companyName != null and companyName != ''">
                company_name = #{companyName},
            </if>
            <if test="ordered != null">
                ordered = #{ordered},
            </if>
            <if test="description != null and description != ''">
                description = #{description},
            </if>
            <if test="status != null">
                status = #{status}
            </if>
        </set>
        where id = #{id};
    </update>

③ 执行方法,进行测试

    @Test
    public void testUpdate() throws IOException {
        //接收参数
        int status = 0;
        String companyName = "波导手机";
        String brandName = "波导";
        String description = "波导手机,手机中的战斗机";
        int ordered = 200;
        int id = 6;


        //封装对象
        Brand brand = new Brand();
        brand.setStatus(status);
//        brand.setCompanyName(companyName);
//        brand.setBrandName(brandName);
//        brand.setDescription(description);
//        brand.setOrdered(ordered);
        brand.setId(id);

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 执行方法
        int count = brandMapper.update(brand);
        System.out.println(count);
        //提交事务
        sqlSession.commit();

        //5. 释放资源
        sqlSession.close();

    }

4、删除

4.1、删除一个

具体步骤:

1、编写Mapper接口

    /**
     * 根据id删除
     */
    void deleteById(int id);

2、编写SQL语句

    <delete id="deleteById">
        delete
        from tb_brand
        where id = #{id};
    </delete>

3、执行测试代码

    @Test
    public void testDeleteById() throws IOException {
        //接收参数

        int id = 6;

        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 执行方法

        brandMapper.deleteById(id);

        //提交事务
        sqlSession.commit();

        //5. 释放资源
        sqlSession.close();

    }

4.2、批量删除

 具体步骤:

① 编写Mapper接口

    /**
     * 批量删除
     */
    void deleteByIds(int[] ids);

② 编写SQL 语句

    <!--
        mybatis会将数组参数,封装为一个Map集合。
            * 默认:array = 数组
            * 使用@Param注解改变map集合的默认key的名称
    -->

    <delete id="deleteByIds">
        delete from tb_brand where id
        in
        <foreach collection="array" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
        ;
    </delete>

<foreach> 标签可以完成数组的遍历

collection="array"   其中collection属性指定的是需要遍历哪个数组/集合。mybatis会将数组参数封装为一个Map集合,该集合是通过key和value来存储的,默认key的名称为array,value就是对应的数组参数。如果想改变默认key的名称,可以使用@Param注解来实现
    /**
     * 批量删除
     */
    void deleteByIds(@Param("ids") int[] ids);
    <!--
        mybatis会将数组参数,封装为一个Map集合。
            * 默认:array = 数组
            * 使用@Param注解改变map集合的默认key的名称
    -->

    <delete id="deleteByIds">
        delete from tb_brand where id
        in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
        ;
    </delete>

item="id"    item属性指定的是遍历出来的每个元素

separator="," 表示设置分隔符为逗号,主要是为拼接SQL,例如:DELETE FROM tb_brand WHERE id IN (1,2,3);

 open="("   表示开始遍历之前添加的数据,主要是为了组拼SQL
 close=")" 表示遍历完成以后要添加的数据,主要是为了组拼SQL

③ 执行方法进行测试

    @Test
    public void testDeleteByIds() throws IOException {
        //接收参数

        int[] ids = {5,7,8};


        //1. 获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2. 获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //SqlSession sqlSession = sqlSessionFactory.openSession(true);

        //3. 获取Mapper接口的代理对象
        BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);

        //4. 执行方法

        brandMapper.deleteByIds(ids);

        //提交事务
        sqlSession.commit();

        //5. 释放资源
        sqlSession.close();

    }

MyBatis参数传递

MyBatis 接口方法中可以接收各种各样的参数,MyBatis底层对于这些参数进行不同的封装处理方式:

单个参数:

  • POJO类型,直接使用,实体类属性名和参数占位符名称一致
  • Map集合,直接使用,键名和参数占位符名称一致
  • Collection
  • List
  • Array
  • 其它类型

多个参数:

  • 通过@Param注解来传递

建议:将来都使用@Param注解来修改Map集合中默认的键名,并使用修改后的名称来获取值,这样可读性更高!

通过在Mapper类中的函数注解完成增删改查

使用注解开发会比配置文件开发更加方便,例如根据id获取用户数据如下代码所示:

    /**
     * 根据id获取Brand
     * @param id
     * @return
     */
    @Select("SELECT * FROM tb_brand WHERE id = #{id}}")
    Brand getBrandById(int id);
  • 查询:@Select
  • 添加:@Insert
  • 修改:@Update
  • 删除:@Detele        

通过注解完成简单功能,通过配置文件的方式完成复杂功能

        

其它:

MyBatisX 插件

        MyBatisX是一款基于IDEA的快速开发插件,为效率而生。

主要的功能:

        1、XML 和 接口方法 项目跳转

        2、根据接口方法生成 statement

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郭宝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值