学习Mybatis

1.Mybatis简介

  • 学习视频:https://www.bilibili.com/vide...
  • 持久化:就是将程序的数据在持久状态和瞬时状态转化的过程
  • 持久层:完成持久化工作的代码块,统称为Dao层
  • MyBatis:简化数据库连接和操作数据库的操作的半持久框架,是目前的主流
  • 官网:https://mybatis.org/mybatis-3...

2.第一个Mybatis项目

2.1.配置数据库

= 创建数据库,表,表数据

CREATE TABLE `user` (
        `id` int(20) NOT NULL AUTO_INCREMENT,#id不为0,自增
        `name` varchar(30) DEFAULT NULL,#name默认null
        `pwd` varchar(30) DEFAULT NULL,#pwd默认null
        PRIMARY KEY (`id`)#主键索引=id
)ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES(1,'狂神','123456');
INSERT INTO `user` VALUES(2,'张三','123456');
INSERT INTO `user` VALUES(3,'李四','123456');

2.2.搭建环境

  • 父工程导包


    
    mysql
    mysql-connector-java
    5.1.48


    
    org.mybatis
    mybatis
    3.5.2


    
    junit
    junit
    4.12
  • 子工程加载资源过滤器

防止后缀为properties和xml配置文件无法加载



    
        
            src/main/resources
            
                **/*.properties
                **/*.xml
            
            true
        
        
            src/main/java
            
                **/*.properties
                **/*.xml
            
            true
        
    
      
  • 配置resources /mybais-config.xml





    
    
        
            
            
            
                
                
                
                
            
        
    
    
    
        
    
  • 编写工厂工具类

    • spring整合mybatis后,这个操作再mybats-config.xml中配置
public class MyBatisUtil {
    /**
     * 提升sqlSessionFactory作用域,便于全局使用
     */
    private 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.Dao层

  • Pojo:User
  • Dao:接口;实现类变成了XXXMapper.xml文件
public interface UserDao {
    List getUserList();
}




    

2.4 测试

  • 资源过滤异常,见上面的子工程配置资源过滤器
  • mapper注册失败异常:在mybatis-config.xml配置

    
public class UserMapperTest {
    @Test
    public void getUserList() {
        //1 获取是sqlSession对象
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        //2 获取的是接口的.class,因为多态
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List userList = userMapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        //3 建议:最后关闭sqlSession
        sqlSession.close();
    }
}

3. CRUD

3.1 namespace=接口全类名相同


    

3.2 select

  • id:接口中的方法名
  • parameterType:返回结果
  • resultType:方法参数

3.3 insert/update/delete

