Mybatis笔记

5 篇文章 0 订阅


. Mybatis笔记


1、简介

1.1 什么是mybatis

是一个优秀的持久层框架,支持定制化sql、存储过程和高级映射。

避免了所有jdbc代码和手动设置参数以及获取结果集。

可以使用简单的xml或注解来配置和映射原生类型、接口和Java中的POJO为数据库中的记录。

如何获得mybatis?

  • maven仓库
  • github
  • 中文文档:直接百度搜索获得

1.2 持久化

数据持久化:将程序的数据在持久状态和瞬时状态转换的过程。

内存:断电即失 ,有些对象不能让他丢掉,所以需要持久化。而且内存太贵了。

数据库持久化,io文件持久化。两种方式都可以完成持久化,后者开销大,所以数据库诞生了。

1.3 持久层

Dao层、Service层、Controller层…

  • 完成持久化工作的代码块,就叫做持久层
  • 层界限十分明显。

1.4 为什么需要MyBatis?

  • 方便
  • 传统的jdbc代码太复杂.简化.框架.自动化.
  • 接触SQL和程序代码的耦合
  • 提供xml标签,支持编写动态sql
  • 提供对象关系映射标签,支持对象关系组建维护。
  • 提供映射标签,支持对象与数据库的orm字段关系映射。

2、第一个Mybatis程序

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

2.1 新建项目

  1. 新建一个普通的maven项目
  2. 删除src目录

2.2 创建一个模块

在左面,父工程项目右键,new moudle 还是新建一个普通的maven项目

这样做的好处在于可以直接继承父工程的环境

  • 编写mybatis的核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "htto://mybatis.org/dtd/mybatis-3-config.dtd">
<!--configuration核心-->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/smbms?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="jiawensili1029"/>
            </dataSource>
        </environment>
        <environment id="tests">
            <transactionManager type="JDBC"></transactionManager>
            <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>
</configuration>
  • 编写mybatis工具类
// sqlSessionFactoryBuilder ---> sqlSessionFactory
// sqlSessionFactory ---> sqlSession
// sqlSession包含了面向数据库执行sql命令所需的所有方法
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            // 获取sqlSessionFactory。通过建造者模式来获取
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static SqlSession getSqlSession(){
        // 获取sqlSession。通过工厂模式来获取
//        SqlSession sqlSession = sqlSessionFactory.openSession();
//        return sqlSession;
        return sqlSessionFactory.openSession();
    }
}

2.3 编写代码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ewsMSyb5-1625065882163)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210607145330136.png)]

使用标签来写查询语句,返回集里resultType来定义返回的类型,比如resultType=“com.shen.pojo.User” ,用来返回一个结果

resultMap用来返回一堆结果。

  • 先定义pojo类User

  • Dao接口

    public interface UserDao {
        List<User> getUserList();
    }
    
  • 接口实现类由原来的UseDaoImpl转变为一个mapper配置文件

    <?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" >
    <!--namespace=绑定一个对应的Dap/Mapper接口-->
    <mapper namespace="com.shen.dao.UserDao">
    
        <!--select查询语句-->
        <select id="getUserList" resultType="com.shen.pojo.User">
            select * from smbms_user
        </select>
    
    </mapper>
    

2.4 使用junit测试

 @Test
    public void test(){
        // 第一步,获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        // 第二步 获得接口,执行sql
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        mapper.getUserList();
    }

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4FLiAoys-1625065882165)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210607224907328.png)]

绑定异常:在mapper注册中心中,接口是未知的

解决方法:

第一步、

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jfRIXk9p-1625065882166)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210607225242309.png)]

只是这样还不够,除非你把UserMapper.xml放到target目录下,否则还是找不到,不生效

但是,我们又不可能每次都手动的把这个东西放进去啊!

出现这个问题的原因,是因为maven的约定大于配置,可能遇到我们写的配置文件,无法被导出或者生效的问题,解决方案如下

第二步、在pom.xml中添加下面代码

<!--在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>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

注意,sqlSession不是线程安全的,因此用完必须关闭(放在finally里)

将上面测试代码改为:

@Test
    public void test(){
        // 第一步,获得SqlSession对象
        SqlSession sqlSession;
        try {
            sqlSession = MybatisUtils.getSqlSession();
            // 第二步 获得接口,执行sql
            UserDao mapper = sqlSession.getMapper(UserDao.class);
            List<User> userList = mapper.getUserList();
            for (User user : userList) {
                System.out.println(user);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            sqlSession.close();
        }
    }

3、CRUD


3.1 namespace

namespace中的包名要和接口的包名一致!

3.2 select/insert/update/delete标签

选择,查询语句

  • id:就是对应的namespace中的方法名
  • resultType:sql语句执行的返回值
  • parameterType:方法的参数类型
  1. 编写接口

  2. 编写对应的mapper中的sql语句

  3. 测试 注意增删改查需要提交事务

3.3 何时使用map?万能map!

假设我们的实体类,有很多字段,但是我们只修改很少的几个字段,则Dao层接口和xml里方法参数类型将不是User,而是Map。具体的#{}里放入map的key就可以自动识别。

多个参数除了使用map意外,还可以使用注解

3.4 模糊查询怎么写?

不要在java层面写"%"+str +"%"

而是要在sql层面写: “%”#{str}"%" 避免sql注入问题!

例子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QAINsRNy-1625065882167)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210613234000226.png)]

注意返回类型是User,但事实上接口的返回类型是List

4、配置解析

4.1 核心配置文件

  • mybatis-config.xml
  • MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息。
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandLers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

4.2 环境配置(environments)

4.2.1 事务管理器

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ghK1fcO-1625065882168)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210614231610228.png)]

4.2.2 数据源

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-juFKDaAi-1625065882169)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210614231851368.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UTHrjyUl-1625065882170)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210614231942829.png)]

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

4.3 属性(properties)

属性都是可以外部配置且可以动态替换的,既可以在典型的Java属性文件中配置,也可以通过properties元素的子元素来传递。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VD2hzhY3-1625065882170)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210614232635346.png)]

注意,xml里,约定了标签的先后顺序,properties必须放在很前面的位置。

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/smbms?useSSL=TRUE&useUnicode=TRUE&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=jiawensili1029

注意,在properties里,driver和url同上面略有区别,true必须大写,不能用& amp;来代表&,driver多个cj,因为不带的已经被淘汰。前面的jdbc.都可以去掉

小结

  • 可以直接引入外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件的

4.4 别名

在xml里

<select id="getUserByUserCode" parameterType="String" resultType="com.shen.pojo.User">
        select * from smbms_user where userCode = #{userCode}
</select>

com.shen.pojo.User太长了,是冗余的。因此使用别名。

  • 方法1.在config.xml里设置别名
<!--可以给实体类型起别名-->
    <typeAliases>
        <typeAlias type="com.shen.pojo.User" alias="user"></typeAlias>
    </typeAliases>
  • 方法2.指定一个包名,MyBatis会在包名下面搜索需要的JavaBean

    扫描实体类的包,它的默认别名就为这个类的类名的首字母小写(使用的时候写成大写也可以)。

<typeAliases>
<!--<typeAlias type="com.shen.pojo.User" alias="user"></typeAlias>-->
	<package name="com.shen.pojo"/>
</typeAliases>

第一种方法可以自定义别名,第二种则需要注解自定义别名。实体类较少建议使用第一种,实体类较多建议使用第二种。第二种方式中,可以用注解来起别名。

@Alias("hello")
public class User {
    // 实体类
    ...
}
<select id="getUserLike" parameterType="String" resultType="hello">
        select * from smbms_user where userName like "%"#{username}"%"
</select>

Java类型中有一些内建的别名。

比如==_int代表int;int代表Integer==

4.5 设置

驼峰命名与数据库命名映射转换

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c95Lsfos-1625065882171)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210619213305302.png)]

4.6 其他配置

  • typeHandlers 类型处理器
  • objectFactory 对象工厂
  • plugins插件(maven搜mybatis)
    • mybatis-plus
    • mybatis-genrator-core
    • 通用mapper

4.7 映射器(mappers)

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

<mappers>
        <!--1.使用相对路径资源引用-->
        <mapper resource="com/shen/dao/UserMapper.xml"></mapper>
        <!--2.使用url完全限定资源定位符,不建议使用-->
        <!--3.使用映射器接口的实现类的完全限定类名-->
        <mapper class="com.shen.dao.UserMapper"></mapper>
        <!--4.将包内的映射器接口实现全部注册为映射器-->
        <package name="com.shen.dao"/>
