Mybatis学习笔记

Mybatis

  • 1.快速入门(xml文件配置形式)
    • 1.创建实体类
    • 2.引入jar包
    • 3.编写全局配置文件
    • 4.编写mapper.xml映射文件(放在类路径下)
    • 5.数据库和log4j配置文件
    • 6.测试
    • 7.结果
  • 2.通过接口来实现
    • 1.添加接口Mapper
    • 2.修改UserMapper.xml配置文件
    • 3.将UserMapper.xml加到全局配置文件中,接口不需要加
    • 4.测试
  • 3.Mybatis全局配置
    • 1.引入dtd约束
    • 2.properties标签
    • 3.setting
    • 4.typeAliases
    • 5.TypeHandlers
    • 6.plugins
    • 7.environments
    • 8.mappers
      • 1.注解接口
      • 2.测试
      • 3.结果
  • 4.增删改查
    • 1.编写实体类
    • 2.编写全局配置文件
    • 3.写mapper接口
    • 4.写对应的mapper.xml文件
    • 5.目录结构
    • 6.测试代码和结果
    • 7.注意点
    • 8.获取自增的id值
      • 1.配置
      • 2.测试
      • 3.结果
  • 5.参数处理
    • 1.单个参数
    • 2.多个参数
    • 3.命名参数
    • 4.Pojo和Map
      • 1.pojo会自动封装
      • 2.map
        • 1.接口
        • 2.xml配置
        • 3.测试
      • 3.VO
      • 4.特殊处理
      • 5.总结
    • 5.参数支持的属性
  • 6.参数取值
  • 7.select元素
    • 1.返回list集合
    • 2.模糊查询
    • 3.返回一个map
      • 1.将对象那个封装成一个map返回
      • 2.多个对象封装成一个map
    • 4.resultmap自定义封装复杂类型
      • 1.一对一关系
        • 1.嵌套结果集
        • 2.分步查询
        • 3.延迟加载
      • 2.一对多的关系
          • 1.嵌套结果集的方式:使用collection结果集映射
          • 2.collection懒加载
      • 3.分步查询 第一个查询结果传递多个参数
          • 1.FetchType属性
      • 4.discriminator鉴别器
  • 8.动态sql
  • 9.缓存
    • 1.一级缓存
      • 1.缓存体验
      • 2.一级缓存失效的4种情况
        • 1.使用不同的sqlsession
        • 2.sqlsession相同,查询的条件不同
        • 3.两次查询相同数据时,执行了增删改操作
        • 4.手动清理缓存
    • 2.二级缓存(全局缓存)
      • 1.体验
      • 2.注意
    • 3.二级缓存有关的属性和设置
      • 2.sqlsession.clearCache()
      • 3.localCacheScope:本地缓存作用域
    • 4.缓存工作原理
  • 配置日志

1.快速入门(xml文件配置形式)

只需要写mapper.xml文件,并把mapper.xml文件配置到全局配置文件中,才通过命名空间就可以找到指定的sql语句,并且封装为JavaBean对象

1.创建实体类

package com.zhw.mybatis.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer id;

    private String userName;

    private String address;

    private Long birthday;
}

2.引入jar包

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

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

3.编写全局配置文件

<?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>

    <!--通过properties标签加载外部的properties文件-->
    <properties resource="db.properties"></properties>

    <!--    自定义别名-->
    <typeAliases>
        <package name="com.zhw.mybatis.entities"/>
    </typeAliases>

    <!--配置环境:可以配置多个环境,当defaul指向谁就用哪个环境-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <!--配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--数据源-->
            <dataSource type="POOLED">
                <!--数据库的基本信息-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--加载映射文件-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>


</configuration>

4.编写mapper.xml映射文件(放在类路径下)


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhw.mybatis.entities.UserMapper">
    <select id="selectUser" resultType="User" parameterType="int">
        select * from tb_user where id = #{id}
    select>
mapper>

5.数据库和log4j配置文件

#将等级为DEBUG的日志输出到conlose和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/zhw.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







jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
#useUnicode是否使用字符集
#characterEncoding设置使用的字符集
#useSSL是否使用SSL协议通信
jdbc.username=root
jdbc.password=123456