  • 增删改需要添加事务,返回值只有int,不用添加resultType

    
    
    
        INSERT INTO mybatis.user(id,NAME,pwd) VALUES (#{id},#{name},#{pwd});
    
    
        update mybatis.user set name = #{name},pwd=#{pwd} where id=#{id};
    
    
        delete from mybatis.user where id=#{id}
    

3.4 常见错误

  • 增删改sql语句写错
# 增加需要values 
insert into mybatis.user(id,NAME,pwd) VALUES (#{id},#{name},#{pwd});
# 修改需要set
update mybatis.user set name = #{name},pwd=#{pwd} where id=#{id};
# 删除需要from
delete from mybatis.user where id=#{id} 
  • 出现bug,是从后往前看查看原因

3.5 万能map

  • 如果数据库字段太多,添加修改需要的bean太多,使用map来封装参数,
  • 好处一:避免多余代码
  • 好处二:跳过特定的Bean属性,可以随意命名key,保证value是字段的属性就行

3.6 模糊查询




4 配置解析

4.1 mybatis_config.xml

  • 在resource中创建mybatis_config.xml

4.2 mybatis中的配置属性

  • properties(属性)
  • settings(设置)
  • typeAliases(类型别名)
  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
  • environments(环境配置)
  • environment(环境变量)
  • transactionManager(事务管理器)
  • dataSource(数据源)
  • databaseIdProvider(数据库厂商标识)
  • mappers(映射器)

4.3 enviroments(环境)

  1. 事务管理器:transcationManager,默认“JDBC”
  2. 连接数据库:默认pooled

        
            
            
            
            
                
                
                
                
            
        

4.4 properties(属性)

  • db.properies
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=utf-8
username=root
password=123456

4.5 settings(设置)

settings配置 解释说明 默认状态
cacheEnabled(重要) 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 默认开启
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 默认关闭
mapUnderscoreToCamelCase(重要) 是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。 默认关闭
logImpl(最重要) 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J、LOG4J、STDOUT_LOGGING等,默认关闭

4.6 typeAliases(类型别名)

  • 作用:mapper.xml配置resultType时,简化书写

学习Mybatis_第1张图片



    
    
    

4.7 plugins(插件)

后期需要加深学习的两大插件,使Mybatis配置更加简单

  • Mybatis-Plus
  • MyBatis Generator Core

4.8 mappers(映射器)

  1. 在mybatis-config.xml中配置mapper映射器


  
  
  
  1. class和package绑定:接口和mapper配置文件必须同名,是否必须在同一个包下有待学习?


  
  
  



  

4.9 MyBatisUtil(参数作用域)

名称 解释说明
SqlSessionFactoryBuilder 一旦创建就不再需要它了,作用域是局部变量=静态代码块先加载
SqlSessionFactory 运行期间一直存在,作用域是应用作用域,使用单例模式或者静态单例模式。
SqlSession 连接到数据库的请求,线程不安全,用完后马上关闭;作用域是方法或者请求中,用完就关闭,关闭操作十分重要
public class MyBatisUtil {
    //0 提升第三步中sqlSessionFactory作用域
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //1 获取mybatis配置文件
            String resource = "mybatis-config.xml";
            //2 获取配置文件的输入流
            InputStream inputStream = Resources.getResourceAsStream(resource);
            //3 使用SqlSessionFactoryBuilder().build()创建sqlSessionFactory
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //4 通过getSqlSession获取session
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession(true);
    }
}

5 属性名和字段名不一致

5.1 更改User中的pwd->password

  • 模拟实现这个过程,数据库中是pwd,更改Pojo中的User属性为pwd,导致不一致
//查询结果:不一致的字段查询结果为null
User{id=1, name='狂神', password='null'}

5.2 解决办法

  • 更改pojo成员属性名 = 数据库字段名:使用起来太low,不推荐
  • 使用结果集映射=resultMap:哪个字段不一致,就使不一致的成员属性property映射到数据库的column

学习Mybatis_第2张图片





    
    
        
    
    
    

6 开启日志

6.1 日志工厂

  • 在setting中配置:name = logImpl 大小写和空格不能错
  • LOG4J:必须掌握,步骤:setting配置,导包,配置pro,测试时加载

    • setting配置,+导依赖包

       
             
       
       
      
          log4j
          log4j
          1.2.17
      
    • log4j.properties:需要时去网上找一份

      # log4j日志系统:通用配置
      # Define the root logger with appender file
      # log=D:\logs
      log4j.rootLogger = DEBUG, FILE, console
      # 输出到当前目录文件下的log包中
      log4j.appender.FILE=org.apache.log4j.FileAppender
      log4j.appender.FILE.File=./logs/log4j.log
      # Set the immediate flush to true (default)
      log4j.appender.FILE.ImmediateFlush=true
      # Set the threshold to debug mode
      log4j.appender.FILE.Threshold=debug
      # Set the threshold to debug mode
      # 设置日志信息追加
      log4j.appender.FILE.Append=true
      # Set the maximum file size before rollover
      # 30MB
      log4j.appender.FILE.MaxFileSize=5KB
      # Set the backup index
      log4j.appender.FILE.MaxBackupIndex=2
      # Define the layout for file appender
      log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
      log4j.appender.FILE.layout.conversionPattern=%m%n
      # 将日志输出到控制台
      log4j.appender.console=org.apache.log4j.ConsoleAppender
      log4j.appender.console.layout=org.apache.log4j.PatternLayout
      log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd HH:mm:ss}]-[%t]-[%F:%L]-[%p]-[%c]-%m%n
      #log4j.appender.console.layout.ConversionPattern=[%d{yyyy-MM-dd}]-[%t]-[%x]-[%-5p]-[%-10c:%m%n]
      log4j.appender.console.encoding=UTF-8
      
    • test中:static Logger logger = Logger.getLogger(UserMapperTest.class);

      public class UserMapperTest {
          //使用log4j
          static Logger logger = Logger.getLogger(UserMapperTest.class);
      
          @Test
          public void getUserById() {
              //1 获取是sqlSession对象
              SqlSession sqlSession = MyBatisUtil.getSqlSession();
              //2 获取方式一:getMapper
              UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
              User user = userMapper.getUserById(1);
              System.out.println(user);
              //3 建议:最后关闭sqlSession
              sqlSession.close();
          }
      }
  • STDOUT_LOGGING :掌握,不用导包,mybatis默认配置了,缺点就是只在控制台显示
 
       
        
 
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • SLF4J
  • NO_LOGGING

