Mybatis学习笔记3

81 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第7天,点击查看活动详情

使用注解开发

1.面向接口编程

真正的开发中,很多时候我们会选择面向接口编程

根本原因:解耦,可拓展,提高利用,分层开发中,上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性更好

关于接口的理解

  • 接口从更深层次的理解,就是定义(规范,约束)与实现(名实分离的原则)的分离。

  • 接口的本身反映了系统设计人员对系统的抽象理解。

  • 接口就有两类:

    • 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class)
    • 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface)
  • 一个体有可能 有多个抽象面。抽象体与抽象面是有区别的

2.使用注解开发

新建项目mybatis-05

复制如下包:

image-20210811111343855.png

mybatis-config.xml中删除mapper,setting改成标准的日志工厂实现

  1. 注解在接口上实现

         @Select("select * from user")
         List<User> getUsers();
    
  2. 需要在核心配置文件中绑定接口

         <mappers>
             <mapper class="com.isabella.dao.UserMapper"></mapper>
         </mappers>
    
  3. 测试

     @Test
         public void test(){
            SqlSession sqlsession = MybatisUtils.getSqlsession();
            //底层主要应用反射
            UserMapper mapper = sqlsession.getMapper(UserMapper.class);
     ​
            List<User> users = mapper.getUsers();
            for (User user : users) {
                System.out.println(user);
            }
     ​
     ​
            sqlsession.close();
        }
    

本质:反射机制实现

底层:动态代理

image.png

Mybatis执行流程剖析

注解增删改查

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

MybatisUtils.java(修改):

 return sqlSessionFactory.openSession(true);

编写接口,增加注解

UserMapper.java:

 package com.isabella.dao;
 ​
 import com.isabella.pojo.User;
 import org.apache.ibatis.annotations.*;
 ​
 import java.util.List;
 ​
 public interface UserMapper {
     @Select("select * from user")
     List<User> getUsers();
 ​
     @Select("select * from user where id = #{id}")
     User getUserById(@Param("id")int id);
 ​
     @Insert("insert into user (id,name,pwd) values (#{id},#{name},#{pwd})")
     int addUser(User user);
 ​
     @Update("update user set name=#{name},pwd=#{pwd} where id=#{id}")
     int updateUser(User user);
 ​
     @Delete("delete from user where id=#{id}")
     int deleteUser(@Param("id") int id);
 ​
 }

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

UserMapperTest.java:

        //查询所有用户
        List<User> users = mapper.getUsers();
        for (User user : users) {
            System.out.println(user);
        }
        //根据id查询用户
        User user = mapper.getUserById(1);
        System.out.println(user);
        //添加用户
        mapper.addUser(new User(7,"Hello","12345"));
        //修改用户
        mapper.updateUser(new User(7,"World","12333"));
        //删除用户
        mapper.deleteUser(7);

关于@Param()注解

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

#{} 与 ${} 的区别

#{}可以防止注入

复杂查询环境搭建

多对一:

  • 多个学生,对应一个老师
  • 对于学生而言,多个学生关联一个老师【多对一】
  • 对于老师而言,集合,一个老师,有很多学生【一对多】

