MyBatis学习

Mybatis-9.28


环境:

  • JDK1.8
  • Mysql5.7
  • maven3.6.1
  • IDEA

回顾(必须掌握的知识):

  • JDBC
  • Mysql
  • Java基础(封装,继承等
  • Maven
  • Junit

SSM框架:配置文件的。 学习最好的方式:看官网文档

Mybatis文档:https://mybatis.org/mybatis-3/


1.简介


1.1 什么是Mybatis

# pic_center

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis
  • 2013年11月迁移到Github








注:6之前的在印象笔记



6. 日志

6.1 日志工厂

如果一个数据库操作出现了异常,我们需要排错,日志是最好的助手!
在这里插入图片描述

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

在Mybatis中具体使用哪个日志,在核心配置文件的setting中设定!

STDOUT_LOGGING标准日志输出

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

正确的效果:
在这里插入图片描述
错误时:
在这里插入图片描述

6.2 LOG4J

什么是LOG4J ?(建议百度)

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
  1. 先导入LOG4J 的依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  1. 在resources里创建log4j.properties(log4j的配置文件)
#将等级为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/Jiang.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
  1. 配置为log4j为日志的实现
 <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
  1. log4j的使用,直接运行刚才的查询
    在这里插入图片描述
    简单使用

    1. 在要使用log4j的类中,导入包: import org.apache.log4j.Logger;
    2. 日志对象,参数为当前类的class(就在类中定义)
    static Logger logger =  Logger.getLogger(UserDaoTest.class);
    
    1. 日志级别
       		logger.info("info:进入了testlog4j");
            logger.debug("deug:进入了testlog4j");
            logger.error("error:进入了testlog4j");
    
    1. 在测试类里面是这样的:
    package com.jiang.dao;
    
    import com.jiang.pojo.User;
    import com.jiang.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    import org.junit.Test;
    import org.apache.log4j.Logger;
    import org.junit.validator.PublicClassValidator;
    
    public class UserDaoTest {
    
        static Logger logger =  Logger.getLogger(UserDaoTest.class);
    
        @Test
        public void getUserLike(){
            SqlSession sqlSession = MybatisUtils.getSQlSession();
            logger.info("info:进入了getUserLike");
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            User user = mapper.getUserById(1);
            System.out.println(user);
    
            sqlSession.close();
        }
    
        @Test
        public void testlog4j(){
            logger.info("info:进入了testlog4j");
            logger.debug("deug:进入了testlog4j");
            logger.error("error:进入了testlog4j");
    
        }
    }
    

    后来:
    在这里插入图片描述

7.分页

使用Mybatis实现分页

7.1 使用Limit进行分页

  1. 接口
 //分页
    List<User> getUserByLimit(Map<String,Integer> map);
  1. Mapper.xml
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select * from mybatis.user limit #{startIndex},#{PageSize}
    </select>
  1. 测试
 @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);

        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("startIndex",1);
        map.put("PageSize",3);

        List<User> userList = mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.2 RowBounds分页(了解即可)

不再使用SQL使用分类

  1. 接口
//分页2
    List<User> getUserByRowBoounds();
  1. mapper.xml
<select id="getUserByRowBoounds" resultMap="UserMap">
        select * from mybatis.user
</select>
  1. 测试
//分页2
    @Test
    public void getUserByRowBoounds(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();

        //RoeBounds实现
        RowBounds rowBounds = new RowBounds(1, 3);

        //通过java代码实现分页
        List<User> userList = sqlSession.selectList("com.jiang.dao.UserMapper.getUserByRowBoounds",null,rowBounds);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

7.3分页插件

了解即可,若要使用,百度mybatis pagehelper,看文档

文档链接:https://pagehelper.github.io/
在这里插入图片描述

8. 使用注解开发

8.1 关于注解

对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。比如,上面的 XML 示例可以被替换成如下的配置:

package org.mybatis.example;
public interface BlogMapper {
  @Select("SELECT * FROM blog WHERE id = #{id}")
  Blog selectBlog(int id);
}

使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。

8.2 使用注解开发

  1. 注解在接口上实现
@Select("select * from user")
    List<User> getUser();
  1. 需要在核心配置文件中绑定接口!与之前的有所不同注意区分
<!--    绑定接口-->
    <mappers>
        <mapper class="com.jiang.dao.UserMapper"/>
    </mappers>
  1. 测试
 @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getUser();
        for (User user1 : user) {
            System.out.println(user1);
        }
        sqlSession.close();
    }