6.测试

 /**
     * 根据xml配置文件(全局配置文件)创建一个sqlSessionFactory对象
     * @throws IOException
     */
    @Test
    public void test01() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //不是单例模式
        //获取sqlsession实例
        SqlSession sqlSession = sqlSessionFactory.openSession();
//        SqlSession sqlSession1 = sqlSessionFactory.openSession();

        /**
         *
          sql的唯一标识statement – Unique identifier matching the statement to use.
         */
        User user = sqlSession.selectOne("com.zhw.mybatis.entities.UserMapper.selectUser", 55);
        System.out.println("用户为:"+user);
        sqlSession.close();
    }

7.结果

Mybatis学习笔记_第1张图片

2.通过接口来实现

主要功能是获取一个代理对象,用代理对象来做对数据库的操作

接口与配置文件动态绑定

1.添加接口Mapper

package com.zhw.mybatis.mapper;

import com.zhw.mybatis.entities.User;


public interface UserMapper {

    public User getUserById(Integer id);
}

2.修改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">
    //指定UserMapper.java的全类名
<mapper namespace="com.zhw.mybatis.mapper.UserMapper">
    //id为类中的方法
    <select id="getUserById" resultType="User" parameterType="int">
        select * from tb_user where id = #{id}
    </select>
</mapper>

3.将UserMapper.xml加到全局配置文件中,接口不需要加

	<mappers>
		只需要将mapper.xml文件加入到mybatis全局配置文件中,mybatis会自己按照命名空间去找对应的mapper对象
        <mapper resource="mybatis/mapper/PersonMapper.xml"/>
        <mapper resource="mybatis/mapper/UserMapper.xml"/>
    mappers>

4.测试

package com.zhw.mybatis.test;
public class MyBatisTest {
    
    @Test
    public void test01() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        SqlSession sqlSession = sqlSessionFactory.openSession();

        //获取接口的代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        User user = userMapper.getUserById(1);

        System.out.println(user);

        sqlSession.close();
    }
}

Mybatis学习笔记_第2张图片

获取封装的接口对象,调用该方法,会执行映射的mapper.xml文件中的sql语句

3.Mybatis全局配置

1.引入dtd约束


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>

configuration>

2.properties标签

 
//在类路径下
    <properties resource="db.properties">properties>

3.setting

   <settings>
        设置开启驼峰
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    settings>

4.typeAliases

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
typeAliases>

<typeAliases>
  <package name="domain.blog"/>
typeAliases>

引用的时候可大写,也可以小写

5.TypeHandlers

6.plugins

7.environments

 
    <environments default="dev">
        
        <environment id="dev">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
                
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            dataSource>
        environment>


        <environment id="test">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
                
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            dataSource>
        environment>
    environments>

8.mappers

将sql映射注册到全局配置中

    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
        <mapper resource="mapper/PersonMapper.xml"/>
        <mapper resource="mapper/UserMapper.xml"/>
        <mapper resource="mapper/PersonMapper.xml"/>
    mappers>
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
mappers>
class用于将UserMapper.java接口注册到全局配置文件中,不用注册UserMapper.xml配置文件,但是UserMapper.xml配置文件必须在同一文件下
//注意必须xml文件和接口必须在同一包下

1.注解接口

package com.zhw.mybatis.mapper;

public interface UserMapperAnnotation {

    @Select("select * from tb_user where id = #{id}")
    public User getUserById(Integer id);
}

//在全局配置文件中引入
<mappers>
  <mapper class="com.zhw.mybatis.mapper.UserMapperAnnotation"/>
mappers>

2.测试

  @Test
    public void test03() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapperAnnotation mapper = sqlSession.getMapper(UserMapperAnnotation.class);
        User user = mapper.getUserById(1);

        System.out.println(user);
    }

3.结果

在这里插入图片描述

4.增删改查

1.编写实体类

package com.zhw.mybatis2.entities;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer id;

    private String userName;

    private String address;

    private Long birthday;
}

2.编写全局配置文件


DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>

    
    <properties resource="db.properties">properties>

    
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    settings>

    
    <typeAliases>
        <package name="com.zhw.mybatis2"/>
    typeAliases>

    
    <environments default="dev">
        
        <environment id="dev">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
                
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            dataSource>
        environment>


        <environment id="test">
            
            <transactionManager type="JDBC">transactionManager>
            
            <dataSource type="POOLED">
                
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            dataSource>
        environment>


    environments>

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


configuration>

3.写mapper接口

package com.zhw.mybatis2.mapper;

import com.zhw.mybatis2.entities.User;

public interface UserMapper1 {

    public User getUserById(Integer id);

    //mybatis会自动封装返回结果,语句执行成功为true,不成功为false
    public Boolean addUser(User user);

    public Boolean deleteById(Integer id);

    public Boolean updateById(User user);
}

4.写对应的mapper.xml文件


DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zhw.mybatis2.mapper.UserMapper1">
    <select id="getUserById" resultType="User" parameterType="int">
        select * from tb_user where id = #{id}
    select>

    <insert id="addUser" parameterType="user">
        insert into tb_user values (#{id},#{userName},#{address},#{birthday})
    insert>

    <delete id="deleteById" parameterType="int">
        delete from tb_user where id = #{id}
    delete>

    <update id="updateById" parameterType="user">
        update tb_user set username = #{userName},address = #{address},birthday = #{birthday} where id = #{id}
    update>
mapper>

5.目录结构

Mybatis学习笔记_第3张图片

6.测试代码和结果

package com.zhw.mybatis.test;

public class MybatisTest {

    //查询方法
    @Test
    public void test01() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        User userById = mapper.getUserById(1);
        System.out.println(userById);
    }

    //增加用户
    @Test
    public void test02() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession(true);
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        User user = new User();
        user.setId(23);
        user.setAddress("uiui");
        user.setBirthday(12344l);
        user.setUserName("zzzz");
        mapper.addUser(user);
    }

    //删除用户
    @Test
    public void test03() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession(true);
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        int i = mapper.deleteById(23);
        System.out.println(i);
    }

    //修改用户
    @Test
    public void test04() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession(true);
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        User user = new User(1, "zhengshihao", "zhengzhaicun", 19991112l);
        mapper.updateById(user);
    }
}

7.注意点

  • mybatis对数据进行改动不会提交数据需要手动提交

    • @Test
        public void test04() throws IOException {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            SqlSession sqlSession = factory.openSession();
            UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
            User user = new User(1, "zhengshihao", "zhengzhaicun", 19991112l);
            mapper.updateById(user);
            //手动提交
            sqlSession.commit();
        }
      
  • 或者自动提交

    • @Test
        public void test04() throws IOException {
            InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
            //自动提交数据
            SqlSession sqlSession = factory.openSession(true);
            UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
            User user = new User(1, "zhengshihao", "zhengzhaicun", 19991112l);
            mapper.updateById(user);
        }
      
  • 语句的返回值

    • //mybatis会自动封装返回结果,语句执行成功为true,不成功为false
          public Boolean addUser(User user);
      

8.获取自增的id值

使用主键自增策略,添加数据的时候不需要,添加主键的值

1.配置

<insert id="addUser" parameterType="user" keyProperty="id" useGeneratedKeys="true">
        insert into tb_user(username,address,birthday) values (#{userName},#{address},#{birthday})
    insert>
keyProperty="id" 将获取的主键封装到javaBean的哪个属性
useGeneratedKeys="true" 是否获取加入的数据的主键

2.测试

 @Test
    public void test02() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession(true);
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        User user = new User();
        user.setAddress("uiui");
        user.setBirthday(12344L);
        user.setUserName("zzzz");
        Boolean aBoolean = mapper.addUser(user);
        if (aBoolean){
            Integer id = user.getId();
            System.out.println(id);
        }else {
            System.out.println("没有封装到");
        }
    }

3.结果

在这里插入图片描述

5.参数处理

1.单个参数

#{参数名}:取出参数名,不做特殊处理,直接将参数封装到给定的#{参数名}中,参数名可以任意,不用和参数名相同
在这里插入图片描述