SQL:

 CREATE TABLE `teacher` (
   `id` INT(10) NOT NULL,
   `name` VARCHAR(30) DEFAULT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE=INNODB DEFAULT CHARSET=utf8;
 ​
 INSERT INTO teacher(`id`, `name`) VALUES (1, "秦老师"); 
 ​
 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;
 INSERT INTO `student` (`id`, `name`, `tid`) VALUES (1, "小明", 1);
 INSERT INTO `student` (`id`, `name`, `tid`) VALUES (2, "小红", 1);
 INSERT INTO `student` (`id`, `name`, `tid`) VALUES (3, "小张", 1);
 INSERT INTO `student` (`id`, `name`, `tid`) VALUES (4, "小李", 1);
 INSERT INTO `student` (`id`, `name`, `tid`) VALUES (5, "小王", 1);

测试环境搭建

  1. 新建实体类Teacher,Student

    Teacher.java:

     package com.isabella.pojo;
     ​
     public class Teacher {
         private int id;
         private String name;
     ​
         public Teacher() {
         }
     ​
         public Teacher(int id, String name) {
             this.id = id;
             this.name = name;
         }
     ​
         public int getId() {
             return id;
         }
     ​
         public void setId(int id) {
             this.id = id;
         }
     ​
         public String getName() {
             return name;
         }
     ​
         public void setName(String name) {
             this.name = name;
         }
     ​
         @Override
         public String toString() {
             return "Teacher{" +
                     "id=" + id +
                     ", name='" + name + ''' +
                     '}';
         }
     }
     ​
    

    Student.java:

     package com.isabella.pojo;
     ​
     public class Student {
         private int id;
         private String name;
     ​
         //学生需要关联一个老师
         private Teacher teacher;
     ​
         public Student() {
         }
     ​
         public Student(int id, String name, Teacher teacher) {
             this.id = id;
             this.name = name;
             this.teacher = teacher;
         }
     ​
         public int getId() {
             return id;
         }
     ​
         public void setId(int id) {
             this.id = id;
         }
     ​
         public String getName() {
             return name;
         }
     ​
         public void setName(String name) {
             this.name = name;
         }
     ​
         public Teacher getTeacher() {
             return teacher;
         }
     ​
         public void setTeacher(Teacher teacher) {
             this.teacher = teacher;
         }
     ​
         @Override
         public String toString() {
             return "Student{" +
                     "id=" + id +
                     ", name='" + name + ''' +
                     ", teacher=" + teacher +
                     '}';
         }
     }
     ​
    
  2. 建立Mapper接口

    TeacherMapper.java:

     package com.isabella.dao;
     ​
     import com.isabella.pojo.Teacher;
     ​
     public interface TeacherMapper {
         Teacher getTeacher(int id);
     }
     ​
    

    StudentMapper.java:

     package com.isabella.dao;
     ​
     public interface StudentMapper {
     }
    
  3. 建立 Mapper.xml文件

image-20210812114341587.png

TeacherMapper.xml:

```
 <?xml version="1.0" encoding="UTF8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.isabella.dao.TeacherMapper">
 ​
     <select id="getTeacher" parameterType="int" resultType="com.isabella.pojo.Teacher">
         select * from mybatis.teacher where id = #{id};
     </select>
 </mapper>
```

StudentMapper.xml:

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

0. 在核心配置文件中绑定注册我们的Mapper接口或文件【方式很多,随心选】

```
 <mappers>
     <mapper resource="com/isabella/dao/TeacherMapper.xml"/>
 </mappers>
```

0. 测试查询是否成功

TeacherMapperTest.java:

```
 package com.isabella.dao;
 ​
 ​
 import com.isabella.pojo.Teacher;
 import com.isabella.utils.MybatisUtils;
 import org.apache.ibatis.session.SqlSession;
 import org.junit.Test;
 ​
 public class TeacherMapperTest {
 ​
     @Test
     public void test(){
         SqlSession sqlsession = MybatisUtils.getSqlsession();
         TeacherMapper mapper = sqlsession.getMapper(TeacherMapper.class);
 ​
         Teacher teacher = mapper.getTeacher(1);
         System.out.println(teacher);
 ​
         sqlsession.close();
 ​
     }
 ​
 }
 ​
```

# 多对一的处理

SQL中联表查询

 select s.id,s.name , t.name from student s, teacher t where s.tid=t.id;

按照查询嵌套处理

StudentMapper.xml:

 <?xml version="1.0" encoding="UTF8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.isabella.dao.StudentMapper">
 ​
     <!--
         思路:
             1.查询所有的学生信息
             2.根据查询出来的学生的tid,寻找对应的老师
     -->
     <select id="getStudent" resultMap="StudentTeacher">
         select * from mybatis.student
     </select>
     
     <resultMap id="StudentTeacher" type="Student">
         <result property="id" column="id"/>
         <result property="name" column="name"/>
         <!--复杂的属性,我们需要单独处理
             对象:association
             集合:collection
         -->
         <association property="teacher" column="tid" javaType="Teacher" select="getTeacherById"/>
     </resultMap>
     
     <select id="getTeacherById" resultType="Teacher">
         select * from 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();
 }

按照结果嵌套处理

StudentMapper.java:

 List<Student> getStudent2();