本质:反射机制实现
底层:动态代理!
最好搞懂mybatis的执行原理(看源码,debug)

8.3

我们可以在工具类创建的时候实现自动提交事务!

 public static SqlSession getSQlSession(){
        return sqlSessionFactory.openSession(true);
    }

编写接口,增加注解

package com.jiang.dao;


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

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

public interface UserMapper {

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

    /*方法存在多个参数,所有参数前面必须加上@Param("id")这样的注解,例如:
     User getUserById(@Param("id") int id,@Param("name")String name);}
     */
    @Select("select * from user where id = #{id}")
    User getUserById(@Param("id") int id);

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

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

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

测试类
【注意:我们必须要将接口注册绑定到核心配置文件中!!】

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

import java.util.List;

public class UserMapperTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> user = mapper.getUser();
        for (User user1 : user) {
            System.out.println(user1);
        }


        sqlSession.close();
    }

    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
        sqlSession.close();
    }


    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int user = mapper.addUser(new User(9, "姣姣", "1112"));
        //因为在工具类的时候定义了提交为true,所以这里之后不再设置提交commit!
        sqlSession.close();
    }


    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
       mapper.updateUser(new User(5,"TAI","99"));
        //因为在工具类的时候定义了提交为true,所以这里之后不再设置提交commit!
        sqlSession.close();
    }


    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        //底层主要应用反射
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        mapper.deleteUser(9);
        //因为在工具类的时候定义了提交为true,所以这里之后不再设置提交commit!
        sqlSession.close();
    }
}

关于@Param()注解

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

#{} / ${} 区别
不懂请自行百度

9. Lombok

Lombok项目是一个Java库,它会自动插入您的编辑器和构建工具中,从而使您的Java更加生动有趣。
永远不要再写另一个getter或equals方法,带有一个注释的您的类有一个功能全面的生成器,自动化您的日志记录变量等等。

使用步骤:

  1. 在idea中安装Lombok的插件
    在这里插入图片描述

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

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

  1. 在实体类上加注解
@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
@val
@var
experimental @var
@UtilityClass

@Data:无参构造,get、set、toString、hashcode、equals
@AllArgsConstructor:有参构造
@NoArgsConstructor:无参构造

10. 多对一处理(mybatis-06)

  • 比如多个学生,对应一个老师
  • 学生这边:多个学生关联一个老师【多对一】
  • 来时这边:集合,一个老师有很多学生【一对多】

10.1 设计SQL:

在这里插入图片描述
在这里插入图片描述

10.2 创建相应的实体类

老师:Teacher

package com.jiang.pojo;

import lombok.Data;

@Data    //有参
public class Teacher {
    private int id;
    private String name;
}

学生:Student

package com.jiang.pojo;

import lombok.Data;

@Data  //有参
public class Student {
    private int id;
    private String name;

    //学生需要关联一个老师!
    private Teacher teacher;
}

10.3 创建实体类相应的接口

老师:TeacherMapper

package com.jiang.dao;

public class TeacherMapper {
	
	@Select("select * from teacher where id = #{tid}")
    Teacher getTeacherById(@Param("tid") int id);
    
}

学生:StudentMapper

package com.jiang.dao;

public interface StudentMapper {
}

10.4 创建接口对应的xml文件

如果Mapper较多,建议将xml文件统一放在resources(新建包com.jiang.dao)里面

老师:TeacherMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jiang.dao.TeacherMapper">

</mapper>

学生:StudentMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jiang.dao.StudentMapper">

</mapper>

resutType里面写的是返回的类型

  1. 如果核心配置文件有给包起别名,那么就写别名
  2. 第一步没有就写全路径

然后在核心配置文件中注册Mappers接口/文件

	<mappers>
        <mapper class="com.jiang.dao.TeacherMapper"/>
        <mapper class="com.jiang.dao.StudentMapper"/>
    </mappers>

这里写的地址是class文件的路径
如果用的是resource,写的是 /