2.多个参数

    <select id="getUserByIdWithName" resultType="User" >
        select * from tb_user where id = #{id} and username = #{userName}
    select>
   public User getUserByIdWithName(Integer id,String userName);

出现异常:

Cause: org.apache.ibatis.binding.BindingException: Parameter ‘id’ not found. Available parameters are [arg1, arg0, param1, param2]

当遇到多个参数mybatis会做特殊处理

多个参数封装成一个map

​ key:param1…paramN 或者参数的arg0…argN也可以

​ value :传入的参数值

    <select id="getUserByIdWithName" resultType="User" >
        select * from tb_user where id = #{param1} and username = #{param2}
    select>
  <select id="getUserByIdWithName" resultType="User" >
        select * from tb_user where id = #{arg0} and username = #{arg1}
    select>

结果

在这里插入图片描述

3.命名参数

在接口的参数上使用@Param注解就可以指定多个参数的命名,测试在xml中就可以使用了

public User getUserByIdWithName(@Param("id") Integer id,@Param("userName") String userName);
<select id="getUserByIdWithName" resultType="User" >
        select * from tb_user where id = #{id} and username = #{userName}
    select>

结果

在这里插入图片描述

4.Pojo和Map

1.pojo会自动封装

2.map

#{key}:取出对应的值,直接用这种方式可以获取map的对应的值

1.接口
//传入一个map
    public User getUserByMap(Map<String,Object> map);

2.xml配置

    <select id="getUserByMap" resultType="user">
        select * from tb_user where id = #{id} and username = #{userName}
    select>
3.测试
/**
     * 根据id和用户名查询 多个参数封装的map
     * @throws IOException
     */
    @Test
    public void test06() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession(true);
        UserMapper1 userMapper = sqlSession.getMapper(UserMapper1.class);
        Map<String, Object> stringObjectMap = new HashMap<>();
        stringObjectMap.put("id",1);
        stringObjectMap.put("userName","zhengshihao");
        User userByMap = userMapper.getUserByMap(stringObjectMap);
        System.out.println(userByMap);
    }

在这里插入图片描述

3.VO

4.特殊处理

Mybatis学习笔记_第4张图片

5.总结

在这里插入图片描述

5.参数支持的属性

Mybatis学习笔记_第5张图片

6.参数取值

#{}:可以获取map中的值或者pojo对象属性的值

${}:可以获取map中的值或者pojo对象属性的值


    <select id="getUserByMap" resultType="user">
        select * from tb_user where id = ${id} and username = #{userName}
    select>

成功

区别:

​ #{}:是以预编译的形式,将参数设置到sql语句中,PreparedStatement;防止sql注入

​ ${}:取出的值直接拼接在sql语句中;会有安全问题

​ 大多情况下,我们取参数的值都应该使用#{}

​ 原生jdbc不支持占位符的地方问哦们可以使用${}进行取值

比如分表:按照年份分表拆分

select * from ${year}_salary where xxx;

select * from tbl_employee order by ${f_name} ${order}

在这里插入图片描述

7.select元素

1.返回list集合

//接口
//查询所有的数据
    public List<User> getAllUser();
xml文件
 <select id="getAllUser" resultType="user">
        select * from tb_user
    select>
//指定查询语句的resultType类型,为集合中的泛型

2.模糊查询

//接口
//查询所有的数据
    public List<User> getAllUser(String userName);
<select id="getAllUser" resultType="user" >
        select * from tb_user where username like #{userName}
    select>
UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        List<User> allUser = mapper.getAllUser("%zheng%");
        System.out.println(allUser);

3.返回一个map

1.将对象那个封装成一个map返回

//将对象封装成一个map返回
    public Map<String,Object> getUserByIdReturnMap(Integer id);
 <select id="getUserByIdReturnMap" parameterType="int" resultType="map">
        select * from tb_user where id = #{id}
    select>
/**
     * 返回对象封装的map
     * @throws IOException
     */
    @Test
    public void test08() throws IOException {
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        Map<String, Object> userByIdReturnMap = mapper.getUserByIdReturnMap(1);
        Set<Map.Entry<String, Object>> entries = userByIdReturnMap.entrySet();

        entries.forEach(e -> {
            System.out.println(e.getKey()+e.getValue());
        });
    }