StudentMapper.xml

     <!--按照结果嵌套处理-->
     <select id="getStudent2" resultMap="StudentTeacher2">
         select s.id sid,s.name sname,t.name tname
         from mybatis.student s , mybatis.teacher t
         where s.tid = t.id;
     </select>
     <resultMap id="StudentTeacher2" type="Student">
         <result property="id" column="sid"/>
         <result property="name" column="sname"/>
         <association property="teacher" javaType="Teacher">
             <result property="name" column="tname"/>
         </association>
     </resultMap>

测试类:

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

一对多的处理

比如:一个老师拥有多个学生

对于老师而言,就是一对多的关系

环境搭建

Student.java:

 package com.isabella.pojo;
 ​
 public class Student {
     private int id;
     private String name;
 ​
     //学生需要关联一个老师
     private int tid;
 ​
     public Student() {
     }
 ​
     public Student(int id, String name, int tid) {
         this.id = id;
         this.name = name;
         this.tid = tid;
     }
 ​
     public int getId() {
         return id;
     }
 ​
     public void setId(int id) {
         this.id = id;
     }
 ​
     public String getName() {
         return name;
     }
 ​
     public void setName(String name) {
         this.name = name;
     }
 ​
     public int getTid() {
         return tid;
     }
 ​
     public void setTid(int tid) {
         this.tid = tid;
     }
 ​
     @Override
     public String toString() {
         return "Student{" +
                 "id=" + id +
                 ", name='" + name + ''' +
                 ", tid=" + tid +
                 '}';
     }
 }
 ​

Teacher.java:

 package com.isabella.pojo;
 ​
 import java.util.List;
 ​
 public class Teacher {
     private int id;
     private String name;
 ​
     //一个老师拥有多个学生
     private List<Student> students;
 ​
     public Teacher() {
     }
 ​
     public Teacher(int id, String name, List<Student> students) {
         this.id = id;
         this.name = name;
         this.students = students;
     }
 ​
     public int getId() {
         return id;
     }
 ​
     public void setId(int id) {
         this.id = id;
     }
 ​
     public String getName() {
         return name;
     }
 ​
     public void setName(String name) {
         this.name = name;
     }
 ​
     public List<Student> getStudents() {
         return students;
     }
 ​
     public void setStudents(List<Student> students) {
         this.students = students;
     }
 ​
     @Override
     public String toString() {
         return "Teacher{" +
                 "id=" + id +
                 ", name='" + name + ''' +
                 ", students=" + students +
                 '}';
     }
 }

按照结果嵌套处理

TeacherMapper.java:

 //获取指定老师下的所有学生及老师的信息
 Teacher getTeacher(int tid);

TeacherMapper.xml:

 <?xml version="1.0" encoding="UTF8" ?>
 <!DOCTYPE mapper
         PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.isabella.dao.TeacherMapper">
 ​
     <!--按结果嵌套查询-->
     <select id="getTeacher" resultMap="TeacherStudent">
         select s.id sid,s.name sname,t.name tname, t.id tid
         from mybatis.student s,mybatis.teacher t
          where s.tid = t.id and t.id = #{tid}
     </select>
 ​
     <resultMap id="TeacherStudent" type="Teacher">
         <result property="id" column="tid"/>
         <result property="name" column="tname"/>
         <!--
         javaType=""指定属性的类型
         集合中的泛型信息,我们使用ofType获取
         -->
         <collection property="students" ofType="Student">
             <result property="id" column="sid"/>
             <result property="name" column="sname"/>
             <result property="tid" column="tid"/>
         </collection>
     </resultMap>
 ​
 </mapper>
  1. 测试类

    MyTest.java:

     @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();
         }
    

按照查询嵌套处理

TeacherMapper.java:

 Teacher getTeacher2(int tid);

TeacherMapper.xml:

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

MyTest.java:

     @Test
     public void testTeacher(){
         SqlSession sqlsession = MybatisUtils.getSqlsession();
         TeacherMapper mapper = sqlsession.getMapper(TeacherMapper.class);
 ​
         Teacher teacher = mapper.getTeacher2(1);
         System.out.println(teacher);
 ​
 ​
         sqlsession.close();
     }

小结

  1. 关联 - association 【多对一】

  2. 集合 - collection 【一对多】

  3. javaType & ofType

    1. javaType用来指定实体类中属性的类型
    2. ofType用来指定映射到List或集合中的pojo类型,泛型中的约束类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果问题不好排查错误,可以使用日志,建议使用Log4j

尽量避免慢SQL

面试高频

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