10.5 测试环境搭建是否成功

import com.jiang.dao.TeacherMapper;
import com.jiang.pojo.Teacher;
import com.jiang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class MyTest {

    @Test
    public void getTeacherById(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacherById(1);
        System.out.println(teacher);
        sqlSession.close();
    }
}

10.6 按照查询嵌套处理

10.6.1 在StudentMapper中添加方法

//查询所有的学生信息,以及对应的老师的信息
    public List<Student> getStudent();

10.6.2 StudentMapper.xml查询语句(子查询)

 <!--
        思路:
            1.查询所有的学生信息,结果返回在Map里面
            2.根据查询出来的学生的tid,寻找对应的老师  子查询
        -->
    <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    </select>

    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <!--复杂的属性我们需要单个处理
            对象:association   多对一
            集合:collection    一对多
        -->
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacherById"/>

    </resultMap>

    <select id="getTeacherById" resultType="Teacher">
        select * from teacher where id = #{tid}
    </select>

10.6.3 测试嵌套查询

 @Test
    public void getStudent(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.getStudent();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }

查询结果
在这里插入图片描述

10.7 按照结果嵌套处理

10.7.1 在StudentMapper中添加方法

public List<Student> getStudent2();

10.7.2 StudentMapper.xml查询语句(联表查询)

 <!--按照结果嵌套处理-->
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname
        from student s,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="name" column="tname"/>
        </association>
    </resultMap>

10.7.3 测试嵌套查询

 @Test
    public void getStudent2(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.getStudent2();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }

11. 一对多处理(mybatis-07)

比如:一个老师拥有多个学生
对于来时而言,就是一对多的关系!

11.1 环境搭建(和10一样)

  1. 依赖

  2. 配置文件

  3. 赋值java文件夹下的包

  4. 创建包并移动成这样
    在这里插入图片描述

  5. 清理Mapper/test文件方便工作

  6. 改变实体类属性

    StudentMapper:

    package com.jiang.pojo;
    
    import lombok.Data;
    
    @Data  //有参
    public class Student {
        private int id;
        private String name;
        private int tid;
    }
    

    TeacherMapper:

    package com.jiang.pojo;
    
    import lombok.Data;
    
    import java.util.List;
    
    @Data    //有参
    public class Teacher {
        private int id;
        private String name;
        
        //一个老师拥有多个学生
        private List<Student> students;
    }
    
  7. 接口方法

    //获取老师
        List<Teacher> getTeacher();
    
    
  8. xml实现

    	<select id="getTeacher" resultType="Teacher">
            select * from teacher
        </select>
    
  9. test

      @Test
        public void getTeacher(){
            SqlSession sqlSession = MybatisUtils.getSQlSession();
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> teacher = mapper.getTeacher();
            for (Teacher teacher1 : teacher) {
                System.out.println(teacher1);
            }
            sqlSession.close();
        }
    

    整体环境搭建测试完毕
    接下来实现一对多

11.2 按结果嵌套查询

11.2.1 TeacherStudent添加方法

 //获取指定老师下的所有学生及老师的信息
    Teacher getTeacher2(@Param("tid") int id);

11.2.2 TeacherStudent.xml写查询

 <!--按结果嵌套查询-->
    <select id="getTeacher2" resultMap="TeacherStudent">
        select s.id sid,s.name sname, t.name tname,t.id tid
        from student s,teacher t
        where s.tid = t.id and t.id = #{tid}
    </select>

    <resultMap id="TeacherStudent" type="Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <!--
        复杂的属性,我们需要单独处理  javaType="" 制定属性的类型!
        集合中的泛型信息,我们使用ofType获取
        -->
        <collection property="students" ofType="Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

11.2.3 测试方法

@Test
    public void getTeacher2(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacherList = mapper.getTeacher2(1);
        System.out.println(teacherList);
        sqlSession.close();
    }

11.3 按照查询嵌套处理(子查询)

11.3.1 TeacherStudent添加方法

Teacher getTeacher3(@Param("tid") int id);

11.3.2 TeacherStudent.xml写查询

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

11.3.3 测试方法

 @Test
    public void getTeacher2(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher3(1);
        System.out.println(teacher);
        sqlSession.close();
    }