2.多个对象封装成一个map

  //将多个对象封装成一个map返回
    //添加一个注解用作可以,来自数据库中的id
    @MapKey("id")
    public Map<Integer,User> getAllUserReturnMap();

    <select id="getAllUserReturnMap" resultType="user">
        select * from tb_user
    select>
//只需要指定value的类型就可以了
/**
     * 返回多个对象封装的map
     * @throws IOException
     */
    @Test
    public void test09() throws IOException {
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        Map<Integer, User> allUserReturnMap = mapper.getAllUserReturnMap();
        System.out.println(allUserReturnMap);
        System.out.println(allUserReturnMap.get(1));
    }

4.resultmap自定义封装复杂类型

//Vo类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.zhw.mybatis2.entities;

public class UserVo {
    private String name;
    private String userName;

    public String getName() {
        return this.name;
    }

    public String getUserName() {
        return this.userName;
    }

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

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof UserVo)) {
            return false;
        } else {
            UserVo other = (UserVo)o;
            if (!other.canEqual(this)) {
                return false;
            } else {
                Object this$name = this.getName();
                Object other$name = other.getName();
                if (this$name == null) {
                    if (other$name != null) {
                        return false;
                    }
                } else if (!this$name.equals(other$name)) {
                    return false;
                }

                Object this$userName = this.getUserName();
                Object other$userName = other.getUserName();
                if (this$userName == null) {
                    if (other$userName != null) {
                        return false;
                    }
                } else if (!this$userName.equals(other$userName)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof UserVo;
    }

    public int hashCode() {
        int PRIME = true;
        int result = 1;
        Object $name = this.getName();
        int result = result * 59 + ($name == null ? 43 : $name.hashCode());
        Object $userName = this.getUserName();
        result = result * 59 + ($userName == null ? 43 : $userName.hashCode());
        return result;
    }

    public String toString() {
        return "UserVo(name=" + this.getName() + ", userName=" + this.getUserName() + ")";
    }

    public UserVo() {
    }

    public UserVo(String name, String userName) {
        this.name = name;
        this.userName = userName;
    }
}

//接口
  //多表查询resultMap结果集映射
    public UserVo getUserWithPersonById(Integer id);
//xml文件
<resultMap id="UserWithPerson" type="userVo">
        <result column="username" property="userName"/>
        <result column="name" property="name"/>
    resultMap>

    <select id="getUserWithPersonById" resultMap="UserWithPerson">
        select u.username,p.name from tb_user u,tb_person p  where u.id = p.id and u.id = #{id}
   select>
//测试
/**
     * 返回resultmap映射
     * @throws IOException
     */
    @Test
    public void test10() throws IOException {
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        UserVo userWithPersonById = mapper.getUserWithPersonById(2);
        System.out.println(userWithPersonById);
    }

//结果成功

规则:

id:映射器的唯一标识  映射器的类型
<resultMap id="UserWithPerson" type="userVo">
    id标签:主键
        <id column="username" property="userName"/>
    result:字段
    column:数据库的字段
    property:javabea的属性
        <result column="name" property="name"/>
resultMap>
resultMap 指定引用哪一个映射器
 <select id="getUserWithPersonById" resultMap="UserWithPerson">
        select u.username,p.name from tb_user u,tb_person p  where u.id = p.id and u.id = #{id}
   select>

1.一对一关系

1.嵌套结果集
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserWithOrder {
    private Integer id;

    private String userName;

    private String address;

    private Long birthday;
    private Order order;
}
 //User中有Order
    public UserWithOrder getUserWithOrder(Integer id);
    <resultMap id="UserWithOrder" type="UserWithOrder">
        <id column="userid" property="id"/>
        <result column="username" property="userName"/>
        <result column="birthday" property="address"/>
        <result column="birthday" property="birthday"/>
        //嵌套结果集
        <association property="order" javaType="Order">
            <id column="oid" property="id"/>
            <result column="number" property="number"/>
            <result column="uid" property="uid"/>
        association>
    resultMap>

    <select id="getUserWithOrder" resultMap="UserWithOrder">
        select *,u.id as userid,o.id oid from tb_user u,tb_orders o where o.id = u.id and u.id = #{id}
    select>

  /**
     * 1对1结果映射
     * @throws IOException
     */
    @Test
    public void test11() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        UserWithOrder userWithOrder = mapper.getUserWithOrder(1);
        System.out.println(userWithOrder);
    }
