MyBatis(二)

MyBatis(二)

8 ResultMap(结果集映射)

resultMap用于替换resultType,在创建的实体类中的字段/属性名和数据库中的字段/属性名不一致的情况下使用。当实体类和数据库中的字段/属性名不一致时,SQL语句的查询结果会返回不一致的字段值为null,此时需要使用resultMap进行字段/属性名映射,使不一致的字段/属性名相互匹配,而非使用resultType。

8.1 resultType

resultType只是简单地将所有的列映射到HashMap的键上。即:

JavaBean(实体类)

package com.pojo;
public class User {
  private int id;
  private String username;
  private String password;

  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String password() {
    return password;
  }
  public void password(String password) {
    this.password = password;
  }
}

mybatis-config配置文件

<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultType="map">
  select id, username, password
  from some_table
  where id = #{id}
</select>

MyBatis 会在幕后自动创建一个ResultMap,自动将列名与JavaBean中相同的属性名相互映射。即:

  xml			id      username      password
   |      		|			|			  |
   |	 		|			|			  |
JavaBean		id      username	  password

如果列名和属性名没有精确匹配,可以在 SELECT 语句中对列使用别名(这是一个基本的 SQL 特性)来匹配标签。如下:

<select id="selectUsers" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "password"
  from some_table
  where id = #{id}
</select>

8.2 resultMap

ResultMap可以自己在mybatis-config配置文件中使用resultMap标签进行配置,而不需要在SQL语句中对列使用别名。

<!--结果集映射-->
<resultMap id="userResultMap" type="User">
  <!--property实体类中的属性,column数据库中的字段-->
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>
<!--select标签中的resultMap通过上面resultMap标签中的id来选择指定-->
<select id="selectUsers" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

当只有部分字段不匹配时,只需配置部分字段的映射即可!

    User{id,username,password}
DataBase{id,username,pwd}

mybatis-config.xml

<!--结果集映射-->
<resultMap id="userResultMap" type="User">
  <!--property实体类中的属性,column数据库中的字段-->
  <result property="password" column="pwd"/>
</resultMap>
<!--select标签中的resultMap通过上面resultMap标签中的id来选择指定-->
<select id="selectUsers" resultMap="userResultMap">
  select id, username, pwd
  from some_table
  where id = #{id}
</select>

9 分页

9.1 Limit实现分页

MyBatis中使用limit实现分页只需要修改三个部分:Mapper接口、Mapper.xml配置文件以及测试类

  1. 在Mapper接口中定义方法
  2. 在Mapper.xml配置文件实现SQL语句
  3. 编写测试类
9.1.1 Mapper接口

在Mapper接口中定义方法

package com.dao;

import com.pojo.User;
import java.util.List;
import java.util.Map;

public interface UserMapper {
    List<User> getUserByLimit(Map<String,Integer> map);
}

9.1.2 Mapper.xml配置文件

在Mapper.xml配置文件实现SQL语句

<select id="getUserByLimit" parameterType="map" resultType="com.pojo.User">
    select * from mybatis.user limit #{startIndex}, #{size};
</select>
9.1.3 编写测试类
package com.dao;

import com.pojo.User;
import com.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserMapperTest {
    @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",0);
        map.put("size",2);
        List<User> userList = mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

9.2 RowBounds

狂神说Java—MyBatis—14.RowBounds分页

10 注解

对于简单的语句建议使用注解开发,但是对于复杂的语句还是使用xml配置文件配置!

10.1 自动提交事务

在工具类中设置自动提交事务

package com.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.IOException;
import java.io.InputStream;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession(true);
    }
}

10.2 使用注解实现CRUD(只针对简单的SQL语句)

只需要修改Mapper接口和测试类,甚至不需要Mapper.xml配置文件(但是mybatis-config配置文件仍旧需要,并且需要绑定接口!)