小结

1. 关联-association 【多对一】
2. 结合 -collection 【一对多】
3. javaType   &   ofType
		1.javaType-->用来指定实体类中属性的类型 (如:List<Student>,指的是List)
		2.1ofaType-->用指定映射到List或者集合中的pojo类型,泛型中的约束类型 (如:List<Student>,指的是List)

12. 动态SQL

根据不同的条件生成不用的SQL语句

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

12.1 搭建环境(mybatis-08)

数据库:
在这里插入图片描述
创建一个基础工程:

  1. 导包(比如Lombok,实体类中要用@Data)

  2. 编写配置文件和utils

  3. 编写实体类

    package com.jiang.pojo;
    
    import lombok.Data;
    
    import java.util.Date;
    
    @Data
    public class Blog {
        private int id;
        private String name;
        private String author;
        private Date create_time;
        private int vires;
    }
    
  4. 编写实体类对应Mapper接口和Mapper.xml文件

  5. 注意修改好相关配置的路径(注册Mapper、namespace、别名等)

解决数据库字段与实体类属性名不一致问题

  • 在核心配置文件的setting中添加:
 <setting name="mapUnderscoreToCamelCase" value="true"/>

12.2 添加工具类:IDutils.java

  • 随机生成不重复的id序列
package com.jiang.utils;

import org.junit.Test;

import java.util.UUID;

@SuppressWarnings("all")
public class IDutils {
    public static String getId(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }

    @Test
    public void test(){
        System.out.println(IDutils.getId());
    }
}

12.3 插入博客数据

12.3.1 接口写方法

 //插入数据
    int addBlog(Blog blog);

