MyBatis入门笔记整理

目录

1.开发环境

2.Mybatis简介

2.1什么是mybatis

2.2如何获得mybatis

2.3持久化

2.4为什么需要mybatis 

3.快速入门——第一个Mybatis程序

3.1搭建环境

3.2代码编写

3.2.1编写实体类User

3.2.2编写UserMapper接口

3.2.3编写UserMapper.xml

 3.3在核心配置文件中注册Mapper

3.4测试

3.5常见错误排查

3.6初步总结 

4.CRUD操作

4.1 namespace说明

4.2 Select

4.3 Insert 

 4.4 Update

4.5 Detele

4.6注意事项

5.配置解析 

5.1核心配置文件mybatis-config.xml

 5.2环境配置(environments)

5.3属性(properties)

5.4设置别名

5.5设置(Settings)

5.6映射器 

5.7生命周期和作用域 

6.ResultMap解决字段不一致问题

6.1问题描述

6.2解决方法 

 7.日志

7.1LOG4J

 7.1.1导入LOG4j依赖

 7.1.2配置log4j.properties文件。放置在resource文件夹下的logj.properties

7.1.3在核心配置文件中配置

 7.1.4运行

 8.注解开发

8.1在接口上标上注解

8.2在核心配置文件中注册接口

8.3测试

8.4注意点

9.一对多、多对一查询 

 9.1创建学生和老师表

9.2多对一处理 (多个学生对应一个老师)

9.2.1问题提出

9.2.2解决方式

 9.3一对多处理(一个老师对应多个学生)

9.3.1问题提出

9.3.2解决方式

10.动态SQL(重点) 

 10.1 if用法

10.2 choose(when、otherwise)的用法

10.3 trim(where、set)的用法

10.3.1问题提出

10.3.2 问题解决

10.4 foreach的用法 

11.缓存机制

11.1简介

 11.2mybatis缓存

11.2.1一级缓存

​ 11.2.2二级缓存

11.3缓存原理


 

1.开发环境

MyBatis入门笔记整理

2.Mybatis简介

2.1什么是mybatis

MyBatis入门笔记整理

      简而言之就是负责操作数据库的框架,用来取代JDBC

2.2如何获得mybatis

 MyBatis入门笔记整理

         官方文档:https://mybatis.org/mybatis-3/zh/index.html

         maven仓库

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.2</version>
</dependency>

 

2.3持久化

MyBatis入门笔记整理

2.4为什么需要mybatis 

  • 传统JDBC代码复杂。为了简化、方便、自动化而诞生的框架
  • 位于Dao层,负责与数据库发生交互,增删改查等操作。
  • 用的人多,SSM框架之一

3.快速入门——第一个Mybatis程序

思路:搭建环境→导入Mybatis依赖→编写代码→测试

整个框架结构如下:

MyBatis入门笔记整理

 

3.1搭建环境

创建数据库