</mappers>

使用方式3和方式4时会遇到的坑:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4bhQCBKp-1625065882172)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210619214923455.png)]

  • 1.接口和他的Mapper配置文件必须在同一个包下.即UserMapper和UserMapper.xml必须在同一个包下。
  • 2.接口和他的Mapper配置文件必须同名!

4.8 生命周期和作用域

这两个东西很重要,因此错误的使用会导致非常严重的并发问题

SqlSessionFactoryBuilder

  • 一旦创建了SqlSessionFactory,就不需要需要SqlSessionFactoryBuilder了
  • 所以它是局部变量

SqlSessionFactory

  • 可以类比为数据库连接池
  • 一旦创建就在运行期间一直存在,没有任何理由丢弃它或者重新创建它,多次重建会让代码bad smell(产生坏味道)
  • 因此SqlSessionFactory最佳作用域是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式

SqlSession

  • 它是链接到连接池的一个请求
  • SqlSession的实例不是线程安全的,因此不能被共享,所以最佳作用域是请求(每次收到HTTP请求以后就创建一个SqlSession,用完就关闭)或方法作用域
  • 用完之后赶紧关闭,否则浪费资源。
  • 一个SqlSession可以连接多个Mapper,这里每一个Mapper,就代表一个具体的业务

5、解决属性名和字段名不一致问题

public class User {
    // 实体类
    private Integer id;
    private String userCodeCodeHa; // 改这里
}

经过测试发现,如果但改这里和所有的userCode参数变为userCodeCodeHa,还是可以从数据库里查到。但是如果把set方法和get方法也改了。比如把setUserCode改为setUserCodeCodeHa以后,就在数据库里找不到这个字段名对应的数据了(输出null)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZM3JKOhe-1625065882172)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210619223025121.png)]

因此可以推测,MyBatis是通过set和get方法的名字,来一一对应java中pojo的实体类的属性名与数据库中字段名的。

  • 方法一:在sql语句里起别名

    <select id="getUserByUserCode" parameterType="String" resultType="hello">
            select userpassword,usercode as usercodecodeha from smbms_user where userCode = #{userCode}
    </select>
    

    其实从这个方法,可以看出,mybatis其实是执行sql以后,把结果的那个列名,拼接上“set”,构成了SetUserCodeCodeHa(不区分大小写),然后在java对应的pojo实体类里,找到对应的这个方法,然后把列名对应的属性作为参数,传入这个set方法里。

  • 方法二:resultMap 结果集映射

    1. 首先,给select标签里的resultMap随便起个名字,这里叫UserMap吧

      <select id="getUserByUserCode" parameterType="String" resultMap="UserMap">
              select * from user_test where usercode = #{userCode}
      </select>
      
    2. 然后,在resultMap标签,做一个映射。注意这里严格区分大小写

      <!--column数据库中的字段,property实体类中的属性 严格区分大小写-->
          <resultMap id="UserMap" type="hello">
              <result column="usercode" property="userCodeCodeHa"></result>
            	<!--对于没有别名的这两句,其实可以不写-->
              <result column="userpassword" property="userPassword"></result>
              <result column="username" property="userName"></result>
      </resultMap>
      

6、日志


6.1 日志工厂

如果一个数据库操作出现异常,可以通过日志工厂来排错。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PEmrUfI0-1625065882173)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210620172235045.png)]

主要掌握LOG4J和STDOUT_LOGGING

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cq2cb4Ll-1625065882173)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210620172712062.png)]

STDOUT_LOGGING是标准的日志工厂,可以直接用

其他的,比如LOG4J就需要导包以后才能用,否则找不到类

6.2 LOG4J

log4j的apache的一个开源项目。可以控制日志信息输送的目的地是控制台、文件还是GUI组件。可以控制每一条日志的输出格式、定义每一条日志信息的级别。可以通过一个配置文件来灵活地进行配置,不需要修改应用的代码。

  1. 先导入log4j的包

    <dependencies>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
        </dependencies>
    
  2. log4j.properties

    #将等级为DEBUG的日志信息输出到console和file两个目的地。console和file的定义在下面的代码
    log4j.rootLogger=debug,file,console
    
    #输出到文件相关设置
    log4j.appender.file.Append = true
    log4j.appender.file.MaxFileSize = 10MB
    log4j.appender.file = org.apache.log4j.RollingFileAppender
    log4j.appender.file.File = ./log/com.shen
    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.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.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
    
    
  3. 配置log4j为日志的实现

  4. 使用

    6.3 日志级别

    info、error、debug