2.分步查询
 	OrderMapper
   namespace="com.zhw.mybatis2.mapper.OrderMapper"
	<select id="getOrderById" resultType="Order" parameterType="int">
        select * from tb_orders where id = #{id}
    select>





 
    
    <resultMap id="MyUserSetp" type="UserWithOrder">
        <id column="id" property="id"/>
        <result column="username" property="userName"/>
        <result column="birthday" property="birthday"/>
        <result column="address" property="address"/>
        
        <association property="order"
        			
        <setting name="lazyLoadingEnabled" value="true"/>
        
        <setting name="aggressiveLazyLoading" value="false"/>
 //14.分布查询
    @Test
    public void test14() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        UserWithOrder userWithOrderStep = mapper.getUserWithOrderStep(1);
        //只用到了User的信息
        System.out.println(userWithOrderStep.getId());
    }

在这里插入图片描述

只发了一条查询语句

 //14.延迟加载
    @Test
    public void test14() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession();
        UserMapper1 mapper = sqlSession.getMapper(UserMapper1.class);
        UserWithOrder userWithOrderStep = mapper.getUserWithOrderStep(1);
        //用到了Order的对象的属性,所以加载了
        System.out.println(userWithOrderStep.getOrder().getId());
    }

Mybatis学习笔记_第6张图片

发了两条sql语句

2.一对多的关系

1.嵌套结果集的方式:使用collection结果集映射
 

    <resultMap id="User1WithOrders" type="User1">
        <id column="uuuid"  property="id"/>
        <result column="birthday" property="birthday"/>
        <result column="address" property="address"/>
        <result column="username" property="userName"/>
        //property:属性的名字,ofType:集合里面的泛型
        <collection property="orders" ofType="com.zhw.mybatis2.entities.Order">
            <id column="id" property="id"/>
            <result column="number" property="number"/>
            <result column="uid" property="uid"/>
        collection>
    resultMap>
    <select id="getUser1WithById" resultMap="User1WithOrders">
        SELECT* ,u.id AS uuuid FROM tb_user u LEFT JOIN tb_orders o ON u.`id` = o.`uid` WHERE u.`id` = #{id}
    select>
2.collection懒加载

    <resultMap id="User1WithOrdersStep" type="com.zhw.mybatis2.entities.User1">
        <id column="id" property="id"/>
        <result column="address" property="address"/>
        <result property="birthday" column="birthday"/>
        <result property="userName" column="username"/>
        
        collection>
    resultMap>
    <select id="getUser1WithByIdStep" resultMap="User1WithOrdersStep">
        select * from tb_user where  id = #{id}
    select>
返回一个List 
<select id="getOrderByIdList" resultType="Order" parameterType="int">
        select * from tb_orders where uid = #{uid}
    select>
 //14.一对多 懒加载
    @Test
    public void test16() throws IOException {
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = factory.openSession();
        User1Mapper mapper = sqlSession.getMapper(User1Mapper.class);
        User1 user1WithById = mapper.getUser1WithByIdStep(1);
        System.out.println(user1WithById.getOrders().get(1));
    }

测试成功

3.分步查询 第一个查询结果传递多个参数

将多个值封装成一个map传递

column={key1=column1,key2=column2}

1.FetchType属性

association和collection的FetchType属性,只当是否开启延迟加载,即使开启了全局的延迟加载,也按照指定的的属性

<collection property="orders"
                    ofType="com.zhw.mybatis2.entities.Order"
                    select="com.zhw.mybatis2.mapper.OrderMapper.getOrderByIdList"
                    column="{uid=id}"
            		fetchType="eager"
                    fetchType="lazy">
    				eager:立即
    				lazy:延迟加载
        collection>