CREATE DATABASE `mybatis`;
use `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 (id,name,pwd) VALUES
(1,‘狂神’,‘123456’),
(2,‘张三’,‘123456’),
(3,‘李四’,‘123890’)

 

新建Maven项目并在pom.xml中导入maven依赖,删除父工程的src文件夹

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

在pom.xml导入如下代码以防资源过滤问题(如使用idea开发则会有这个问题)

<!--在build中配置resources,防止资源导出问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>

            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>

在父工程下创建子工程

MyBatis入门笔记整理 

在resource文件夹下添加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">
<!--mybatis核心配置文件-->
<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=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=GMT"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

 编写utils工具类,用于获取Sqlsession

 MyBatis入门笔记整理

 

package com.kuang.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;
    static{
        try {
            //1.获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            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();
    }
}

注意:这里的mybatis-config.xml就是我们上一步写的核心配置文件。名字没有要求,但一般命名为mybatis-config.xml。

3.2代码编写

3.2.1编写实体类User

package com.kuang.pojo;

public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

3.2.2编写UserMapper接口

package com.kuang.dao;

import com.kuang.pojo.User;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    //查询全部用户
    List<User> getUserList();

    //根据ID查询用户
    User getUserById(int id);

    //插入用户
    int addUser(User user);

    //修改用户
    int updateUser(User user);

    //删除用户
    int deleteUser(int id);

}

3.2.3编写UserMapper.xml

一个Mapper对应一个Mapper.xml。Mapper.xml是用于编写sql语句的。

<?xml version="1.0" encoding="UTF-8" ?>
<!--中文错误改成UTF8即可-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace绑定对应的接口-->
<mapper namespace="com.kuang.dao.UserMapper">
    <select id="getUserList" resultType="com.kuang.pojo.User">
        select * from mybatis.user
    </select>

    <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
        select * from mybatis.user where id= #{id}
    </select>

    <!--对象中的属性,可以直接取出来-->
    <insert id="addUser" parameterType="com.kuang.pojo.User" >
        insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})
    </insert>

    <update id="updateUser" parameterType="com.kuang.pojo.User">
        update mybatis.user
        set name =#{name},pwd=#{pwd}
        where id=#{id};
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>

</mapper>

几个参数的意义(这里先简单了解,后文会具体说明)

namespace:表示这个Mapper.xml对应的是哪个Mapper接口。

resultType:  返回类型。如查询所有用户。返回类型为User,注意写全类名

parameterType:  参数类型。方法传入的参数类型,如根据id查找用户,传入的id是整型int

id: 该sql语句对应Mapper接口中的哪个方法。

 3.3在核心配置文件中注册Mapper

    <!--每一个Mapper.xml都需要在mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>

3.4测试

package com.kuang.dao;

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

import java.util.HashMap;
import java.util.List;

public class UserDaoTest {


    @Test
    public void test(){
        //1.获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //2.执行sql
        //方式一:getMapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        System.out.println(userList);

        //方式二:需要强制类型转换,不推荐
        //List<User> objects = sqlSession.selectList("com.kuang.dao.UserMapper.getUserList");
        //System.out.println(objects);

        //3.关闭sqlSession
        sqlSession.close();
    }
}

3.5常见错误排查

见我的另一篇博客:https://blog.csdn.net/m0_56522574/article/details/119055121

3.6初步总结 

  • 编写实体类,属性名尽可能和数据库中字段名一致。
  • Mapper接口,用于实现增删改查操作
  • Mapper.xml用于实现增删改查的具体sql语句
  • 一个Mapper接口,对应一个Mapper.xml文件。通过在Mapper.xml中设置namespace表明两者对应关系
  • 一个Mapper.xml必须在核心配置文件中注册,方便mybatis找到。

4.CRUD操作

4.1 namespace说明

namespace:表示这个Mapper.xml对应的是哪个Mapper接口。需要一一对应

MyBatis入门笔记整理 

4.2 Select

Mapper接口

    //查询全部用户
    List<User> getUserList();

    //根据ID查询用户
    User getUserById(int id);

Mapper.xml文件 

    <select id="getUserList" resultType="com.kuang.pojo.User">
        select * from mybatis.user
    </select>

    <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
        select * from mybatis.user where id= #{id}
    </select>

 测试代码

    @Test
    public void test(){
        //1.获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //2.执行sql
        //方式一:getMapper
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        System.out.println(userList);

        //方式二:需要强制类型转换,不推荐
        //List<User> objects = sqlSession.selectList("com.kuang.dao.UserMapper.getUserList");
        //System.out.println(objects);

        //3.关闭sqlSession
        sqlSession.close();
    }

    @Test
    public void  test1(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        User user=sqlSession.selectOne("com.kuang.dao.UserMapper.getUserById",1);
        System.out.println(user);

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
    }

4.3 Insert 

Mapper接口

    //插入用户
    int addUser(User user);

Mapper.xml文件 

    <!--对象中的属性,可以直接取出来-->
    <insert id="addUser" parameterType="com.kuang.pojo.User" >
        insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd})
    </insert>

 测试代码

    @Test
    public void addUser(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(new User(4,"张飞","1234560"));
        sqlSession.commit();//增删改需要提交事务
        sqlSession.close();
    }

 4.4 Update

Mapper接口

    //修改用户
    int updateUser(User user);

Mapper.xml文件 

    <update id="updateUser" parameterType="com.kuang.pojo.User">
        update mybatis.user
        set name =#{name},pwd=#{pwd}
        where id=#{id};
    </update>

 测试代码

    @Test
    public void updateUser(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser(new User(4,"关公","guangong"));
        sqlSession.commit();
        sqlSession.close();
    }

4.5 Detele

Mapper接口

    //删除用户
    int deleteUser(int id);

Mapper.xml文件 


    <delete id="deleteUser" parameterType="int">
        delete from mybatis.user where id=#{id}
    </delete>

 测试代码

    @Test
    public void deleteUser(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(4);
        sqlSession.commit();
        sqlSession.close();
    }

4.6注意事项

增删改操作需要提交事务:即加上sqlSession.commit()

xxxMapper.xml一定要在核心配置文件中注册

xxxMapper.xml一定要绑定xxxMapper接口

5.配置解析 

5.1核心配置文件mybatis-config.xml

MyBatis入门笔记整理

 5.2环境配置(environments)

MyBatis入门笔记整理

  Mybatis默认的事务管理器是jdbc,使用连接池:POOLED

5.3属性(properties)

MyBatis入门笔记整理

注意属性优先级 

MyBatis入门笔记整理

 具体使用:

配置db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT
username=root
password=123456

修改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">
<!--mybatis核心配置文件-->

<configuration>
    <!--映入外部配置文件-->
    <properties resource="db.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>
    <!--每一个Mapper.xml都需要在mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/kuang/dao/UserMapper.xml"/>
    </mappers>
</configuration>

 MyBatis入门笔记整理

 注意红框处内容,需要和db.properties一致。属性名一致!文件名一致!

5.4设置别名

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:

    <typeAliases>
        <typeAlias type="com.kuang.pojo.User" alias="user"></typeAlias>
    </typeAliases>

 MyBatis入门笔记整理

设置别名后红框处的内容就可以替换为user,减少冗余。 

 方式二:为某一个包下所有类,自动设置别名。在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。 比如com.kuang.pojo.User的别名为user ;若有注解,则别名为其注解值。见下面的例子:

MyBatis入门笔记整理 

一些Java内置类。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。 具体见官方文档。

5.5设置(Settings)

经常使用的有:

MyBatis入门笔记整理

 MyBatis入门笔记整理

MyBatis入门笔记整理

5.6映射器 

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如

MyBatis入门笔记整理 

 

1.推荐使用第一种和第三种

2.第三种和第四种方式需要保证:

  •         接口和他的配置文件必须同名
  •         接口和他的配置文件必须在同一个包下

 

5.7生命周期和作用域 

理解我不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。

  • 可以理解为局部变量

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 

  • 可以理解为数据库连接池
  • 最佳作用域是应用作用域

SqlSession

每个线程都应该有它自己的 SqlSession 实例。

  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 
  • 可以理解为JDBC中的一个Connection
  • 用完之后需要关闭,否则资源占用

MyBatis入门笔记整理

 

MyBatis入门笔记整理

 

6.ResultMap解决字段不一致问题

6.1问题描述

 MyBatis入门笔记整理

 实体类中的字段

MyBatis入门笔记整理

 发现password和pwd名字不一致!

6.2解决方法 

 解决方法一:起别名。sql语句可以给字段名起别名

 MyBatis入门笔记整理

 

 解决方法二(推荐):使用结果集映射

MyBatis入门笔记整理 

resultMap:结果集映射

数据库:id   name   pwd

                ↓      ↓         ↓

实体类:id   name   password

 

 7.日志

如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!

取代debug和sout的方式!

 日志在在核心配置文件settings中进行配置MyBatis入门笔记整理

MyBatis入门笔记整理 

7.1LOG4J

 Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件

  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

 7.1.1导入LOG4j依赖

<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

 7.1.2配置log4j.properties文件。放置在resource文件夹下的logj.properties

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/kuang.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}[%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

7.1.3在核心配置文件中配置

<settings>-->
    <setting name="logImpl" value="LOG4J"/>-->
</settings>-->

 7.1.4运行

MyBatis入门笔记整理

 

 8.注解开发

MyBatis入门笔记整理

8.1在接口上标上注解

 

package com.kuang.dao;

import com.kuang.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;

public interface UserMapper {
    @Select("select `id`,`name`,`pwd` from user")
    List<User> getUser();
    //有多个参数时一定要加上@Param()
    @Select("select * from user where id=#{id}")
    User getUserById(@Param("id") int id);

    @Insert("insert into user(`id`,`name`,`pwd`) values(#{id},#{name},#{pwd})")
    int addUser(User user);

    @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
    int updateUser(User user);

    @Delete("delete from user where id=#{id}")
    int deleteUser(@Param("id") int id);
}

8.2在核心配置文件中注册接口

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

8.3测试

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

import java.util.List;

public class UserMapperTest {

    @Test
    public void getUserTest(){
        SqlSession sqlSession= MybatisUtils.getSqlSession();
        //使用了反射技术
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getUser();
        System.out.println(user);
        sqlSession.close();
    }

    @Test
    public void getUserByIdTest(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        SqlSession sqlSession2=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
        System.out.println("================");
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User userById2 = mapper2.getUserById(1);
        System.out.println(userById2);
        System.out.println(userById==userById2);
        System.out.println(sqlSession==sqlSession2);
        sqlSession.close();
        sqlSession2.close();

    }

    @Test
    public void addUserTest(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.addUser(new User(4,"张飞","zhangfei"));
        sqlSession.close();
    }

    @Test
    public void updateUserTest(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.updateUser(new User(4,"张飞","zf1234"));
        sqlSession.close();
    }

    @Test
    public void deleteUserTest(){
        SqlSession sqlSession=MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(4);
        sqlSession.close();
    }
}

8.4注意点

MyBatis入门笔记整理

需要设置事务的自动提交。在utils工具类中修改如下:

    public static SqlSession getSqlSession(){
        //设置自动提交
        return sqlSessionFactory.openSession(true);
    }

 #{}和${}的区别:

#{}:会做参数类型解析,如果传入的是String类型,设置参数时会自动加上引号“”,可以防止sql注入问题。

${}: 不会做参数类型解析,仅仅是字符串的拼接,存在sql注入问题。但模糊查询只能用${}

 

9.一对多、多对一查询 

MyBatis入门笔记整理 

关联association用于多对一,比如学生对老师

集合collection用于一对多,比如老师对学生

 

 9.1创建学生和老师表


CREATE TABLE teacher(
id int(10) Not null,
name VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (id)
)ENGINE=INNODB DEFAULT CHARSET=utf8
 
INSERT INTO teacher(id,name) 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(id,name,tid) VALUES (1,'小明',1);
INSERT INTO student(id,name,tid) VALUES (2,'小红',1);
INSERT INTO student(id,name,tid) VALUES (3,'小张',1);
INSERT INTO student(id,name,tid) VALUES (4,'小李',1);

9.2多对一处理 (多个学生对应一个老师)

9.2.1问题提出

查询所有的学生信息以及学生对应的老师信息

9.2.2解决方式

 方式一:子查询

MyBatis入门笔记整理

    <select id="getStudent" resultMap="StudentTeacher">
        select * from mybatis.student;
    </select>
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    <select id="getTeacher" resultType="Teacher">
        select * from mybatis.teacher where id=#{tid}
    </select>

 方式二:联表查询

MyBatis入门笔记整理

    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from mybatis.student s,mybatis.teacher t
        where s.tid=t.id;
    </select>

    <resultMap id="StudentTeacher2" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>

    </resultMap>

总结:

  • 多对一处理:使用association 
  • 子查询(嵌套查询)和联表查询

 9.3一对多处理(一个老师对应多个学生)

9.3.1问题提出

查询老师以及他所教的学生(集合)

9.3.2解决方式

方式一:子查询

    <select id="getTeacher2" resultMap="TeacherStudent2">
        select *
        from mybatis.teacher t
        where id=#{tid}
    </select>

    <resultMap id="TeacherStudent2" type="Teacher">
        <collection property="students" javaType="ArrayList" ofType="Student"
                    select="getTeacherOfStudent" column="id"/>
    </resultMap>
    <select id="getTeacherOfStudent" resultType="Student">
        select * from mybatis.student where tid=#{tid};
    </select>

 方式二:联表查询

    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from mybatis.teacher t,mybatis.student s
        where t.id=s.tid and t.id=#{tid};
    </select>
    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>

总结:

  • 一对多问题:使用collection
  •  javaType:用来指定实体类中属性的类型。一般都是List
  • ofType: 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型!

10.动态SQL(重点) 

动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

简而言之就是动态的添加条件,如if,where等

 10.1 if用法

MyBatis入门笔记整理

如果传入的title不是空,则添加筛选条件:title = #{title}

如果传入的author不是空,则添加筛选条件:author = #{author}

注意:一般会加上where 1=1是为了当所有if子句都不满足时,sql语句能够正常运行而不会出现select * from table  where的错误 

10.2 choose(when、otherwise)的用法

这个类似于java语法中的switch,从上到下依次判断是否匹配,只会找出满足的一个条件。若都不满足,执行otherwise 

 MyBatis入门笔记整理

< where></where>标签:where标签会自动去除第一个子句的AND/OR。从而避免了AND/OR的多余。

10.3 trim(where、set)的用法

前面所述的<where>标签正是trim标签的子功能之一。同理<set>标签也是

10.3.1问题提出

考虑如下SQL

<select id="findActiveBlogLike"
     resultType="Blog">
  SELECT * FROM BLOG
  WHERE
  <if test="state != null">
    state = #{state}
  </if>
  <if test="title != null">
    AND title like #{title}
  </if>
  <if test="author != null and author.name != null">
    AND author_name like #{author.name}
  </if>
</select>

如果没有匹配的条件会怎么样?最终这条SQL会变成这样 :

SELECT * FROM BLOG  WHERE

这会导致查询失败!

如果匹配的只是第二个条件又会怎样?这条 SQL 会是这样:

SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’

 这个查询也会失败!

10.3.2 问题解决

trim(where、set)的标签出现正是为了解决这一问题

where等价于: 

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

set等价于:

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

prefixOverrides 属性会忽略通过管道符分隔的文本序列(注意此例中的空格是必要的)。上述例子会移除所有 prefixOverrides 属性中指定的内容,并且插入 prefix 属性中指定的内容。

prefixOverrides和suffixOverrides会自动选择该元素是否该删去:

例如where后面第一个子句的 AND/OR必须删去,set后第一个子句的“,”必须删去。

 

10.4 foreach的用法 

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  WHERE ID in
  <foreach item="item" index="index" collection="list"
      open="(" separator="," close=")">
        #{item}
  </foreach>
</select>

 举个例子说明:如要查询Select * from student where id in (1,2)?

MyBatis入门笔记整理 

MyBatis入门笔记整理

 

11.缓存机制

11.1简介

MyBatis入门笔记整理

 

 11.2mybatis缓存

MyBatis入门笔记整理

11.2.1一级缓存

MyBatis入门笔记整理 11.2.2二级缓存

MyBatis入门笔记整理

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中;
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中!

 

11.3缓存原理

MyBatis入门笔记整理 参考整理自狂神mybatis视频中的笔记

上一篇:mybatis中 #{}和${}的区别


下一篇:Spring Boot2篇 - 八、Spring Boot 整合Mybatis