7、分页

7.1 limit分页

  • 减少数据的处理量
// 分页
    List<User> getUserByLimit(Map<String,Integer> map);
<select id="getUserByLimit" parameterType="map" resultType="user">
        select * from smbms_user limit #{startIndex},#{pageSize}
    </select>

7.2 RowBounds分页

<select id="getUserByRowBounds" resultMap="UserMap">
        select * from smbms_user
    </select>
@Test
    public void  getUserByRowBounds(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        // 其实RowBounds本质也是在调用limit
        RowBounds rowBounds = new RowBounds(2,5);
        // 通过Java层面代码实现分页
        List<User> list = sqlSession.selectList("com.shen.dao.UserMapper.getUserByRowBounds",null,rowBounds);
        for(User user : list){
            System.out.println(user);
        }
    }

7.3 在maven里用一些其他的分页插件,如pageHelper

8、使用注解开发

面向接口编程的根本原因:解耦、提高复用。

不需要mapper.xml,对于简单的sql语句,可以直接在接口中使用注解。

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

本质:反射机制实现

底层:动态代理—代理模式!

9、Lombok

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0lwUtLMC-1625065882174)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210621180320371.png)]

使用maven仓库引入lombok的jar包。

只需要一个注解 Data,就生成了:

​ 无参构造、set、get、toString、hashcode、equals

@NoArgsConstructor
@AllArgsConstructor

无参构造和有参构造的注解

10、多对一处理


10.1 按照查询嵌套处理

例:smbms_user的userRole不是Integer类型,而直接使用Role类型的实体。

Pojo:Role

@Data
public class Role {
    private Integer roleCode;
    private String roleName;
}

Pojo:User

@Data
public class User {
    // 实体类
    private Integer id;
    private String userCode; // # 解决属性名和字段名不一致问题
    private String userName;
    private Role userRole;
}

UserMapper.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" >
<!--namespace=绑定一个对应的Dap/Mapper接口-->
<mapper namespace="com.shen.dao.UserMapper">

    <!--这里的userAndRole本质上还是一个User类型的,但因为涉及到复杂属性,不得不另起一个map来描述清楚-->
    <resultMap id="userAndRole" type="user">
        <result property="userCode" column="userCode"></result>
        <result property="userName" column="userName"></result>
        <!--复杂的属性需要单独处理,对象:association  集合:collection-->
        <association property="userRole" column="userRole" javaType="Role" select="getRoleByRoleCode"></association>
    </resultMap>

    <select id="getUsersAndRoleName" resultMap="userAndRole">
        select * from smbms_user
    </select>

    <select id="getRoleByRoleCode" resultType="role">
        select * from smbms_role where roleCode = #{roleCode}
    </select>
</mapper>

注意,其中

<select id="getRoleByRoleCode" resultType="role">
        select * from smbms_role where roleCode = #{roleCode}
    </select>

这个查询,不是放在RoleMapper.xml而是放在UserMapper.xml

因为getUsersAndRoleName这个接口的实现,要使用getRoleByRoleCode(这个在RoleMapper接口里定义,在UserMapper.xml里实现)

<association property="userRole" column="userRole" javaType="Role" select="getRoleByRoleCode"></association>

本质其实就是property的userRole对应User类里的Role userRole的实例对象。

column的userRole对应数据库表里smbms_user的userRole(BigInteger类型)

javaType相当于是要使用column作为参数,去select后面那个语句以后的返回类型,正好就是Role类型嘛!因为getRoleByRoleCode返回的是role类型。

以上称之为按照查询嵌套处理

10.2 按照结果嵌套处理

例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R8BT1I8u-1625065882174)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210621230423305.png)]

返回学生姓名和学生对应的老师的姓名

回顾mysql嵌套查询方法:子查询、联表查询

其实就是对应上面的按照查询嵌套和按照结果嵌套

11、一对多处理

比如:一个老师拥有多个学生!对于老师而言,就是一对多。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1FSh8Tgh-1625065882175)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210621230804334.png)]

学生类则是单独的和数据库一一对应的pojo

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8qzTr234-1625065882175)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210621232357846.png)]