4.discriminator鉴别器

使用结果值来决定使用哪个 resultMap

看文档把不想写了

<select id="getUser1WithByIdStep" resultMap="User1WithOrdersStep">
        select * from tb_user where  id = #{id}
    select>


	//如果查出来的用户名为zhegnshihao则查询该用户的订单,否则什么也不做
    <resultMap id="User1WithOrdersStep" type="com.zhw.mybatis2.entities.User1">
        <id column="id" property="id"/>
        <result column="address" property="address"/>
        <result property="birthday" column="birthday"/>
        <result property="userName" column="username"/>
        column:为判断的属性,javaType:为该属性定义的类型
        <discriminator javaType="string" column="userName">
            valueL:为column指定的情况
            <case value="zhengshihao">
                <collection property="orders"
                            ofType="com.zhw.mybatis2.entities.Order"
                            select="com.zhw.mybatis2.mapper.OrderMapper.getOrderByIdList"
                            column="id"
                            fetchType="lazy">
                collection>
            case>
        discriminator>
    resultMap>

8.动态sql

看官方文档

9.缓存

两级缓存

​ 一级缓存:(本地缓存):sqlsession级别的缓存,一级缓存是一直开启的,没法关掉

  • 与数据库通一次会话期间查询的数据会放在本地缓存中
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库
  • 如果失效,会发送多个sql

1.一级缓存

1.缓存体验

 @Test
    public void test01() throws IOException {
        SqlSession sqlSession = getSqlSession();

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

        User userById1 = mapper.getUserById(1);
        System.out.println(userById1);

        System.out.println(userById == userById1);
    }

在这里插入图片描述

只发出了一个sql语句,并且第二次查询的对象与第一次相同

2.一级缓存失效的4种情况

1.使用不同的sqlsession
  • //使用不同的sqlsession实现一级缓存失效
        @Test
        public void test02() throws IOException {
            SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
            SqlSession sqlSession1 = sqlSessionFactory.openSession();
    
            //sqlsession1
            UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
            User user1 = mapper1.getUserById(1);
            System.out.println(user1);
    
            //sqlsession2
            SqlSession sqlSession2 = sqlSessionFactory.openSession();
            UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
            User user2 = mapper2.getUserById(1);
            System.out.println(user2);
    
            System.out.println(user1 == user2);
        }
    

Mybatis学习笔记_第7张图片

发了两条SQL语句

2.sqlsession相同,查询的条件不同

当前的sqlsession中还没有要查的数据

//相同的sqlsession,不同的条件
    @Test
    public void test03() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();


        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //
        User userById = mapper.getUserById(1);

        //因为2号员工在sqlsession中没有
        User userById1 = mapper.getUserById(2);

    }

在这里插入图片描述

3.两次查询相同数据时,执行了增删改操作

执行了增删改操作就会清除sqlsession中的缓存

//相同的sqlsession,执行力增删改操作就会清除sqlsession的缓存
    @Test
    public void test04() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        SqlSession sqlSession = sqlSessionFactory.openSession();


        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User userById = mapper.getUserById(1);
        mapper.addUser(new User(null,"fanyuning","xinxiang",19991212l));
        sqlSession.commit();
        User userById1 = mapper.getUserById(1);
        System.out.println(userById1 == userById);

    }

Mybatis学习笔记_第8张图片

4.手动清理缓存
sqlSession.clearCache()

2.二级缓存(全局缓存)

基于naespace级别的缓存,一个namespace对应一个二级缓存

工作机制

  1. ​ 一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中

  2. 如果当前会话关闭,一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容

  3. sqlsession === UserMapper ==> User

    ​ OrderMapper ==> Order

    不同的namespace查出的数据会放在自己对应的缓存(map)中