12.3.2 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">
<!--configuration 核心配置文件-->
<mapper namespace="com.jiang.dao.BlogMapper">
    <insert id="addBlog" parameterType="blog">
        insert into blog(id,title,author,create_time,views)
        values (#{id},#{title},#{author},#{createTime},#{views})
    </insert>
</mapper>

12.3.3 测试插入

import com.jiang.dao.BlogMapper;
import com.jiang.pojo.Blog;
import com.jiang.utils.IDutils;
import com.jiang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;

public class MyTest {
    @Test
    public void addInitBlog(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        Blog blog = new Blog();
        blog.setId(IDutils.getId());
        blog.setTitle("Mybatis如此简单");
        blog.setAuthor("狂神说");
        blog.setCreateTime(new Date());
        blog.setViews(9999);

        mapper.addBlog(blog);

        blog.setId(IDutils.getId());
        blog.setTitle("Java如此简单");
        mapper.addBlog(blog);

        blog.setId(IDutils.getId());
        blog.setTitle("Spring如此简单");
        mapper.addBlog(blog);

        blog.setId(IDutils.getId());
        blog.setTitle("微服务如此简单");
        mapper.addBlog(blog);

        sqlSession.close();
    }
}

IF

接口方法

 	//查询博客
    List<Blog> queryBlogIF(Map map);

XML

	<select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </where>
    </select>

测试

 @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();

        //添加则查出限定条件的信息
        map.put("title","Java如此简单");
        map.put("author","狂神说");

        List<Blog> blogs = mapper.queryBlogIF(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

choose (when, otherwise)

  • 表示至选择when标签中的一个条件

接口方法

List<Blog> queryBlogChoose(Map map);

XML

 <select id="queryBlogChoose" parameterType="map" resultType="blog">
        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 queryBlogChoose(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();
        //map.put("title","Java如此简单");
        map.put("author","狂神说");
        map.put("views",9999);

        List<Blog> blogs = mapper.queryBlogChoose(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

trim (where,set)

  • trim的用法可以查看官方代码

接口方法

	//更新博客
    int updateBlog(Map map);

XML

<update id="updateBlog" parameterType="map">
        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 updateBlog(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();
        //map.put("title","Java如此简单2");
        map.put("author","狂神说2");
        map.put("id","412e4f22842f46a7b5f507989000e298");
        //map.put("views",9999);

        int i = mapper.updateBlog(map);
        if (i != 0){
            System.out.println("OK!");
        }
        sqlSession.close();
    }

foreach

select * from blog where 1=1 and (id = 1 or id = 2 or id = 3)

在这里插入图片描述

接口方法

在这里插入图片描述

	//查询第1、2、3号blog
    List<Blog> queryBlogForeach(Map map);

XMl

<!--
    select * from blog where 1=1 and (id = 1 or id = 2 or id = 3)
    其实本质就是用这些方法拼凑这些语句出来,但是是动态的

    传递一个万能map,这个map存在一个集合
    -->
    <select id="queryBlogForeach" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                id = #{id}
            </foreach>
        </where>
    </select>

测试

 @Test
    public void queryBlogForeach(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);

        HashMap map = new HashMap();
        ArrayList<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        map.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForeach(map);

        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

SQL片段

把一部分代码提取出来方便复用
1. 使用sql标签抽取公共的部分
2. 在需要使用的地方使用include标签引用即可

<sql id="if-title-author">
        <if test="title != null">
            and title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </sql>
    
    <select id="queryBlogIF" parameterType="map" resultType="blog">
        select * from blog
        <where>
           <include refid="if-title-author"></include>
        </where>
    </select>

注:

  • 最好基于单表来定义SQL片段
  • 不要存在where标签

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去拼接组合就可以了

13. 缓存

查询--->连接数据库--->耗资源

	解决:一次查询得结果,存在一个可以直接取到的地方!-->内存

再次查询相同数据的时候,直接走缓存,就不用走数据库了
  • 可以减少和数据库交互次数,减少系统开销,提高系统效率
  • 用在:经常查询并且不经常改变的数据
  • 只有两级缓存:
    1. 一级缓存默认开启(SqlSession级别的,本地缓存)
    2. 二级缓存需要手动开启和配置,基于namespace级别的缓存
    3. Mybatis定义了Cache接口,可以通过实现Cache接口来定义二级缓存

一级缓存

  1. 搭建环境
  2. 开启日志!
  3. 测试在一个Session中查询两次相同的记录
@Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);

        System.out.println("----------------------------------------------------");

        User user2 = mapper.queryUserById(1);
        System.out.println(user2);

        System.out.println(user==user2);
        sqlSession.close();

    }
  1. 查看日志输出
    在这里插入图片描述

缓存失效:

  1. 查询不同的数据

  2. 增删改操作,可能会改变原来的数据,所以必定会刷新缓存

  3. 查询不同的Mapper.xml

  4. 手动清理

     sqlSession.clearCache();
    

以上好像是一级缓存

二级缓存

  1. 开启全局缓存(核心配置文件里面的Setting)

    <!--显示的开启全局缓存-->
    <setting name="cacheEnabled" value="true"/>
    
  2. 在Mapper.xml中添加开启缓存

     <!--在当前Mapper.xml中使用二级缓存-->
        <cache/>
    

    在这里插入图片描述
    也可以在查询标签里面自定义开关在这里插入图片描述

    也可以自定义参数:

     <!--在当前Mapper.xml中使用二级缓存-->
        <cache eviction="FIFO" 
               flushInterval="60000" 
               size="512" 
               readOnly="true"
               />
    
  3. 测试

 @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSQlSession();
        SqlSession sqlSession2 = MybatisUtils.getSQlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        System.out.println(user);
        sqlSession.close();

        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        User user2 = mapper2.queryUserById(1);
        System.out.println(user2);

        System.out.println(user==user2);
        
        sqlSession2.close();
    }

问题:

当只用了< cache />出现了

  1. 我们需要将实体类序列化,否则就会报错

    Error serializing object.  Cause: java.io.NotSerializableException: com.jiang.pojo.User
    

    解决:
    在这里插入图片描述

小结

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据都会先放在以及缓存中
  • 只有当会话提交,或者关闭的时候,才回提交到二级缓存中
    在这里插入图片描述

自定义缓存

Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存

要在程序中使用ehcache,先要导包!

<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
 <!--自定义缓存,使用外部包 -->
     <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

在resources创建ehcache.xml自定义缓存

<?xml version="1.0" encoding="UTF-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    
    <diskStore path="./tmpdir/Tmp_EhCache"/>
    
    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>
        
    <cache 
            name="Cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
</ehcache>

在这里插入图片描述
在这里插入图片描述
Redis数据库来做缓存!??????

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值