一对多使用集合Collection 集合中的元素类型不用javaType,而是用ofType表示

12、动态sql

动态sql就是指根据不同的条件生成不同的sql语句

if

<select ....>
	<if test=" title!=null ">
		 AND title like #{title}
  </if>
</select>

choose(when ,otherwise)

类似于java中的swich语句

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hwpI7ufU-1625065882176)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623230045371.png)]

两个when条件都满足,但只走了第一个.相当于switch case breake了

trim(where,set)

where元素只会在至少有一个子元素的条件返回SQL子句的情况下才会插入where,若语句开头为AND或者OR,where元素会自动将它们去除.

where和set都是trim的子元素.使用trim可以自己定制类似where和set的标签,并且定义前缀后缀/前缀覆盖后会覆盖.

前缀/后缀:比如where,如果没有任何子元素,就自动把where去掉

前缀覆盖:比如and和or,如果是第一个子元素,就会自动去掉and和or,第二个开始的子元素会保留and和or

后缀覆盖:比如set的逗号,如果是最后一个set的子元素,会把逗号去掉,不然sql里多一个逗号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LtH3nzze-1625065882176)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623225935781.png)]

foreach

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xbOreIug-1625065882176)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623231256430.png)]

item就是从collection里遍历的每一项

例:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dCbEWoqk-1625065882177)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623231413483.png)]

因为where标签很"智能",所以不需要写1=1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6k44Wt1h-1625065882177)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623231810060.png)]

ids使用map传入

sql标签与include标签(sql片段)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GInpd2Kl-1625065882178)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623230700242.png)]

可以用来存取一个sql片段,避免重写一遍.

注意事项:

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

13、缓存

一级缓存

sqlSession级别的缓存。一级缓存默认开启,且无法关闭,只在一次sqlSession中有效

比如在一次sqlSession会话中,查询两次同一条语句,但sql其实只走了一次。

一级缓存就是一个Map

实现方式:LRU(最长时间不用的就被顶替)、FIFO(最先使用过的被顶替)

缓存失效的情况:

  1. 查询不同的东西

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

  3. 查询不同的Mapper.xml

  4. 手动清理缓存

    sqlSession.clearCache();
    

二级缓存

namespace级别的缓存

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Btx4QK2r-1625065882179)(/Users/shenhangran/Desktop/学习笔记/我的/Mybatis笔记.assets/image-20210623234039925.png)]

步骤:

  1. 在config的settings里开启缓存
<settings>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
</settings>
  1. 在当前mapper中使用
<!--在当前mapper中使用二级缓存 每隔60秒刷新-->
    <cache eviction="FIFO" flushInterval="60000"
           size="512" readOnly="true"/>

刷新时间单位为毫秒。

记得在具体的一个sql语句的地方开启cache

<select id="getUsersAndRoleName" resultMap="userAndRole" useCache="true">
        select * from smbms_user
    </select>

小结

  • 二级缓存有弊端,需要pojo实体类实现Serializable接口保证不报错(readonly设置为false时)
  • 只要开了二级缓存,在同一个mapper下就有效!
  • 所有的数据都会放在一级缓存中,只有会话提交或者关闭的时候,才会提交到二级缓存。即.只有一级缓存崩了以后,二级缓存才生效

readOnly设置为false时,下面的代码会输出false,否则会输出true。原因是因为事先了Serializable接口,深拷贝,哈希变了,但因为开了二级缓存,所以还是只走了一遍sql!

public void test1(){
        SqlSession sqlSession1 = MybatisUtils.getSqlSession();
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        List<User> users1 = mapper1.getUsersAndRoleName();
        sqlSession1.close(); // 得先关闭。因为只有一级缓存崩了以后二级缓存才生效
        System.out.println("------");
        SqlSession sqlSession2 = MybatisUtils.getSqlSession();
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        List<User> users2 = mapper2.getUsersAndRoleName();

        System.out.println(users1==users2);

        sqlSession2.close();
    }

总结:

对于用户的命令而言,先从二级缓存里看有没有,没有的话看一级缓存里有没有,还没有的话才去数据库里查找!

ehcache

maven导入ehcache可以自定义缓存,也可以用现成的。

type属性指定的类必须实现org.mybatis.cache.Cache接口且提供一个String id

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值