7 分页

7.1 limit

  • 第一个参数:startIndex=开始分页的下标 = (第几页 - 1 )* pageSize
  • 第二个参数:pageSize=分页中每页的大小
  • 只有一个参数:默认是从第一个元数到该index下标实现分页
select * from user limit startIndex,pageSize;# startIndex=(第几页-1)*pageSize
select * from user limit index;# 默认从第一个元素到第index个用户

7.2 实现分页

  • map和RowbBounds两者都可以实现分页:推荐使用map分页,因为默认key=#{key}
public interface UserMapper {
    /**
     * 根据id获取一个用户
     * @param id 指定
     * @return User
     */
    User getUserById(int id);

    /**
     * 通过map分页数据,推荐使用
     * @param map 常用
     * @return ListUser
     */
    List getLimitUser(Map map);

    /**
     * 了解,不推荐使用,通过RowBounds分页数据
     * @return ListUser
     */
    List getLimitUserByRowBounds();
}

        

    
    
    
    
    
    
    
    
public class UserMapperTest {    
    @Test
    public void getLimitUser() {
        UserMapper userMapper = MyBatisUtil.getSqlSession().getMapper(UserMapper.class);
        Map map = new HashMap<>();
        //mapper.xml会自动寻找map中的key=#{key}
        map.put("startIndex",0);
        map.put("pageSize",2);
        List limitUser = userMapper.getLimitUser(map);
        for (User user : limitUser) {
            System.out.println(user);
        }
    }
     @Test
    public void getLimitUserBrRowBounds() {
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        //老式的查询分页:使用RowBounds
        RowBounds rowBounds = new RowBounds(0, 2);
        //语法麻烦
        List usersList = sqlSession.selectList("com.ssl.dao.UserMapper.getLimitUserByRowBounds",0,rowBounds);
        for (User user : usersList) {
            System.out.println(user);
        }
    }
}

7.3 分页插件

  • 自学Mybatis PageHelper插件,公司需要就去网站自学

8 注解配置sql语句

8.1 mybaits-config.xml中配置映射器



    

8.2 缺点

  • 如果表中列名和成员属性名不一致,查出来就是null

8.3 注解的CRUD

  • 学习@param(非常重要)

    • 基本类型、String建议都加上,引用类型不用加
    • (uid)中的就是sql中的#{uid}
public interface UserMapper {
    /**
     * 使用注解开发,有局限性就是column 必须与 dao接口成员属性名一致,否知输出就是null,查不出来
     * 所以注解语句开发,便于使用简单场景
     */
    @Select("select * from user")
    List getUsers();

    /**
     * @param id=uid
     * @return User
     */
    @Select("select * from user where id = #{uid}")
    User getUserById(@Param("uid") int id);
}
  • 增删改自动提交事务
 public static SqlSession getSqlSession() {
        //不推荐使用,建议手动提交commit
        return sqlSessionFactory.openSession(true);
    }

9 Lombok

9.1 IDEA中安装Lombok插件

9.2 maven安装依赖


    org.projectlombok
    lombok
    1.18.12