1.体验

  1. 开启全局二级缓存配置

    1. 在全局配置文件中开启二级缓存
      <setting name="cacheEnabled" value="true"/>
      
  2. 去mappere.xml中配置使用二级缓存:

    1. 
      DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      <mapper namespace="com.zhw.cache.mapper.UserMapper">
          //开启二级缓存
          <cache eviction="" >cache>
          <select id="getUserById" resultType="com.zhw.cache.entities.User">
              select * from tb_user where id = #{id};
          select>
      
          <insert id="addUser" parameterType="user">
              insert into tb_user(id,username,address,birthday) values (null ,#{userName},#{address},#{birthday});
          insert>
      mapper>
      
    2. cache的配置

      • Mybatis学习笔记_第9张图片

      • eviction:缓存的回收策略

      • flushInterval:缓存刷新间隔

        • 多长时间清空缓存,默认不清空,设置一个毫秒值

        • flushInterval="60000"
          
      • readOnly:是否只读

        • true:只读
          • mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户,不安全,速度快。
        • false:非只读
          • mybatis觉得获取的数据可能被修改。
          • mybatis会利用反序列化克隆一个新的数据,安全,速度慢
      • size:缓存存放多少元素

      • type:自定义缓存的全类名

    3. 我们的pojo需要实现序列化接口

    4. 测试结果

      • /**
             * 二级缓存
             */
            @Test
            public void testSecondLevelCache() throws IOException {
                SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
                //获取不同的sqlsession
                SqlSession sqlSession1 = sqlSessionFactory.openSession();
                SqlSession sqlSession2 = sqlSessionFactory.openSession();
                //获取mapper代理对象
                UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
                UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        
                //mapper1查询id为1的用户
                User userById = mapper1.getUserById(1);
                System.out.println(userById);
                sqlSession1.close();
                try {
                    //测试 flushInterval="10000"属性
                    
                    Thread.sleep(12000L);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //mapper2查询id为1的用户
                //当不超时的情况下,会从二级缓存中获取数据,并没有发送sql语句
                User userById1 = mapper2.getUserById(1);
                System.out.println(userById1);
                sqlSession2.close();
            }
        

    Mybatis学习笔记_第10张图片

2.注意

  • ​ 数据会先放在一级缓存中
  • 当SQL session关闭了或者提交了才会把数据放到二级缓存

3.二级缓存有关的属性和设置


        <setting name="cacheEnabled" value="false"/>
		1.不会关闭二级缓存,只会关闭二级缓存
		2.一级缓存值即可用

每个select标签都有useCache="true"
		<select id="getUserById" resultType="User" useCache="false">
        1.关闭二级缓存,一级缓存仍然可用
            
每个增删改标签都有flushCache="true"
         <insert flushCache="true" id="addUser" parameterType="user">
        insert into tb_user(id,username,address,birthday) values (null ,#{userName},#{address},#{birthday});
    insert>
        1.就会清除缓存
        2.会清除一级和二级缓存的数据
        3.查询标签的flushCache="false"
            如果设置为true则每次也都会清除一级和二级缓存

2.sqlsession.clearCache()

/**
     * sqlsession.clearCache()
     * 是否清除二级缓存
     * @throws IOException
     */
    @Test
    public void testSecondLevelCache3() throws IOException {
        SqlSessionFactory sqlSessionFactory = getSqlSessionFactory();
        //获取不同的sqlsession
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        //获取mapper代理对象
        UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
        UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
        //mapper1查询id为1的用户
        User userById = mapper1.getUserById(1);
        System.out.println(userById);
        sqlSession1.close();
        //只会清除对应的sqlsession中的一级缓存
        //不会对二级缓存有影响
        sqlSession2.clearCache();
        //mapper2查询id为1的用户
        User userById1 = mapper2.getUserById(1);
        System.out.println(userById1);
        sqlSession2.close();
    }

3.localCacheScope:本地缓存作用域

localCacheScope = STATEMENT 时会禁用一级缓存(没人去设置它)

4.缓存工作原理

Mybatis学习笔记_第11张图片

配置日志

1.添加依赖

 <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>

2.日志配置文件

# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE            debug   info   warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE

# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE

# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:/axis.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r [%15.15t] %-5p %30.30c %x - %m\n

3.开启配置

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

4.结果
Mybatis学习笔记_第12张图片

你可能感兴趣的:(mybatis,mybatis)