Mybatis完整学习笔记!

Mybatis

1、简介

在这里插入图片描述

1.1、简介

1.简介

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射。
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

2.如何获得Mybatis

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.2</version>
</dependency>

1.2、持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和顺势状态转化的过程
  • 内存:断电即失
  • 数据库、IO文件持久化

为什么要持久化?

  • 有一些对象是不能丢失的
  • 内存太贵

1.3、持久层

概念:完成持久化工作的代码块,层界限十分明显

2、第一个mybatis程序

思路:搭建环境–>导入Mybatis–>编写代码–>测试

2.1、搭建环境

1.搭建数据库环境:创建数据库 数据表

CREATE DATABASE `Mybatis`;
USE `Mybatis`;

CREATE TABLE `user`(
	`id` INT(11) PRIMARY KEY,
	`name` VARCHAR(20) NOT NULL,
	`password` VARCHAR(20) DEFAULT NULL 

)ENGINE = INNODB DEFAULT CHARSET = utf8;

INSERT INTO `user` (`id`,`name`,`password`) VALUES
(1,"zhangsan","123"),
(2,"李四","2312312"),
(3,"王五","23124")

2.新建一个普通的maven项目,删除src目录 这样就可以把这个maven当成一个父工程 ,并在父工程导入依赖

<dependencies>
    <!-- mysql驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.46</version>
    </dependency>
    <!-- Mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <!-- junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

2.2、创建一个子模块

好处:不用每次新建一个模块的重新导依赖了

1.编写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=false&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 每一个Mapper.xml都需要在核心配置文件中注册-->
    <mappers>
        <mapper resource="com/morant/mybatis/Mapper/UserMapper.xml"/>
    </mappers>
</configuration>

2.编写Mybatis工具类