9.3 @Data等注解

  • @Data:最常用,自动加上Setter Getter equals tostring,
  • @AllArgsConstructor:有参构造
  • @NoArgsConstructor:无参构造

9.4 缺点

  • 虽然可以混合使用,但多重的构造器的构造器不能重载
  • 公司用就用,不用就少用,因为改变了java源码的书写习惯,不利于推广

10 多对一

  • 导入Lombok插件和依赖,减少pojo代码
  • 新建实体类Student、Teacher和数据库表

    • Student中有一个字段tid使用外键约束,关联Teacher
CREATE TABLE `student` (
  `id` int(10) NOT NULL,
  `name` varchar(20) 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

CREATE TABLE `teacher` (
  `id` int(10) NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
  • 配置环境:pojo和mapper接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    //需要关联一个老师类
    private Teacher teacher;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}
public interface StudentMapper {
    //子查询
    List getStudents();
    //联表查询
    List getStudents1();
}

10.1:子查询=查询嵌套

  • mapper.xml

    • 以下对于理解非常重要
    • javaType=“teacher”配置了别名,大小写都可以,去pojo路径中中找Teacher,然后使用其成员属性tid

学习Mybatis_第3张图片




        
        
     

  • 测试
     @Test
    public void getStudents() {
        StudentMapper studentMapper = MyBatisUtil.getSqlSession().getMapper(StudentMapper.class);
        List students = studentMapper.getStudents();
        for (Student student : students) {
            System.out.println(student);
        }
        /*
            Student(id=1, name=小红, teacher=Teacher(id=1, name=秦老师))
         */
}

10.2:联表查询=结果嵌套

  • 使用多表查询,避免写多个sql
  • mapper.xml

学习Mybatis_第4张图片




    
    
    
        
    
  • 测试:与嵌套查询结果没变
 @Test
    public void getStudents1() {
        StudentMapper studentMapper = MyBatisUtil.getSqlSession().getMapper(StudentMapper.class);
        List students = studentMapper.getStudents1();
        for (Student student : students) {
            System.out.println(student);
        }
        /*
            Student(id=1, name=小红, teacher=Teacher(id=0, name=秦老师))
         */
    }

11 一对多

  • 配置环境:pojo和dao下的mapper接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private String name;
    private int tid;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
    //一对多的集合
    private List students;
}
public interface StudentMapper {
    
}

public interface TeacherMapper {
    /**
     * 子查询:按查询嵌套查询
     * @param tid
     * @return
     */
    Teacher getTeacher(@Param("id") int tid);
    /**
     * 联表查询:按结果嵌套查询
     * @param tid
     * @return
     */
    Teacher getTeacher1(@Param("id") int tid);
}

11.1: 子查询

学习Mybatis_第5张图片




    
    
    
    

测试:

@Test
public void getTeacher() {
    TeacherMapper teacherMapper = MyBatisUtil.getSqlSession().getMapper(TeacherMapper.class);
    Teacher teacher = teacherMapper.getTeacher(1);
    System.out.println(teacher);
    /*
        如果id=0怎么解决?就是collection中配置result property="id" column="id"
        Teacher(id=1, name=秦老师, students=[Student(id=1, name=小红, tid=1),Student(id=2, name=小明, tid=1)...
         */
}

11.2: 联表查询




    
    
    
    
        
        
        
    

测试:

@Test
public void getTeacher1() {
    TeacherMapper teacherMapper = MyBatisUtil.getSqlSession().getMapper(TeacherMapper.class);
    Teacher teacher = teacherMapper.getTeacher1(1);
    System.out.println(teacher);
    /*
        Teacher(id=1, name=秦老师, students=[Student(id=1, name=小红, tid=1), Student(id=2, name=小明, tid=1)...
         */
}

11.3: 多表查询小结

  • 多对一中的一:association
  • 一对多中的多:collection
  • javaType & ofType

    • javaType:指定实体类中的属性的java返回值类型
    • ofType:映射List或某些指定的pojo泛型的类型,联想List中的泛型类型Student用ofType绑定
  • 注意点:

    • 保证SQL的可读性,建议使用联表查询

