Mybatis基本使用

学习资源:
b站:遇见狂神说
链接:https://www.bilibili.com/video/BV1NE411Q7Nx/?spm_id_from=333.999.0.0

使用环境:

  • jdk1.8
  • mysql5.7
  • maven3.8

1、第一个Mybatis程序

1.1、搭建数据库
CREATE DATABASE `mybatis`

CREATE TABLE `user` (
	`id` INT(20) NOT NULL PRIMARY KEY,
	`name` VARCHAR(30) DEFAULT NULL,
	`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES 
(1,'jack','123'),
(2,'tom','123'),
(3,'smith','123')
1.2、使用idea创建一个maven项目

导入依赖:

<!--数据库驱动依赖-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
<!--mybatis依赖-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.7</version>
</dependency>
<!--junit单元测试-->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>
<dependency>
    <!--lombok依赖-->
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
    <scope>compile</scope>
</dependency>
1.3、编写mybatis核心配置文件
<?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>

    <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://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;charsetEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

</configuration>
1.4、创建工具类,获取sqlSessionFactory对象
package com.yang.utils;

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;

public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory = null;

    static {
        String resource = "mybatis-config.xml";
        try {
            // 获取sqlSessionFactory对象
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从sqlSessionFactory对象获取sqlSession实例
     * sqlSession:执行sql语句的对象
     */
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
1.5、编写测试代码

实体类:

package com.yang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

接口:

package com.yang.dao;

import com.yang.pojo.User;

import java.util.List;

public interface UserMapper {
    List<User> getUserList();
}

接口对应的mapper.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:对应的dao接口-->
<mapper namespace="com.yang.dao.UserMapper">
    <!--
        id:对应dao接口的方法名
        resultType:返回的类型
    -->
    <select id="getUserList" resultType="com.yang.pojo.User">
        select * from user
    </select>

</mapper>

在mybatis核心配置文件中(configuration标签内)注册mapper:

<mappers>
    <mapper resource="com/yang/dao/UserMapper.xml" />
</mappers>

测试:

package com.yang.dao;

import com.yang.pojo.User;
import com.yang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {

    @Test
    public void test(){
        // 1获取sqlSession实例
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        // 2执行sql
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

注意:如果mapper.xml定义在resources目录之外,需要在pom.xml下配置

<build>
    <resources>
        <resource>
            <!-- 选择需要导出资源的路径 -->
            <directory>src/main/resources</directory>
            <includes>
                <!-- 写入需要导出文件的类型 -->
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <!-- 是否过滤这些文件 -->
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
1.6、总结

步骤:

  1. maven项目下使用mybatis需要在resources目录下创建一个mybatis的核心配置文件
  2. 创建数据库对应的实体类
  3. 编写接口
  4. 接口对应的mapper
  5. 配置文件中注册mapper
  6. 测试

注意点:

  1. 注意每一个接口对应一个mapper.xml文件,接口和接口中的方法,在mapper.xml文件中对应
  2. 在mybatis核心配置文件中注册对应的mapper使其生效
  3. mapper.xml不在resources目录下创建时,需要处理配置文件之外的载失败的问题

2、增删改查

在UserMapper接口下添加方法:

// 根据id查询用户
User getUserById(int id);
// 添加一个用户
int addUser(User user);
// 修改用户信息
int updateUser(User user);
// 根据id删除用户
int deleteUser(int id);

对应的mapper:

<!--根据id查询用户-->
<!--
    parameterType:参数类型
-->
<select id="getUserById" resultType="com.yang.pojo.User" parameterType="int">
    select * from user where id = #{id}
</select>

<!--增加用户-->
<!--
    1 增删改操作返回类型都是int,可以省略不写
    2 增删改操作必须提交事务,否者不成功
-->
<insert id="addUser" parameterType="com.yang.pojo.User">
    insert into user values(#{id},#{name},#{pwd})
</insert>

<!--修改用户信息-->
<update id="updateUser" parameterType="com.yang.pojo.User">
    update user set name=#{name},pwd=#{pwd} where id=#{id}
</update>

<!--删除用户-->
<delete id="deleteUser" parameterType="int">
    delete from user where id=#{id}
</delete>

测试:

/**
 * 删除用户
 */
@Test
public void test05(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.deleteUser(4);
    sqlSession.commit();
    sqlSession.close();
}

/**
 * 修改用户信息
 */
@Test
public void test04(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.updateUser(new User(3,"smith","123"));
    sqlSession.commit();
    sqlSession.close();
}

/**
 * 增加一个用户
 */
@Test
public void test03(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.addUser(new User(4,"milan","123"));
    sqlSession.commit();
    sqlSession.close();
}

/**
 * 查询单个用户
 */
@Test
public void test02(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.getUserById(2);
    System.out.println(user);
    sqlSession.commit();
    sqlSession.close();
}

注意:

  1. 传递的参数类型是基本数据类型时,可以省略parameterType不写
  2. 增删改操作返回类型都是int,可以省略resultType不写
  3. 增删改操作必须提交事务,否者不成功

3、核心配置文件引入外部配置文件

resources目录下创建外部配置文件:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8"
username=root
password=root

核心配置文件中引入外部配置文件:

<?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>
    <!--引入外部配置文件-->
    <properties resource="db.properties">
        <!--可以添加属性-->
        <!--因为外部配置文件中有属性password,则优先使用外部配置文件的配置-->
        <property name="password" value="123"/>
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/yang/dao/UserMapper.xml" />
    </mappers>
</configuration>

注意:

  1. 可以在核心配置文件中引入外部配置文件
  2. 可以在核心配置文件中增加一些属性
  3. 如果核心配置文件和外部配置文件中有共同属性字段,优先使用外部配置文件的

4、别名替代全类名

方式1指定别名(指定具体类):

<!--方式1使用别名-->
<typeAliases>
    <!--
        type:指定全类名
        alias:别名
    -->
    <typeAlias type="com.yang.pojo.User" alias="User" />
</typeAliases>

方式2指定别名(扫描包):

<!--方式2使用别名-->
<typeAliases>
    <!--为com.yang.pojo包下的实现类设置别名,默认为以小写字母开头的类名-->
    <package name="com.yang.pojo"/>
</typeAliases>

使用方式2指定别名,不适用默认别名情况下,需要单独设置别名时使用注解@Alias(“别名”)的方式:

package com.yang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias("testUser") // 设置别名为testUser
public class User {
    private int id;
    private String name;
    private String pwd;
}

5、映射器

方式1:指定接口对应的mapper配置文件绑定

<mappers>
    <mapper resource="com/yang/dao/UserMapper.xml" />
</mappers>

方式2:接口全类名绑定

<mappers>
    <mapper class="com.yang.dao.UserMapper" />
</mappers>

方式3:扫描包绑定

<mappers>
    <package name="com.yang.dao"/>
</mappers>

注意:使用时需要注意接口和mapper的存放位置

6、生命周期和作用域

6.1、SqlSessionFactoryBuilder
  • 一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder实例
  • 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)
6.2、SqlSessionFactory
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在
  • 使用 SqlSessionFactory 在应用运行期间尽量不要重复创建多次
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域
6.3、SqlSession
  • 每个线程都应该有它自己的 SqlSession 实例
  • SqlSession不能被共享,所以它的最佳的作用域是请求或方法作用域
  • 每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它

7、resultMap结果集映射

实体类属性名为password,数据库列名为pwd,使用resultMap解决:

<!--结果集映射resultMap-->
<resultMap id="userResultMap" type="user">
    <!--只需处理属性名和查询结果集的列名不一致的关系映射即可-->
    <!--column对应数据库列名,property对应实体类属性名-->
    <result column="pwd" property="password" />
</resultMap>
<!--resultMap属性值与resultMap标签的id属性值对应-->
<select id="getUserById" resultMap="userResultMap">
    select * from user where id = #{id}
</select>

8、日志

8.1、mybatis核心配置文件中设置标准的日志实现:

在核心配置文件中设置:

<!--日志功能-->
<settings>
    <!--标准的日志实现-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
8.2、Log4j日志实现
  • 通过Log4j日志可以输出日志到控制台,以及指定文件中
  • 可以指定输出日志的格式
  • 定义日志信息的级别可以精确控制日志的生成
  • 通过配置文件配置,不需要修改程序原有代码

1、导入log4j依赖:

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

2、resources目录下新建log4j.properties配置文件:

### 设置
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 级别以上的日志到=./log/debug.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./log/debug.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 级别以上的日志到=./log/error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =./log/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

3、编写测试类:

package com.yang.dao;

import org.apache.log4j.Logger;
import org.junit.Test;

public class Log4jTest {

    private static final Logger logger = Logger.getLogger(Log4jTest.class);
    @Test
    public void testLog4j(){
        // 记录debug级别的信息
        logger.debug("This is debug message.");
        // 记录info级别的信息
        logger.info("This is info message.");
        // 记录error级别的信息
        logger.error("This is error message.");
    }
}

4、查看控制台输出以及项目路径下生成目录和文件记录的内容

9、Mybatis实现分页

接口中添加方法:

/**
 * 分页查询
 */
List<User> getUserByLimit(Map<String,Integer> map);

mapper中添加分页查询语句:

<!--
    分页查询
        1 parameterType:接收参数类型
        2 resultMap:返回结果集映射
-->
<select id="getUserByLimit" parameterType="map" resultMap="userResultMap">
    select * from user limit #{startIndex},#{pageSize}
</select>

测试代码:

@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    // 使用map封装
    Map<String, Integer> map = new HashMap<>();
    map.put("startIndex",0);
    map.put("pageSize",3);
    List<User> userList = userMapper.getUserByLimit(map);
    for (User user : userList) {
        System.out.println(user);
    }
    sqlSession.close();
}

补充:

  1. parameterType接收类型,对应的取值类型
    1. 普通类型 int,double …,取值为_int …
    2. 包装类型Integer,Double …,取值为 integer …
  2. 当parameterType接受的类型是Map,取值时需要和Map的key对应

9、Mybatis注解开发

Mybatis注解开发的底层逻辑是使用反射加载接口的结构,进而获取接口方法(返回类型,泛型,参数等)

  • 使用注解来映射简单语句会使代码显得更加简洁
  • 如果是一些很复杂的操作,最好用 XML 来映射语句
  • 简单的sql语句可以使用注解的方式实现,遇到一些复杂的sql语句,尽量使用xml语句的映射方式

接口代码:

package com.yang.dao;


import com.yang.pojo.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {

    @Select("select * from user")
    List<User> queryUsers();
}

核心配置文件中配置:

<!--绑定接口-->
<mappers>
    <mapper class="com.yang.dao.UserMapper" />
</mappers>

测试:

package com.yang;

import com.yang.dao.UserMapper;
import com.yang.pojo.User;
import com.yang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class TestUser {

    @Test
    public void testQueryUsers(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.queryUsers();
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

使用注解开发简单的CRUD操作:

// 根据id查询用户
@Select("select * from user where id = #{uid}")
User getUserById(@Param("uid") Integer id);

// 添加用户
@Insert("insert into user values (#{id},#{name},#{password})")
int addUser(User user);

// 修改用户信息
@Update("update user set name=#{name},pwd=#{password} where id=#{id}")
int updateUser(User user);

// 删除用户
@Delete("delete from user where id=#{uid}")
int deleteUser(@Param("uid") Integer id);
@Param注解的基本使用说明
  • 传入单个基本数据类型时,可以不指定@Param注解,默认值为参数名
  • 传入多个基本参数类型时,需要给每个基本类型的参数使用@Param注解
  • 执行sql预编译的参数对应的是@Param注解的值,而不是参数名
  • 包装类型不需要指定@Param注解

10、复杂结果集映射

添加数据库测试数据:

CREATE TABLE `teacher` (
	`id` INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `teacher` VALUES(1,'李老师')

CREATE TABLE `student` (
	`id` INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	`tid` INT(10) DEFAULT NULL,
	PRIMARY KEY (`id`),
	KEY `fktid` (`tid`),
	CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO `student` VALUES ('1','小明','1');
INSERT INTO `student` VALUES ('2','小强','1');
INSERT INTO `student` VALUES ('3','小红','1');
INSERT INTO `student` VALUES ('4','小李','1');
INSERT INTO `student` VALUES ('5','小王','1');

teacher对应实体类:

package com.yang.pojo;

import lombok.Data;

@Data
public class Teacher {
    private Integer id;
    private String name;
}

student对应实体类:

package com.yang.pojo;

import lombok.Data;

@Data
public class Student {
    private Integer id;
    private String name;
}
10.1、对一关系

这里以一个学生对应一个老师的形式举例

Student实体中添加对象属性:

// 一个学生关联一个老师
private Teacher teacher;

StudentMapper.xml:

<!--使用联表查询的方式-->
<select id="studentList" resultMap="studentMap">
    select s.id sid,s.name sname,t.id tid,t.name tname
    from student s
    join teacher t
    on s.tid = t.id
</select>

<!--结果集映射-->
<resultMap id="studentMap" type="student">
    <id property="id" column="sid" />
    <result property="name" column="sname" />
    <!--对象类型的属性映射关系使用association-->
    <!--
        property:Student实体类对应的属性名
        javaType:实体类型,这里使用了别名的方式,可以使用全类名的方式
    -->
    <association property="teacher" javaType="teacher">
        <!--这里映射的是Teacher实体类的对应关系-->
        <id property="id" column="tid" />
        <result property="name" column="tname" />
    </association>
</resultMap>

注意:

  • 对象类型属性关系映射使用association和javaType
  • property属性对应的是实体类属性
  • column属性对应的是查询结果返回的列名
  • 因为查询结果时使用了别名的方式,所以属性column取值为别名的方式
10.2、对多关系

这里以一个老师对应多个学生的形式举例

Teacher实体类中添加集合类型属性:

// 一个老师对应多个学生
private List<Student> studentList;

TeacherMapper.xml:

<select id="queryById" resultMap="teacherMap">
    SELECT t.id tid,t.name tname,s.id sid,s.name sname
    FROM `teacher` t
    JOIN `student` s
    ON t.id = s.tid
    where tid = #{tid}
</select>

<resultMap id="teacherMap" type="teacher">
    <id property="id" column="tid" />
    <result property="name" column="tname" />
    <!--集合类型的属性映射关系使用collection-->
    <!--使用ofType指定集合泛型的类型-->
    <collection property="studentList" ofType="student">
        <id property="id" column="sid" />
        <result property="name" column="sname" />
    </collection>
</resultMap>

测试:

@Test
public void testTeacher(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
    Teacher teacher = teacherMapper.queryById(1);
    System.out.println(teacher);
    sqlSession.close();
}

注意:

  • 集合类型的属性关系映射与对象类型属性关系映射不同
  • 集合类型的属性关系映射是使用collection和ofType
  • ofType指定的类型为集合的泛型类型
总结
  • 当处理简单的普通类型的映射关系时,使用resultType
  • 处理复杂类型(对象、集合)的映射关系时,需要使用结果集映射resultMap
  • 处理结果集映射的关系时,需要注意属性名和列名的问题

11、动态SQL

  • 在数据库层面增加一些逻辑,根据条件动态生成不同的sql语句

数据库准备:

CREATE TABLE `blog` (
	`id` VARCHAR(50) NOT NULL COMMENT '博客id',
	`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
	`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

核心配置文件:

<!--引入外部配置文件-->
<properties resource="db.properties" />

<settings>
    <!--mybatis默认日志打印-->
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <!--开启驼峰命名转换-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

<!--扫描包使用别名-->
<typeAliases>
    <package name="com.yang.pojo"/>
</typeAliases>

创建新的工具类:

package com.yang.utils;

import java.util.UUID;

public class IdUtils {

    /**
     * 返回一个随机的string类型的id
     */
    public static String getId(){
        return UUID.randomUUID().toString().replace("-","");
    }
}

实体类:

package com.yang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private Integer views;
}

接口:

package com.yang.dao;

import com.yang.pojo.Blog;

public interface BlogMapper {

    int addBlog(Blog blog);
}

接口对应mapper:

<insert id="addBlog">
    insert into blog values (#{id},#{title},#{author},#{createTime},#{views})
</insert>

插入数据:

@Test
public void insertTest(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    blogMapper.addBlog(new Blog(IdUtils.getId(),"Mybatis如此简单","jack",new Date(),8888));
    blogMapper.addBlog(new Blog(IdUtils.getId(),"Spring如此简单","tom",new Date(),7777));
    blogMapper.addBlog(new Blog(IdUtils.getId(),"SpringMVC如此简单","smith",new Date(),4444));
    blogMapper.addBlog(new Blog(IdUtils.getId(),"SpringBoot如此简单","milan",new Date(),5555));
    sqlSession.commit();
    sqlSession.close();
}
11.1、if
  • 使用if动态拼接 SQL 最常见情景是根据条件包含 where 子句的一部分

接口:

List<Blog> queryBlogs(Map<String, Object> map);

mapper:

<select id="queryBlogs" parameterType="map" resultType="blog">
    <!--使用if标签动态拼接符合条件的sql语句,这里使用 where 1 = 1 演示,实际开发不会这样使用,因为有风险-->
    select * from blog where 1 = 1
    <if test="title != null">
        and title=#{title}
    </if>
    <if test="author != null">
        and author=#{author}
    </if>
</select>

测试:

@Test
public void queryBlogTest(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    HashMap<String, Object> map = new HashMap<>();
    map.put("author","tom");
    List<Blog> blogList = blogMapper.queryBlogs(map);
    for (Blog blog : blogList) {
        System.out.println(blog);
    }
    sqlSession.close();
}

通过传入Map,对指定内容进行筛选,使用if标签拼接sql实现不同的查询结果

11.2、where
  • where只会在至少一个子元素返回SQL子句的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where元素也会将它们去除,避免了sql语句拼接错误

去除mapper中的 where 1 = 1:

<select id="queryBlogs" parameterType="map" resultType="blog">
    <!--使用if标签动态拼接符合条件的sql语句-->
    select * from blog
    <where>
    	<if test="title != null">
            and title=#{title}
        </if>
        <if test="author != null">
            and author=#{author}
        </if>
    </where>
</select>
11.3、choose、when、otherwise
  • 当我们只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 java中的 switch 语句

mapper:

<select id="queryBlogs" parameterType="map" resultType="blog">
    <!--使用choose、when、otherwise标签动态拼接符合条件的sql语句,拼接的结果只有0个或者1个-->
    <!--使用形式与java中的 switch 语句类似-->
    select * from blog
    <where>
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views = #{views}
            </otherwise>
        </choose>
    </where>
</select>

测试:

@Test
public void queryBlogTest(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    HashMap<String, Object> map = new HashMap<>();
    map.put("title","SpringBoot如此简单");
    map.put("author","tom");
    map.put("views",8888);
    List<Blog> blogList = blogMapper.queryBlogs(map);
    for (Blog blog : blogList) {
        System.out.println(blog);
    }
    sqlSession.close();
}

当第一个条件满足时,下面的sql语句将不在拼接

11.4、set
  • set会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)

接口中添加方法 :

int updateBlog(Map<String,Object> map);

mapper:

<update id="updateBlog">
    update blog
    <set>
        <if test="title != null">
            title=#{title},
        </if>
        <if test="author != null">
            author=#{author}
        </if>
    </set>
    where id=#{id}
</update>

测试:

@Test
    public void updateBlogTest(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map<String, Object> map = new HashMap<>();
    map.put("title","Mybatis如此简单");
    map.put("author","jack");
    map.put("id","751e59e0a6934e509ab40f49d1a6a117");
    blogMapper.updateBlog(map);
    sqlSession.commit();
    sqlSession.close();
}

使用set时,当前面的条件满足,后面的条件不满足时,会自动去除多余的逗号,保证sql语句的正确

注意:当没有条件满足时,使用set,会导致sql语句拼接错误

11.5、sql片段
  • 把sql语句中的公共部分提取,方便复用
<!--sql标签的id属性与include标签的refid对应-->
<sql id="if_title_author">
    <choose>
        <when test="title != null">
            title = #{title}
        </when>
        <when test="author != null">
            and author = #{author}
        </when>
        <otherwise>
            and views = #{views}
        </otherwise>
    </choose>
</sql>

<select id="queryBlogs" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <include refid="if_title_author"></include>
    </where>
</select>

include标签相当于将sql标签的内容插入到where标签内,当下次有同样需求时,sql片段可以实现复用,建议使用时,sql片段内不包含where标签

11.6、foreach
  • 可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值

接口:

List<Blog> queryBlogsForeach(Map<String,Object> map);

mapper:

<select id="queryBlogsForeach" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <foreach collection="ids" item="id" open="(" separator="or" close=")">
            id=#{id}
        </foreach>
    </where>
</select>
  • collection是需要遍历的集合
  • item是集合中的每一个值
  • open表示在开头拼接
  • close表示在结尾拼接
  • separator每一个值之间的分隔符,比如:where (item1 or item2 …)

测试:

@Test
public void queryBlogsForeachTest(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map<String, Object> map = new HashMap<>();
    ArrayList<String> ids = new ArrayList<>();
    ids.add("751e59e0a6934e509ab40f49d1a6a117");
    ids.add("b7e24d13123e445cbdb6ef9230496eff");
    ids.add("5e6d4acc336342df9939033eb5c898c5");
    // 将list集合放入map集合中
    map.put("ids",ids);
    List<Blog> blogList = blogMapper.queryBlogsForeach(map);
    for (Blog blog : blogList) {
        System.out.println(blog);
    }
    sqlSession.close();
}
  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值