10.2.1 Mapper接口
package com.dao;
import com.pojo.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
import java.util.Map;
public interface UserMapper {
    //查询所有学生
    @Select("select * from user")
    List<User> getUserList();
    //根据学号查询学生
    @Select("select * from user where id = #{id}")
    User getUser(int id);
    //根据学号删除学生
    @Delete("delete from mybatis.user where id = #{id};")
    void deleteUser(int id);
    //插入一条学生信息
    @Insert("insert into mybatis.user (id, name, pwd) values (#{id}, #{name}, #{pwd});")
    void addUser(User user);
    //更新一条学生信息
    @Update("update mybatis.user set name = #{name}, pwd = #{pwd} where id = #{id};")
    void updateUser(User user);
}
10.2.2 mybatis-config配置文件
<mappers>
    <mapper class="com.dao.UserMapper"></mapper>
</mappers>
10.2.3 测试类

10.3 Lombok的使用

使用步骤:

  1. 在IDEA中添加Lombok的插件

    File——>Settings——>Plugins——>搜索框搜索

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

    <!--导入Lombok插件的jar包-->
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
    </dependency>
    

    注意:

    直接从Maven上复制的Lombok依赖为

    <!--导入Lombok插件的jar包-->
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.10</version>
        <scope>provided</scope>
    </dependency>
    

    规定了作用域,删掉最后一句才能正常使用

  3. 在实体类上添加注解

    package com.pojo;
    
    import lombok.Data;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructorpublic class User {
        private int id;
        private String name;
        private String pwd;
    }
    

    使用上述三个注解可以无需再写构造函数、getter和setter方法以及toString方法!

11 复杂查询

本质:复杂的结果集映射

举例:一个老师有多个学生

对于学生而言,多个学生关联一个老师————>多对一,使用关联描述之间的关系(association)

对于老师而言,一个老师有多个学生的集合————>一对多,使用集合描述之间的关系(collection)

11.1 多对一处理