11.4: 面试题自学补充

  • MySQL引擎
  • InnoDB底层原理
  • 索引和索引优化

12 动态SQL

  • 概念:动态 SQL 是 MyBatis 的强大特性之一,简化了原生复杂SQL书写
  • 四个判断条件:

    • if
    • choose (when, otherwise)
    • trim (where, set)
    • foreach
  • 搭建数据库
CREATE TABLE blog(
    id VARCHAR(50) NOT NULL COMMENT '博客id',
    title VARCHAR(100) NOT NULL COMMENT '博客标题',
    author VARBINARY(30) NOT NULL COMMENT'博客作者',
    # 数据库时间DateTime类型=pojo中的Date类型
    # 下划线命名调到pojo中的驼峰式命令,需要mybatis开启驼峰式命令
    create_time DATETIME NOT NULL COMMENT'创建时间',
    views INT(30) NOT NULL COMMENT'浏览量'
)ENGINE=INNODB DEFAULT CHARSET = utf8;
  • pojo和驼峰式命名
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    /**
     * 下划线命名调到pojo中的驼峰式命令,需要mybatis开启驼峰式命令
     */
    private Date createTime;
    private int views;
}
 

    
    
  • Utils
public class MyBatisUtil {
    /**
     * 提升sqlSessionFactory作用域,便于全局使用
     */
    private 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);
    }
}
//随机产生数据库表中的views
public class UUIDUtils {
    public static String getId() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    @Test
    public void getUUId() {
        System.out.println(UUIDUtils.getId());
    }
}
  • mapper接口
public interface BlogMapper {
    int addBlog(Blog blog);
    List queryBlogByIf(Map map);
    List queryBlogByWhere(Map map);
    List queryBlogByForeach(Map map);
}

if

  • 概念:sql常见的场景就是判断使用
  • 方式一:通过< if >直接使用,或者< include>跳转sql使用时候,需要保证where成立,所以需要在sql语句中加上类似where 1= 1 或者 where state = 'active'等语句

    • 这里使用了SQL片段复用,见后面讲解

学习Mybatis_第6张图片




    
        and  title like #{title}
    
    
        and author like #{author}
    
  • 方式二:通过< where >和< if >混合使用,就不用手动加上where 1= 1

  • 测试:模糊查询需要封装通配符
@Test
public void queryBlogByIf() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap<>();
    //模糊查询,使用map的好处
    map.put("title", "%my%");
    List blogs = blogMapper.queryBlogByIf(map);
    System.out.println(blogs);
    sqlSession.close();
}

@Test
public void queryBlogByWhere() {
    SqlSession sqlSession = MyBatisUtil.getSqlSession();
    BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
    Map map = new HashMap<>();
    //map.put("id","%4%");
    map.put("views", "%2%");
    List blogs = blogMapper.queryBlogByWhere(map);
    System.out.println(blogs);
    sqlSession.close();
}

choose

  • 概念:有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。
  • 需求:传入了 “title” 就按 “title” 查找,传入了 “author” 就按 “author” 查找的情形。若两者都没有传入,就返回标记为 featured 的 BLOG
  • 细节:choose只能满足其中一个whenotherwisw;使用WHERE state = ‘ACTIVE’等保证where成立

where

  • 单独使用< if > 的缺点:如果没有查询条件或者第一个条件没有满足,就会出现错误的sql语句:
  • 出现错误sql:
# 没有条件成立
SELECT * FROM BLOG
WHERE
# 第一个条件没有成立
SELECT * FROM BLOG
WHERE
AND title like ‘someTitle’
  • 使用< where >

    • 优势:where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
  • 使用自定义 trim 元素来定制 where 元素的功能

    • 与< where>等价的< trim>

      • prefix="WHERE"满足条件,自动添加的字段:prefixOverrides自动忽略的字段,细节:AND |OR 两者后面都包含了一个空格,这是正确sql的书写要点

  ...

set

  • 概念:用于动态update语句的叫做 set。set 元素可以用于动态包含需要更新的列,忽略其它不更新的列

    • 等价的trim语句,set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)= 也就是说其实mybatis自动在update中set就给你加上了逗号,但是你自己手写加上了,< set> 也会给你忽略掉

  ...

  update Author
    
      username=#{username},
      password=#{password},
      email=#{email},
      bio=#{bio}
    
  where id=#{id}