//sqlSessionFactory-->sqlsession
public class MybatisUtils {
    public static SqlSessionFactory sqlSessionFactory;
    static{
        try {
            //使用Mybatis第一步:获取sqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //既然有了sqlSessionFactory对象,我们就可以从中获取SqlSession的实例了
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2.3、编写代码

  • 实体类
package com.morant.mybatis.entity;

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

    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 getPassword() {
        return password;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
  • Mapper接口
public interface UserMapper {
    public List<User> find();
}
  • 实现接口配置文件
<?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.morant.mybatis.Mapper.UserMapper">
    <select id="find" resultType="com.morant.mybatis.entity.User">
        select * from user
    </select>
</mapper>

注意:常见错误

1、org.apache.ibatis.binding.BindingException: Type interface com.Mybatis.Mapper.UserMapper is not known to the MapperRegistry(错误原因:未注册Mapper.xml,每一个Mapper.xml都需要在核心配置文件中注册)

解决办法:

<!-- 在核心配置文件Mybatis-config.xml中配置-->
<mappers>
    <mapper resource="com/Mybatis/Mapper/UserMapper.xml"/>
</mappers>

2、Caused by: java.io.IOException: Could not find resource com/morant/Mapper/UserMapper.xml(错误原因:Maven本身的原因,我们写的配置文件无法被导出)

<!--在build中配置resources,来防止我们资源导出失败的问题--><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>

2.4 测试

public class UserMapperTest {    @Test    public void a(){        SqlSession sqlSession = MybatisUtils.getSqlSession();        UserMapper mapper = sqlSession.getMapper(UserMapper.class);        List<User> users = mapper.find();        for (User user : users) {            System.out.println(user);        }        sqlSession.close();    }}

3、CURD(增删改查需要提交事务)

1、select

  • id:对应的namespace中的方法名;
  • resultType:sql语句执行的返回值 Class、基本类型
  • parameterType:参数类型
  • 案例:查找一个用户
<select id="findid" resultType="com.morant.mybatis.entity.User" parameterType="int">    select * from user where id=#{id};</select>

2、insert

  • id:对应的namespace中的方法名;

  • parameterType:参数类型

  • 案例:插入一个用户

<insert id="insert" parameterType="com.morant.mybatis.entity.User">    <!--传入参数类型设置的是用户的实体类 因此可以直接写属性名字 作为参数-->    insert into user (id,name,password) values (#{id},#{name},#{password})</insert>

注意:测试的时候需要提交事务 sqlSession.commit();

3、update

  • id:对应的namespace中的方法名;

  • parameterType:参数类型

  • 案例:修改一个用户

<update id="update" parameterType="com.morant.mybatis.entity.User">    update user set name=#{name},password=#{password} where id=#{id}</update>

注意:测试的时候需要提交事务 sqlSession.commit();

4、delete

  • id:对应的namespace中的方法名;

  • parameterType:参数类型

  • 案例:删除一个用户

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

注意:测试的时候需要提交事务 sqlSession.commit();

5、万能的Map

假设,我们实体类或者数据库表中,字段或参数过多,我们应当考虑使用map传参,此时parameterType=“map”

  • Map传递参数,直接在sql中取出key即可!parameterType=“map”
  • 对象传递参数,直接在sql中取出对象的属性即可!parameterType=“Object”
  • 只有几个基本数据类型的情况下,可以直接在sql中取到!parameterType=“int”可以不写

多个参数用Map或者注解

4、配置解析

1、配置环境(environment)

MyBatis可以配置适应多种环境

不过要记住:尽管可以配置多个环境,但是每个SqlSessionFactory实例只能选择一个环境

MyBatis默认的事务管理器就是JDBC,连接池:POOLED

2、属性(properties)

我们可以通过properties属性来实现引用配置文件

这些属性都是可外部配置且可动态替换的,即可以在典型的java属性文件[db.properties]中配置,亦可以通过properties元素的子元素来传递

1.编写一个db.properties配置文件

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

2.在核心配置文件中引入
在这里插入图片描述
核心配置文件xml中规定的标签顺序

<!-- 引入配置文件 --><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>
  • 可以直接引入外部文件
  • 可以再其中增加一些属性
  • 如果两个文件有同一个字段,优先使用外部配置文件的

3、设置(setting)

4、类型别名(typeAliases)

  • 类型名是为Java类型设置一个短的名字
  • 存在的意义仅在于用来减少类完全限定名的冗余

1、给类起别名

<typeAliases>    <typeAlias type="com.morant.mybatis.entity.User" alias="User"></typeAlias></typeAliases>

2、扫描实体类的包,他默认别名就位这个包内所在类的类名,首写字母小写!(如果实体类上面有@Alias("")注解 则必须写注解名)

<typeAliases>    <package name="com.morant.mybatis.entity"/></typeAliases>

在实体类比较少的时候 建议使用第一种

实体类比较多的时候 推荐使用第二种

5、其他配置

6、映射器(Mapper)

MapperRegistry:注册绑定我们的mapper文件

方式一【推荐使用】

<mappers>    <mapper resource="com/morant/mybatis/Mapper/UserMapper.xml"/></mappers>

方式二:使用class的文件绑定注册

<mappers>    <class class="com/morant/mybatis/Mapper/UserMapper"/></mappers>

注意点:

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

方式三:使用扫描包进行绑定

<mappers>    <package name="com/morant/mybatis/Mapper"/></mappers>

注意点:

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

7、生命周期和作用域

5、ResultMap

1、发现问题

实体类属性:

private int id;
private String name;
private String secret;

数据库对应字段

在这里插入图片描述

实体类和数据库对应字段不一致的时候 执行select方法之后 secret为null

解决方法

  • 起别名
<select id="find" resultType="user">
    select id,name,password as secret from user
</select>
  • 采用结果集映射
<resultMap id="UserMapper" type="com.morant.mybatis.entity.User">
    <!-- 其中colum代表数据库中的字段 property代表实体类中的属性值-->
    <result column="id" property="id" />
    <result column="name" property="name" />
    <result column="password" property="secret" />
</resultMap>
<select id="find" resultMap="UserMapper">
    select * from user
</select>

2、结果集映射 ResultMap

数据库字段:id name password实体类属性:id name secret
<resultMap id="UserMapper" type="com.morant.mybatis.entity.User">    <!-- 其中colum代表数据库中的字段 property代表实体类中的属性值-->    <result column="id" property="id" />    <result column="name" property="name" />    <result column="password" property="secret" /></resultMap><select id="find" resultMap="UserMapper">    select * from user</select>
  • resultMap元素是Mybatis中最重要最强大的元素
  • ResultMap的设计思想是:对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句只需要描述他们的关系就行了
  • ResultMap最优秀的地方在于虽然你已经对他相当了解了,但是根本就不需要显示的用到他们

6、日志

6.1、日志工厂(STDOUT_LOGGING )

如果一个数据库的sql语句操作,出现了异常,我们需要排错,做好的帮手就是日志!

工厂日志的设置

在这里插入图片描述

name:

​ logImpl

value:

  • SLF4J
  • LOG4J 【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING 【掌握】
  • NO_LOGGING

在Mybatis中具体使用哪一个日志实现,在设置中设定,

STDOUT_LOGGING标准日志的配置

在核心配置文件mybatis-config.xml中配置日志工厂

<settings>    <setting name="logImpl" value="STDOUT_LOGGING"/></settings>

日志信息

在这里插入图片描述

6.2、LOG4J

概述:

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 我们也可以控制每一条日志的输出格式;
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。
  • 最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

1、先导包

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

2、创建log4j.properties配置文件

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码log4j.rootLogger=DEBUG,console,file#控制台输出的相关设置log4j.appender.console = org.apache.log4j.ConsoleAppenderlog4j.appender.console.Target = System.outlog4j.appender.console.Threshold=DEBUGlog4j.appender.console.layout = org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%c]-%m%n#文件输出的相关设置log4j.appender.file = org.apache.log4j.RollingFileAppenderlog4j.appender.file.File=./log/morant.loglog4j.appender.file.MaxFileSize=10mblog4j.appender.file.Threshold=DEBUGlog4j.appender.file.layout=org.apache.log4j.PatternLayoutlog4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n#日志输出级别log4j.logger.org.mybatis=DEBUGlog4j.logger.java.sql=DEBUGlog4j.logger.java.sql.Statement=DEBUGlog4j.logger.java.sql.ResultSet=DEBUGlog4j.logger.java.sql.PreparedStatement=DEBUG

3、在核心配置文件mybatis-config.xml中将log4j配置为日志的实现

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

4.Log4j的使用!直接运行

5、简单的使用

  • 要在Log4j的类中,导入包import org.apache.log4j.Logger;
  • 日志对象 参数为当前类的class
static Logger logger = Logger.getLogger(UserMapperTest.class);
  • 日志级别
logger.info("info:进入了testLog4j")logger.debug("debug:进入了testLog4j")logger.error("error:进入了testLog4j")

7、分页

1、使用Limit分页

语法:SELECT * from user limit startIndex,pageSize;SELECT * from user limit 3;#[0,3] 只写一个参数 从零开始到写的数字

使用Mybatis实现分页,核心Sql

1.接口

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

2.Mapper.xml

<select id="limit" parameterType="map" resultMap="UserMapper">
    select * from user limit #{startIndex},#{pageSize}
</select>

3.测试

@Test
public void b(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    HashMap<String, Integer> map = new HashMap<String, Integer>();
    map.put("startIndex",0);
    map.put("pageSize",2);
    List<User> limit = mapper.limit(map);
    for (User user : limit) {
        System.out.println(user);
    }
    sqlSession.close();
}

2、RowBounds分页

8、使用注解开发

本质:反射机制实现

底层:动态代理!

入门:

1.注解在接口上实现

public interface UserMapper {    @Select("select * from user")    public List<User> find();}

2.需要在核心配置文件中绑定接口

<mappers>    <mapper class="com.morant.mybatis.Mapper.UserMapper" /></mappers>

3.测试

@Testpublic void a(){    SqlSession sqlSession = MybatisUtils.getSqlSession();    UserMapper mapper = sqlSession.getMapper(UserMapper.class);    List<User> users = mapper.find();    for (User user : users) {        System.out.println(user);    }    sqlSession.close();}

CURD

我们可以在工具类中设置自动提交事务

public class MybatisUtils {    public static SqlSessionFactory sqlSessionFactory;    static{        try {            //使用Mybatis第一步:获取sqlSessionFactory对象            String resource = "mybatis-config.xml";            InputStream inputStream = Resources.getResourceAsStream(resource);            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);        } catch (IOException e) {            e.printStackTrace();        }    }    //既然有了sqlSessionFactory对象,我们就可以从中获取SqlSession的实例了    public static SqlSession getSqlSession(){        //设置自动提交事务        return sqlSessionFactory.openSession(true);    }}

8.1、编写注解 增加接口@selete

@selete

UserMapper(@Param中的变量名就是sql对查找的参数)

//根据id查询用户@Select("select * from user where id=#{id} and name=#{nname}")public User findid(@Param("id") int id,@Param("nname")String name);

测试

@Testpublic void b(){    SqlSession sqlSession = MybatisUtils.getSqlSession();    UserMapper mapper = sqlSession.getMapper(UserMapper.class);    User findid = mapper.findid(2,"李四");    System.out.println(findid);    sqlSession.close();}

8.2、编写注解 增加接口@Insert

@Insert

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

测试

@Testpublic void c(){    SqlSession sqlSession = MybatisUtils.getSqlSession();    UserMapper mapper = sqlSession.getMapper(UserMapper.class);    mapper.insert(new User(4,"第四个","123"));    sqlSession.close();}

8.3、编写注解 增加接口@Update

@Update

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

测试

@Testpublic void d(){    SqlSession sqlSession = MybatisUtils.getSqlSession();    UserMapper mapper = sqlSession.getMapper(UserMapper.class);    int one = mapper.update(1, "1", "one");    sqlSession.close();}

8.4、编写注解 增加接口@Delete

Delete

//删除用户
@Delete("delete from user where id = #{id}")
public int delete(@Param("id") int id);

测试

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

8.5、关于Param()注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话可以忽略,但是建议加上
  • 我们SQL中引用的就是Param()中设定的属性名

9、Lombok

使用步骤:

​ 1.在IDEA中安装Lombok插件!

​ 2.在项目中导入Lombok的jar包

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --><dependency>    <groupId>org.projectlombok</groupId>    <artifactId>lombok</artifactId>    <version>1.18.12</version>    <scope>provided</scope></dependency>

​ 3.在实体类上加注解即可!

@Getter and @Setter@FieldNameConstants@ToString@EqualsAndHashCode@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog@Data@Builder@SuperBuilder@Singular@Delegate@Value@Accessors@Wither@With@SneakyThrows

@Data:无参构造、get、set、toString、hashcod、equals

10、多对一处理

  • 多个学生,对应一个老师

  • 对于学生而言,关联…多个学生,关联一个老师【多对一】

  • 对于老师而言,集合…一个老师有很多学生【一对多】

1、环境搭建

  • 创建新的数据表Teacher、Student
#创建老师表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`);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GkwSTdqa-1629956787711)(C:\Users\mohai\AppData\Roaming\Typora\typora-user-images\image-20210824222359394.png)]

  • 导入Lombok的jar包
<dependencies>    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->    <dependency>        <groupId>org.projectlombok</groupId>        <artifactId>lombok</artifactId>        <version>1.18.12</version>    </dependency></dependencies>
  • 新建Teacher、Student实体类
@Data@AllArgsConstructor@NoArgsConstructorpublic class Student {    private int id;    private String name;    private int tid;}
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Teacher {
    private int id;
    private String name;
}
  • 新建TeacherMapper、StudentMapper接口
public interface StudentMapper {

}
public interface TeacherMapper {
    //通过ID查找老师
    @Select("select * from teacher where id = #{tid}")
    public Teacher findbyId(@Param("tid") int id);
}
  • 新建TeacherMapper.xml、StudentMapper.xml实现接口
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.morant.mybatis.Mapper.StudentMapper">

</mapper>
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.morant.mybatis.Mapper.TeacherMapper"></mapper>
  • 在核心配置文件中注册接口
<mappers>    <mapper class="com.morant.mybatis.Mapper.TeacherMapper" />    <mapper class="com.morant.mybatis.Mapper.StudentMapper" /></mappers>
  • 测试
public class TeacherMapperTest {    @Test    public void a(){        SqlSession sqlSession = MybatisUtils.getSqlSession();        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);        Teacher teacher = mapper.findbyId(1);        System.out.println(teacher);        sqlSession.close();    }}

2、多对一处理

方法一(类似子查询的方法),按照查询嵌套处理,写两个select语句

  • StudentMapper
//方法一:(子查询)查询所有学生public List<Student> findStudent();
  • StudentMapper.xml
<!-- 思路:    1.查询所有学生信息    2.根据查询出来的学生的tid,查找相应的老师--><select id="findStudent" resultMap="StudentTeacher">    select * from student</select><resultMap id="StudentTeacher" type="com.morant.mybatis.entity.Student">    <result property="id" column="id"/>    <result property="name" column="name"/>    <!-- 复杂的属性 我们需要单独处理,对象用association标签 集合用collection标签 -->    <association property="teacher" column="tid" javaType="com.morant.mybatis.entity.Teacher" select="findTeacher"/></resultMap><select id="findTeacher" resultType="com.morant.mybatis.entity.Teacher">    select * from teacher where id = #{tid}</select>

方法二(嵌套处理的思路),按照结果嵌套处理,一条查询语句

  • StudentMapper
//方法二:(连表查询)查询所有学生public  List<Student> findStudent2();
  • StudentMapper.xml
<!--思路二:按照嵌套处理 --><select id="findStudent2" resultMap="StudentTeacher2">    select s.id sid,s.name sname,s.tid tid,t.name tname    from student s,teacher t    where s.tid = t.id</select><resultMap id="StudentTeacher2" type="com.morant.mybatis.entity.Student">    <result property="id" column="sid"/>    <result property="name" column="sname"/>    <association property="teacher" javaType="com.morant.mybatis.entity.Teacher">        <!--相当于在这里嵌套查询 对Teacher属性做说明-->        <result property="name" column="tname"/>        <result property="id" column="tid"/>    </association></resultMap>

11、一对多处理

1、环境搭建(省略)

2、一对多查询

方法一(类似子查询的方法),按照查询嵌套处理,写两个select语句

  • StudentMapper
//子查询
    public Teacher findTStudent2(@Param("tid")int id);
  • StudentMapper.xml
<!-- 子查询 -->
    <select id="findTStudent2" resultMap="TStudent2">
        select * from teacher where id = #{tid}
    </select>
    <resultMap id="TStudent2" type="com.morant.mybatis.entity.Teacher">
        <!--
            1.JavaType 用来指定实体类中属性的类型
            2.ofType 用来指定映射到List或者集合中pojo类型,泛型中的约束类型
        -->
        <collection property="students" column="id" javaType="ArrayList" ofType="com.morant.mybatis.entity.Student" select="find"/>
    </resultMap>
    <select id="find" resultType="com.morant.mybatis.entity.Student">
        select * from student where tid=#{tid}
    </select>

方法二(嵌套处理的思路),按照结果嵌套处理,一条查询语句

  • StudentMapper
//嵌套查询    public Teacher findTStudent(@Param("tid")int id);
  • StudentMapper.xml
<!-- 嵌套查询 -->
    <select id="findTStudent" resultMap="TStudent">
        SELECT s.id sid,s.name sname,t.id tid,t.name tname
        from student s,teacher t
        where t.id=#{tid} and s.tid = t.id
    </select>
    <resultMap id="TStudent" type="com.morant.mybatis.entity.Teacher">
        <result column="tid" property="id"/>
        <result column="tname" property="name"/>
         <!--
           
			2.ofType 用来指定映射到List或者集合中pojo类型,泛型中的约束类型
        -->
        <collection property="students" ofType="com.morant.mybatis.entity.Student">
            <result property="id" column="sid"/>
            <result property="tid" column="tid"/>
            <result property="name" column="sname"/>
        </collection>
    </resultMap>

3、小结:

1.关联 -association【多对一】

2.集合 -collection 【一对多】

3.javaType & ofType

​ 1.JavaType 用来指定实体类中属性的类型

​ 2.ofType 用来指定映射到List或者集合中pojo类型,泛型中的约束类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题!

12、动态SQL

什么是动态SQL:动态SQL就是值根据不同的条件生成不同的SQL语句

1、IF标签

标签:如过if内的语句成立就追加

<select id="selectBlog" parameterType="map" resultType="com.morant.mybatis.entity.Blog">
    select * from blog where 1=1
    <if test="author != null">
        and author = #{author}
    </if>
    <if test="views != null">
        and views = #{views}
    </if>
</select>

2、where

标签:where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

select * from blog title = #{title} and author = #{author} and views = #{views}

3、choose、when、otherwise

标签:类似java中的switch、case、default

<select id="selectBlog" parameterType="map" resultType="com.morant.mybatis.entity.Blog">
    select * from blog
        <where>
            <choose>
                <when test="title != null">
                     title = #{title}
                </when>
                <when test="author != null">
                     title = #{title}
                </when>
                <otherwise>
                     views = #{views}
                </otherwise>
            </choose>
        </where>
</select>

4、set

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

<update id="updateAuthorIfNecessary">
  update Author
    <set>
      <if test="username != null">username=#{username},</if>
      <if test="password != null">password=#{password},</if>
      <if test="email != null">email=#{email},</if>
      <if test="bio != null">bio=#{bio}</if>
    </set>
  where id=#{id}
</update>

5、SQL片段

有时候,我们可能会将一些功能的片段部分抽取出来,方便复用

1.使用SQL标签抽取公共部分

<sql id="if-author-views"	>
	<if test="author != null">
        and author = #{author}
    </if>
    <if test="views != null">
        and views = #{views}
    </if>
</sql>

2.在需要引用的地方使用Include标签引用即可

<include refid="id-author-views"></include>

注意事项:

  • 最好基于单标定义Sql
  • 不要存在where标签

13、缓存

13.1:一级缓存

1.概念
  • 一级缓存也叫作本地缓存:Sqlsession
    • 与数据库同一次会话期间查询的的数据会放在本地缓存
    • 以后如果需要获取相同的数据,直接从缓存中拿,就没记要再去查询数据库
2.测试步骤:

​ 1.开启日志

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

​ 2.测试一次sqlSession

public void a(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user1 = mapper.findById(1);
    System.out.println(user1);
    System.out.println("===========================");
    User user2 = mapper.findById(1);
    System.out.println(user2);
    System.out.println(user1 == user2);
    sqlSession.close();
}

在这里插入图片描述

3.缓存失效的情况
  • 查询不同的东西
  • 增删改查操作,改变原来的数据,所有缓存会刷新
  • 查询不同的Mapper.xml
  • 手动清理缓存
sqlSession.clearCache();
4.小结:

一级缓存默认是开启的,只在一次SqlSession中有效,也就是从拿到连接到关闭连接这个区间!一级缓存就是一个Map

13.2:二级缓存

1.概念
  • 二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存
  • 工作机制
    • 一个会话查询一条语句,这个数据就会被放在当前会话的一级缓存中
    • 如果当前缓存关闭了,这个会话对应的一级缓存就没了;但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中
    • 新的会话查询信息,就可以从二会话中获取内容
    • 不同的mapper查出的数据会放在自己对应的缓存(map)中
2.测试步骤

1.开区全局缓存 并开启日志

<settings>
    <setting name="cacheEnabled" value="true"/>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

2.在要使用二级缓存的Mapper中开启

<cache/>

也可以自定义一些参数

3.测试

未序列化报错

在这里插入图片描述

解决办法 实现Serializable接口

public class User implements Serializable {
    private int id;
    private String name;
    private String password;
}
4.小结
  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在一级缓存中
  • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中

13.3:缓存原理

缓存顺序:

1.先看Mapper二级缓存有没有

2.再看一级SqlSession缓存中有没有

本文根据狂神说Mybatis教学制作笔记,教学视频地址
https://www.bilibili.com/video/BV1NE411Q7Nx?.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

MMorant

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

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

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

打赏作者

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

抵扣说明:

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

余额充值