11.1.1 环境搭建
11.1.1.1 数据库建表
//创建teacher表
CREATE TABLE `teacher` (
	`id`	INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
//插入一条teacher信息
INSERT INTO teacher(`id`,`name`) VALUES(1,'秦老师');
//创建student表,绑定外键为teacher的id
CREATE TABLE `student` (
	`id`	INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	`tid`	INT(10) DEFAULT NULL,
	PRIMARY KEY (`id`),
	KEY `fktid`	(`tid`),
	CONSTRAINT `fktid`	FOREIGN KEY (`tid`)	REFERENCES	`teacher`	(`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
//插入5条学生信息
INSERT INTO student(`id`,`name`,`tid`) VALUES('1','xiaoming','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('2','xiaohong','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('3','xiaolan','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('4','xiaolv','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('5','xiaohuang','1');
11.1.1.2 新建项目
  • 根据数据库表建立对应实体类

    Student表

    package com.pojo;
    
    import lombok.Data;
    
    @Data
    public class Student {
        private int id;
        private String name;
        //关联老师
        private Teacher teacher;
    }
    

    Teacher表

    package com.pojo;
    
    import lombok.Data;
    
    @Data
    public class Teacher {
        private int id;
        private String name;
    }
    
  • 编写对应Mapper接口

    TeacherMapper

    package com.dao;
    
    import com.pojo.Teacher;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    public interface TeacherMapper {
        @Select("select * from teacher where id = #{id}")
        Teacher getTeacher(@Param("id") int id);
    }
    

    StudentMapper

    package com.dao;
    
    public interface StudentMapper {
    }
    
  • 编写对应Mapper.xml文件

    TeacherMapper.xml

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

    StudentMapper.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.dao.StudentMapper">
    
    </mapper>
    
  • 编写mybatis-config.xml配置文件

    <?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 resource="db.properties"></properties>
        <typeAliases>
    <!--        <typeAlias type="com.pojo.User" alias="user"></typeAlias>-->
            <package name="com.pojo"/>
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC" />
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper class="com.dao.TeacherMapper"/>
            <mapper class="com.dao.StudentMapper"/>
        </mappers>
    </configuration>
    
  • 编写测试类

    测试是否可以查询到老师

    import com.dao.TeacherMapper;
    import com.pojo.Teacher;
    import com.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    
    public class MyTest {
        public static void main(String[] args) {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            Teacher teacher = mapper.getTeacher(1);
            System.out.println(teacher);
            sqlSession.close();
        }
    }
    
11.1.1.2 需求解决

需求:查询所有的学生信息及对应老师的信息

SQL语句:select s.id,s.name,t.name from student s, teacher t where s.tid = t.id;

  • 在对应Mapper类中编写需求方法

    package com.dao;
    
    import com.pojo.Student;
    
    import java.util.List;
    
    public interface StudentMapper {
        //查询所有的学生信息及对应老师的信息
        List<Student> getStudent();
    }
    
  • 编写对应Mapper.xml配置文件(StudentMapper.xml)

    单纯的SQL语句好写,但是xml配置文件中不允许。

    思路:

    1. 查询所有学生的信息
    2. 根据查询出来学生的tid寻找对应老师的信息
    1. 根据结果嵌套处理(推荐使用,较为简单)————对应MySQL中的联表查询

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.dao.StudentMapper">
          <select id="getStudent" resultMap="getStudentAndTeacher">
              select s.id sid,s.name sname,t.name tname
            from student s, teacher t
              where s.tid = t.id;
          </select>
          <!--本质依旧为解决结果集映射问题-->
          <resultMap id="getStudentAndTeacher" type="Student">
              <!--将Java类中的属性映射为对应数据库中的列名-->
              <result property="id" column="sid"/>
              <result property="name" column="sname"/>
              <!--复杂的属性单独处理
                  多对一的情况使用关联 association
                  一对多的情况使用集合 collection   -->
              <association property="teacher" javaType="Teacher">
                  <!--teacher是一个类,类中的属性再映射-->
                  <result property="name" column="tname"/>
              </association>
          </resultMap>
      </mapper>
      
    2. 根据查询嵌套处理————对应MySQL中的子查询

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper
           PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.dao.StudentMapper">
          <!--方式一:根据查询嵌套查询,相当于子查询-->
          <select id="getStudent" resultMap="getStudentAndTeacher">
              select * from student ;
          </select>
          <!--此时查出来的teacher一列为null,所以本质还是解决结果映射问题,即解决teacher属性映射-->
          <resultMap id="getStudentAndTeacher" type="Student">
              <!--id:一般表示主键    result:万能(主键也可以)   -->
              <result property="id" column="id"/>
              <!--上面写成<id property="id" column="id"/>也可以,因为是主键-->
              <result property="name" column="name"/>
              <!--复杂的属性单独处理
              多对一的情况使用关联 association
              一对多的情况使用集合 collection   -->
              <association property="teacher" javaType="Teacher" column="tid" select="getTeacher"/>
              <!--teacher属性对应数据库中的tid列。
              因为teacher属性是一个Java类,需要指定javaType。
              然后用一个id为getTeacher的查询语句在teacher类中根据tid查询对应teacher信息-->
          </resultMap>
          <select id="getTeacher" resultType="Teacher">
              select * from mybatis.teacher where id = #{tid};
          </select>
      </mapper>
      
  • 编写测试类

    @Test
    public void testStudent(){
        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();
    }
    
    /**
    Out:
    Student(id=1, name=xiaoming, teacher=Teacher(id=1, name=秦老师))
    Student(id=2, name=xiaohong, teacher=Teacher(id=1, name=秦老师))
    Student(id=3, name=xiaolan, teacher=Teacher(id=1, name=秦老师))
    Student(id=4, name=xiaolv, teacher=Teacher(id=1, name=秦老师))
    Student(id=5, name=xiaohuang, teacher=Teacher(id=1, name=秦老师))
    **/
    

11.2 一对多处理

11.2.1 环境搭建
11.2.1.1 数据库建表
//创建teacher表
CREATE TABLE `teacher` (
	`id`	INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
//插入一条teacher信息
INSERT INTO teacher(`id`,`name`) VALUES(1,'秦老师');
//创建student表,绑定外键为teacher的id
CREATE TABLE `student` (
	`id`	INT(10) NOT NULL,
	`name` VARCHAR(30) DEFAULT NULL,
	`tid`	INT(10) DEFAULT NULL,
	PRIMARY KEY (`id`),
	KEY `fktid`	(`tid`),
	CONSTRAINT `fktid`	FOREIGN KEY (`tid`)	REFERENCES	`teacher`	(`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8
//插入5条学生信息
INSERT INTO student(`id`,`name`,`tid`) VALUES('1','xiaoming','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('2','xiaohong','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('3','xiaolan','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('4','xiaolv','1');
INSERT INTO student(`id`,`name`,`tid`) VALUES('5','xiaohuang','1');
11.2.1.2 新建项目
  • 根据数据库表建立对应实体类

    Student表

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

    Teacher表

    package com.pojo;
    
    import lombok.Data;
    
    @Data
    public class Teacher {
        private int id;
        private String name;
        private List<Student> students;
    }
    
  • 编写对应Mapper接口

    TeacherMapper

    package com.dao;
    
    import com.pojo.Student;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    public interface TeacherMapper {
        @Select("select * from teacher")
        Teacher getTeacher();
    }
    

    StudentMapper

    package com.dao;
    
    public interface StudentMapper {
    }
    
  • 编写对应Mapper.xml文件

    TeacherMapper.xml

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

    StudentMapper.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.dao.StudentMapper">
    </mapper>
    
  • 编写mybatis-config.xml配置文件

    <?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 resource="db.properties"></properties>
        <typeAliases>
    <!--        <typeAlias type="com.pojo.User" alias="user"></typeAlias>-->
            <package name="com.pojo"/>
        </typeAliases>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC" />
                <dataSource type="POOLED">
                    <property name="driver" value="${driver}"/>
                    <property name="url" value="${url}"/>
                    <property name="username" value="${username}"/>
                    <property name="password" value="${password}"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper class="com.dao.TeacherMapper"/>
            <mapper class="com.dao.StudentMapper"/>
        </mappers>
    </configuration>
    
  • 编写测试类

    测试是否可以查询到老师

    import com.dao.TeacherMapper;
    import com.pojo.Teacher;
    import com.utils.MybatisUtils;
    import org.apache.ibatis.session.SqlSession;
    
    public class MyTest {
        public static void main(String[] args) {
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
            List<Teacher> teacherList = mapper.getTeacher();
            for(Teacher teacher : teacherList){
            	System.out.println(teacher);    
            } 
            sqlSession.close();
        }
    }
    
11.2.2 需求解决

需求:查询指定老师下的所有学生及老师信息

SQL语句:select s.id sid,s.name sname,t.name tname,t.id tid from student s, teacher t where s.tid = t.id;

  • 在对应Mapper类中编写需求方法

    package com.dao;
    
    import com.pojo.Teacher;
    
    import java.util.List;
    
    public interface TeacherMapper {
        //查询所有的学生信息及对应老师的信息
        List<Teacher> getTeacher(@Param("id") int id);
    }
    
  • 编写对应Mapper.xml配置文件(TeacherMapper.xml)

    单纯的SQL语句好写,但是xml配置文件中不允许。

    思路:

    1. 查询所有学生的信息
    2. 根据查询出来学生的tid寻找对应老师的信息
    1. 根据结果嵌套处理(推荐使用,较为简单)————对应MySQL中的联表查询

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.dao.TeacherMapper">
          <select id="getTeacher" resultMap="TeacherStudent">
              select s.id sid, s.name sname, t.name tname, t.id tid
              from mybatis.teacher t,mybatis.student s
              where s.tid = t.id and t.id = #{tid};
          </select>
          <!--本质依旧为解决结果集映射问题-->
          <resultMap id="TeacherStudent" type="Teacher">
              <result column="tid" property="id"/>
              <result property="name" column="tname"/>
              <!--复杂的属性单独处理
                  多对一的情况使用关联 association
                  一对多的情况使用集合 collection   -->
              <!--集合中的泛型用ofType获取而不使用javaType-->
              <collection property="students" ofType="Student">
                  <result property="id" column="sid"/>
                  <result property="name" column="sname"/>
                  <result property="tid" column="tid"/>
              </collection>
          </resultMap>
      </mapper>
      
    2. 根据查询嵌套处理————对应MySQL中的子查询

      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
      
      <mapper namespace="com.dao.TeacherMapper">
      	<select id="getTeacher2" resultMap="TeacherStudent2">
              select * from mybatis.teacher where id = #{tid2};
          </select>
          <select id="getStudentList" resultType="Student">
              select * from mybatis.student where tid = #{tid2};
          </select>
          <resultMap id="TeacherStudent2" type="Teacher">
              <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentList" column="id">
              </collection>
          </resultMap>
      </mapper>
      
  • 编写测试类

    @Test
    public void testTeacher(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
        Teacher teacher = mapper.getTeacher(1);
        System.out.println(teacher);
        sqlSession.close();
    }
    
    /**
    Out:
    Teacher(id=0, name=秦老师, students=[Student(id=1, name=xiaoming, tid=1), Student(id=2, name=xiaohong, tid=1), Student(id=3, name=xiaolan, tid=1), Student(id=4, name=xiaolv, tid=1), Student(id=5, name=xiaohuang, tid=1)])
    **/
    

面试高频:

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

12 动态SQL

动态SQL:根据不同的条件生成不同的SQL语句

动态 SQL 元素和 JSTL 或基于类似 XML 的文本处理器相似。在 MyBatis 之前的版本中,有很多元素需要花时间了解。MyBatis 3 大大精简了元素种类,现在只需学习原来一半的元素便可。MyBatis 采用功能强大的基于 OGNL 的表达式来淘汰其它大部分元素。

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

12.1 环境搭建

12.1.1 数据库环境搭建
CREATE TABLE `blog` (
	`id` VARCHAR(50) NOT NULL COMMENT '博客id',
	`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
	`author` VARCHAR(100) NOT NULL COMMENT '博客作者',
	`create_time` datetime NOT NULL COMMENT '创建时间',
	`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8
12.1.2 创建项目
  • 编写数据库对应的实体类

    package com.pojo;
    
    import lombok.Data;
    import java.util.Date;
    
    @Data
    public class Blog {
        private String id;
        private int views;
        private String title;
        private String author;
        private Date createTime;	//属性名和字段名不一致(数据库中是create_time)
    }
    

    MyBatis中解决属性名和字段名不一致的方法:

    在mybatis-config配置文件中的setting标签的mapUnderscoreToCamelCase属性为true

    mapUnderscoreToCamelCase:是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。默认为False。

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

    开启之后可将数据库中的字段名create_time映射为Java类中的属性名createTime。

  • 编写实体类对应的Mapper

    package com.dao;
    public interface BlogMapper {
    }
    
  • 编写Mapper对应的xml文件

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.dao.BlogMapper">
    </mapper>
    
12.1.3 添加数据
  • 编写实体类对应Mapper的方法

    package com.dao;
    public interface BlogMapper {
        //插入数据
        void addBlog(Blog blog);
    }
    
  • 插入数据

    //插入数据
    @Test
    public void addTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    
        Blog blog = new Blog();
        blog.setId(IDUtils.getID());
        blog.setAuthor("IU");
        blog.setTitle("You And I");
        blog.setCreateTime(new Date());
        blog.setViews(10000);
        mapper.addBlog(blog);
    
        blog.setId(IDUtils.getID());
        blog.setAuthor("IU");
        blog.setTitle("Good Day");
        blog.setCreateTime(new Date());
        blog.setViews(12000);
        mapper.addBlog(blog);
    
        blog.setId(IDUtils.getID());
        blog.setAuthor("IU");
        blog.setTitle("Blueming");
        blog.setCreateTime(new Date());
        blog.setViews(10000);
        mapper.addBlog(blog);
    
        blog.setId(IDUtils.getID());
        blog.setAuthor("IU");
        blog.setTitle("BBIBBI");
        blog.setCreateTime(new Date());
        blog.setViews(10000);
        mapper.addBlog(blog);
    
        sqlSession.close();
    }
    

12.2 trim(where、set)

  • where标签

    
    
  • set标签

    
    

12.3 if

if


12.4 choose···when···otherwise

choose···when···otherwise类似于Java中的switch···case···default语句


12.5 foreach

13 缓存

13.1 缓存简介

13.1.1 什么是缓存(Cache)
  • 存在内存中的临时数据
  • 将用户经常查询的数据存放在缓存(内存)中,用户查询数据时就不用从磁盘上(关系型数据库数据文件)查找,而是从缓存中查找,从而提高了查询效率。解决了高并发系统的性能问题
13.1.2 为什么使用缓存
  • 减少和数据库的交互次数,减少系统开销,提高系统效率
13.1.3 什么样的数据适合使用缓存
  • 经常查询且不经常改变的数据

13.2 MyBatis缓存

  • MyBatis 内置了一个强大的事务性查询缓存机制,它可以非常方便地配置和定制
  • MyBatis系统默认定义了两级缓存:一级缓存二级缓存
    • 默认情况下,只有一级缓存开启
    • 一级缓存,基于SqlSession级别的缓存(随SqlSession的close而关闭),也称为本地缓存
    • 二级缓存需要手动开启和配置,是基于namespace级别的缓存(在绑定接口中的所有方法中都可以使用)
    • 为了提高可扩展性,MyBatis定义了缓存接口Cache。可以通过实现Cache接口来自定义二级缓存(也只能定义二级缓存)
13.2.1 一级缓存
  • 一级缓存也叫做本地缓存:

    • 与数据库同一次会话期间查询到的数据会放到本地缓存中
    • 以后如果需要获取相同的数据,直接从缓存中拿,不必再查询数据库
  • 一级缓存失效的情况:

    • 查询不同的东西

    • 增删改操作都会失效!(增删改操作会改变原来的数据,所以会刷新缓存)

    • 查询不同的Mapper.xml

    • 手动清理缓存(SqlSession有一个clearCache方法用来清理缓存)

      SqlSession.clearCache();
      
13.2.2 二级缓存
  • 二级缓存也叫全局缓存,由于一级缓存的作用域过低,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间对应一个二级缓存
  • 工作机制
    1. 一个会话查询一条数据,这条数据就会被放在当前会话的一级缓存中
    2. 如果当前会话关闭了,这个会话对应的一级缓存也会消失。开启二级缓存后,一级缓存中的数据会放入二级缓存中
    3. 新的会话查询信息就可以从二级缓存中获取数据
    4. 不同的Mapper查出的数据会放在自己对应的缓存中

使用步骤:

  • 开启全局缓存

    在mybatis-config核心配置文件中使用setting标签

    <!--开启全局缓存-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  • 使用二级缓存

    在Mapper.xml配置文件中添加cache标签

    • 使用默认的二级缓存

      <cache/>
      
    • 使用配置的二级缓存

      通过cache元素的属性来自配置二级缓存

      <cache
        eviction="FIFO"
        flushInterval="60000"
        size="512"
        readOnly="true"/>
      <!--该配置创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的-->
      
      1. 可用的清除策略有:

        • LRU – 最近最少使用:移除最长时间不被使用的对象。
        • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
        • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
        • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

        默认的清除策略是 LRU

      2. flushInterval(刷新间隔)属性可以被设置为任意的正整数,设置的值应该是一个以毫秒为单位的合理时间量。 默认情况是不设置,也就是没有刷新间隔,缓存仅仅会在调用语句时刷新。

      3. size(引用数目)属性可以被设置为任意正整数,要注意欲缓存对象的大小和运行环境中可用的内存资源。默认值是 1024。

      4. readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。

小结:

  • 只要开启了二级缓存,在同一个Mapper下就有效
  • 所有的数据会被先放在一级缓存中
  • 只有当会话提交或会话关闭时,才会将一级缓存中的数据放入二级缓存中(将一级缓存中的数据转存入二级缓存)
13.2.3 自定义缓存(了解即可)

视频30

一般使用Redis!

13.2.4 MyBatis的缓存原理

执行SQL查询语句时:

  • 先看二级缓存中有没有
  • 再看一级缓存中有没有
  • 最后再在数据库中查询
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值