foreach

  • 概念:动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)
  • 原生: SELECT * FROM blog WHERE 1=1 AND (id=1 OR id=2);
  • 细节:if < where> 多个条件成立时,就会忽略掉原生中and书写

学习Mybatis_第7张图片



SQL片段

  • 回顾:前面的< where >结合< if>,我们将公共的SQL语句抽取出来,复用.
  • 使用:< sql id= > 标签和< include refid= >引用
  • 细节:

    • 最好基于单表使用sql片段,多表别的表不一定支持
    • 使用sql片段复用,不要使用< where >标签,因为它内置了会忽略掉某些字段

    
        and  title like #{title}
    
    
        and author like #{author}
    


bind(了解)

  • bind 元素允许你在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。比如:

13 缓存

  • 我们再次查询相同数据时候,直接走缓存,就不用再存了,解决速度问题
  • 什么样的数据需要用到缓存?

    • 经常查询并且不经常改变的数据,可以使用缓存

缓存原理图(重要)

二级缓存工作原理:

  • 一次sqlsession是一级缓存,查询操作结束后,是默认保存在一级缓存中的
  • 如果开启二级缓存,必须先关闭一级缓存,这时候的缓存数据会保存到二级缓存中
  • 第二次查询时候,用户操作会嫌去二级缓存中查找

学习Mybatis_第8张图片

一级缓存

  • 默认情况下,只启用了本地的会话(一级)缓存,它仅仅对一个会话中的数据进行缓存。

    • 把一级缓存想象成一个会话中的map,便于理解

学习Mybatis_第9张图片

  • 缓存失效

    • 增删改会把所有的sql缓存失效,下次会重写从数据库中查
    • 查询不同的东西,查询不同的mapper.xml
    • 手动清除缓存: sqlSession.clearCache();

二级缓存

  • mybatis-config,xml开启全局缓存

    
    
    
  • mappper.xml开启二级缓存:

    
    
    • 映射语句文件中的所有 select 语句的结果将会被缓存。
    • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
    • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
    • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
    • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
    • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

      • 读写缓存需要pojo开启序列化操作
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private int id;
    private String name;
    private String pwd;

    public static void main(String[] args) {
        new ArrayList<>();
        new HashMap<>();
        new LinkedList<>();
    }
}
  • 开启二级缓存时,可以指定参数

    • eviction:清楚算法,默认LRU

      • LRU – 最近最少使用:移除最长时间不被使用的对象。
      • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
      • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
      • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。
    • flushInterval:刷新缓存间隔,默认无
    • size:最多缓存数量,默认1024
    • readOnly:只读缓存;写操作会不走缓存,直接从数据库查询,默认是读/写缓存
  • 使用二级缓存

    • 测试语句
public class MyTest {
    @Test
    public void queryUserById() {
        SqlSession sqlSession = MyBatisUtil.getSqlSession();
        SqlSession sqlSession1 = MyBatisUtil.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.queryUserById(1);
        //关闭上次sqlSession,如果开启二级缓存,就会把这次的一级缓存保存到二级缓存中
        sqlSession.close();
        System.out.println("=================");

        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        //如果开启二级缓存,下次相同mapper的查询操作会先重二级缓存中查找
        User user1 = mapper1.queryUserById(1);
        sqlSession1.close();
    }
}

学习Mybatis_第10张图片

学习Mybatis_第11张图片

自定义缓存(了解)

  • 概念:ehcache是一个分布式缓存,主要面向通用缓存
  • 手写或者导入第三方的ehcache缓存依赖
  • 所以可以自定义ehcache.xml配置文件


    org.mybatis.caches
    mybatis-ehcache
    1.2.0
  • 在mapper.xml中配置
 
  • 在resource中创建ehcache.xml文件:

  
      
      
   
      
      
      
      
      
      
  

Redis

  • 自学,另一个开始

你可能感兴趣的:(学习Mybatis)