Mybatis学习笔记

Mybtais框架

参考资料

mybatis官方文档

狂神说Mybatis最新完整教程IDEA版

1.简介

1.1什么是 MyBatis?

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.2Mybatis的优点

  1. 便于维护管理,基于 SQL 语句编程,相当灵活;

  2. 很好的与各种数据库兼容

1.2Mybatis的缺点

  1. 数据库移植性差, 不能随意更换数据库。

2.第一个Mybatis程序

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

2.1搭建环境

2.1.1搭建数据库
2.1.2新建项目
1.准备工作
  • 下载安装Maven

  • 配置maven系统环境变量(配置好环境变量,进入cmd,输入mvn -version,若成功出现版本信息,则环境变量配置成功。)

在这里插入图片描述
在这里插入图片描述

  • 配置maven的settings.xml文件

    1.修改maven默认的仓库

    大致49–63行

    <!-- localRepository
       | The path to the local repository maven will use to store artifacts.
       |
       | Default: ${user.home}/.m2/repository
      <localRepository>/path/to/local/repo</localRepository>
      -->
      <localRepository>D:/JavaSourceProgram/Maven</localRepository>
      <!-- interactiveMode
       | This will determine whether maven prompts you when it needs input. If set to false,
       | maven will use a sensible default value, perhaps based on some other setting, for
       | the parameter in question.
       |
       | Default: true
      <interactiveMode>true</interactiveMode>
      -->
    
    

    2.修改服务器

    大致152–166行

    <mirror>
          <id>mirrorId</id>
          <mirrorOf>repositoryId</mirrorOf>
          <name>Human Readable Name for this Mirror.</name>
          <url>http://my.repository.com/repo/path</url>
        </mirror>
         -->
    	 <mirrors>
    		<mirror>
    				<id>aliyunmaven</id>
    				<mirrorOf>*</mirrorOf>
    				<name>阿里云公共仓库</name>
    				<url>https://maven.aliyun.com/repository/public</url>
    		</mirror>
    	</mirrors>
    

    3.需改IDEA默认配置

    File–>settings
    在这里插入图片描述

2.新建一个普通的Maven项目

1.File–>new–>project–>Maven
在这里插入图片描述
NEXT–>修改一下姓名(Name)和路径(Location)–>NEXT–>(选择自己的环境)Finsh
在这里插入图片描述

2.删除src目录 (就可以把此工程当做父工程了,然后创建子工程)

3.导入maven依赖

​ 可以在 https://mvnrepository.com/ 中寻找自己想要的包,复制里面的依赖

<!--导入依赖-->
<dependencies>
    <!--mysqlq驱动-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId> 
        <version>8.0.12</version>
    </dependency>
    <!--mybatis-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.4</version>
    </dependency>
    <!--junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

4.创建一个Module

2.2创建一个模块

2.2.1编写mybatis的核心配置文件
<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/school?useUnicode=true&amp;characterEncoding=UTF-8&amp;useSSL=true&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="2002416x"/>
            </dataSource>
        </environment>
    </environments>
<!--每一个Mapper.XML都需要在Mybatis核心配置文件中注册-->
    <mappers>
        <mapper resource="com/dar/dao/StudentMapper.xml"/>
    </mappers>
</configuration>
2.2.1编写mybatis工具类
//MybatisUtils.java
package com.dar.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;

//SqlSessionFactory
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //1.获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

2.3编写代码

2.3.1编写实现类
//Student.java
package com.dar.pojo;
public class Student {
    private String num;
    private String id;
    private String name;
    private String sex;
    private String grade;

    public Student(){

    }

    public Student(String num, String id, String name, String sex, String grade) {
        this.num = num;
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.grade = grade;
    }

    public String getNum() {
        return num;
    }

    public void setNum(String num) {
        this.num = num;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }

    @Override
    public String toString() {
        return "Student{" +
                "num='" + num + '\'' +
                ", id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", grade='" + grade + '\'' +
                '}';
    }
}


2.3.2编写dao层
//StudentMapper.java
package com.dar.dao;

import com.dar.pojo.Student;

import java.util.List;
import java.util.Map;

public interface StudentMapper {

    List<Student> getStudentLike(String value);

    //获取全部学生信息
    List<Student> getStudentList();

    //根据id查询
    Student getStudentById(int id);

    Student getStudentById2(Map<String,Object> map);

    //插入学生信息
    int addStudent(Student student);

    int addStudent2(Map<String,Object> map);

    //修改学生信息
    int updateStudent(String id,String name,String grade);

    //删除学生信息
    int deleteStudent(int id);
}

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

   <select id="getStudentLike" resultType="com.dar.pojo.Student">
      select * from student where name like #{value};
   </select>
<!-- 查询语句-->
<!--   id 对应namespace的方法名   resultTypeSql语句执行的返回值-->
   <select id="getStudentList" resultType="com.dar.pojo.Student">
      select * from school.student;
   </select>

   <select id="getStudentById" parameterType="int" resultType="com.dar.pojo.Student">
      select * from school.student where id = #{id};
   </select>

   <select id="getStudentById2" parameterType="map" resultType="com.dar.pojo.Student">
      select * from student where id = #{id} and name = #{name};
   </select>

   <insert id="addStudent" parameterType="com.dar.pojo.Student">
      insert into school.student (num,id,name,sex,grade) values (#{num},#{id},#{name},#{sex},#{grade});
   </insert>

   <insert id="addStudent2" parameterType="map">
      insert into school.student (id,grade) values (#{Id},#{Grade});
   </insert>

   <update id="updateStudent" parameterType="com.dar.pojo.Student">
      update school.student set name=#{param2},grade=#{param3}  where id = #{param1};
   </update>

   <delete id="deleteStudent" parameterType="int">
      delete from school.student where id = #{id};
   </delete>
</mapper>

注:

  • id:就是对应的namespace中的方法名;
  • resultType : Sql语句执行的返回值;
  • parameterType : 参数类型;
CURD(数据库技术)相关事宜
(1)namespace

namespace=绑定一个对应的Dao/Mapper接口,namespace中的包名要和Dao/Mapper接口的包名一致

如:

<mapper namespace="com.dar.dao.StudentMapper">
(2)select,insert,update,delete

语法可参考StudentMapper.xml的代码

增删改查一定要提交事务:

sqlSession.commit();
(3)万能的Map

我们的实体类,或者数据库中的表,字段或者参数过多,我们应该考虑使用Map

//dao层接口中
//万能的map
int addUser1(Map<String, Object> map);
<!--dao层xml中--->
<!--用map类型,对象的属性可以直接取出来,传递map的key,
values后面可自定义名字,无需完全匹配数据库,但是测试的时候,字段要和values后面的一样
-->
<insert id="addUser" parameterType="map">
    insert into mybatis.user (id,name,password) values (#{id},#{username},#{password});
 </insert>

//测试
    @Test
    public void test3(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("userid",4);
        map.put("username","王虎");
        map.put("userpassword",789);
        mapper.addUser2(map);
        //提交事务
        sqlSession.commit();
        //关闭资源
        sqlSession.close();
    }

(3)模糊查询
  1. Java代码执行的时候,传递通配符% %

    List<User> userList = mapper.getUserLike("%李%");
    
  2. 在sql拼接中使用通配符

    select * from user where name like "%"#{value}"%"
    
常见问题

由于maven里的约定大于配置,有些写的配置文件无法导出或生效

<!--在build中配置resources,来防止我们资源导出失败的问题-->
    <build>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>

2.3.3编写测试类
package com.dar.dao;

import com.dar.pojo.Student;
import com.dar.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 StudentMapperTest {

    @Test
    public void getStudentLike(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentLike = mapper.getStudentLike("%1%");
        for(Student student : studentLike) {
            System.out.println(studentLike);
        }
        sqlSession.close();
    }

    @Test
    public void test(){
        //1.获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //执行SQL
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        List<Student> studentList = mapper.getStudentList();
        for (Student student : studentList) {
            System.out.println(student);
        }
        sqlSession.close();
    }
    @Test
    public void getStudentById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Student student = mapper.getStudentById(1);
        System.out.println(student);

        sqlSession.close();
    }

    @Test
    public void getStudentById2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("8","8");
        mapper.getStudentById2(map);

        sqlSession.close();
    }
    //增删改需要提交事务
    @Test
    public void addStudent(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        mapper.addStudent(new Student("6", "6", "6", "6", "6"));
        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void addStudent2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        Map<String,Object> map = new HashMap<String,Object>();
        map.put("7","7");
        mapper.addStudent2(map);
        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void updateStudent(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        mapper.updateStudent("3","wdd","122");
        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void deleteStudent(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        mapper.deleteStudent(6);
        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }
}

3.配置解析

3.1核心配置文件(mybatis-config.xml)

MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

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

3.2环境配置(environments)

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中

尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境

3.3属性 properties

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置

  • 编写配置文件

    driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/school
    username=root
    password=2002416x
    
  • 在核心配置文件中引入

    可以直接引入外部文件

    可以在其中增加一些属性配置

    <!--    引入外部配置文件-->
        <properties resource="db.properties">
            <property name="username" value="root"/>
            <property name="password" value="2002416x"/>
        </properties>
    

    如果两个文件有同一个字段,优先使用外部配置文件的

3.4类型别名 typeAliases

**类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写 **

  1. 可以给实体类起别名

    <typeAliases>
            <typeAlias type="com.dar.pojo.Student" alias="Student"/>
    </typeAliases>
    
  2. 指定一个包名

    <typeAliases>
            <package name="com.dar.pojo.Student"/>
    </typeAliases>
    
  3. 注解

    每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名,若有注解,则别名为其注解值。

    @Alias("Student")
    public class Student {
    
    }
    
  • 在实体类比较少的时候,使用第一种方式。

  • 如果实体类十分多,建议用第二种扫描包的方式。

  • 第一种可以自定义别名,第二种不行,如果非要改,需要在实体类上增加注解。

3.5设置 Settings

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

如:

logImpl指定 MyBatis 所用日志的具体实现,未指定时将自动查找。SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

3.6映射器 mappers

注册绑定我们的Mapper文件

  1. 使用相对于类路径的资源引用(推荐使用)

     <mappers>
            <mapper resource="com/dar/dao/StudentMapper.xml"/>
     </mappers>
    
  2. 使用映射器接口实现类的完全限定类名

    <mappers>
    	   <mapper class="com.dar.dao.StudentMapper"/>
    </mappers>
    
  3. 将包内的映射器接口实现全部注册为映射器

    <mappers>
     	   <package name="com.dar.dao"/>
    </mappers>
    

3.7作用域和生命周期

SqlSessionFactoryBuilder

这个类可以被实例化、使用和丢弃,一旦创建了 SqlSessionFactory,就不再需要它了。 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。 你可以重用 SqlSessionFactoryBuilder 来创建多个 SqlSessionFactory 实例,但最好还是不要一直保留着它,以保证所有的 XML 解析资源可以被释放给更重要的事情。

SqlSessionFactory

SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。 使用 SqlSessionFactory 的最佳实践是在应用运行期间不要重复创建多次,多次重建 SqlSessionFactory 被视为一种代码“坏习惯”。因此 SqlSessionFactory 的最佳作用域是应用作用域。 有很多方法可以做到,最简单的就是使用单例模式或者静态单例模式。

SqlSession

每个线程都应该有它自己的 SqlSession 实例。SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。 绝对不能将 SqlSession 实例的引用放在一个类的静态域,甚至一个类的实例变量也不行。 也绝不能将 SqlSession 实例的引用放在任何类型的托管作用域中,比如 Servlet 框架中的 HttpSession。 如果你现在正在使用一种 Web 框架,考虑将 SqlSession 放在一个和 HTTP 请求相似的作用域中。 换句话说,每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它。 这个关闭操作很重要,为了确保每次都能执行关闭操作,你应该把这个关闭操作放到 finally 块中。

4.解决属性名和字段名不一致的问题

问题:数据库的字段与实体类中的字段不一致

数据库中
在这里插入图片描述

实体类
在这里插入图片描述

测试出现问题
在这里插入图片描述

解决方法

  1. 起别名

    <select id="getStudentById" resultType="com.dar.pojo.Student">
        select num,id,name,sex,grade as score from student where id = #{id}
    </select>
    
    
  2. 结果集映射

    resultMap 元素是 MyBatis 中最重要最强大的元素

    ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

     <resultMap id="Students" type="Student">
    <!--  column数据库中的字段,   property实体类中的属性  -->
          <result column="num" property="num"/>
          <result column="id" property="id"/>
          <result column="name" property="name"/>
          <result column="sex" property="sex"/>
          <result column="grade" property="score"/>
       </resultMap>
    

5.日志

5.1日志工厂

Mybatis 通过使用内置的日志工厂提供日志功能。内置日志工厂将会把日志工作委托给下面的实现之一:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging

在MyBatis中具体使用哪一个日志实现,在设置中设定

STDOUT_LOGGING

 <settings>
<!--        标准的日志工厂实现-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TLKhxPln-1621166024727)(C:\Users\1482882482\Pictures\QQ截图20210513215054.jpg)]

5.2 Log4j

  • 什么是Log4j

    Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件,甚至是套接口服务器、NT的事件记录器、UNIX Syslog守护进程等;我们也可以控制每一条日志的输出格式;通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

  • 使用步骤

    1. 先导入log4j的包

      <dependencies>
         <dependency>
           <groupId>log4j</groupId>
           <artifactId>log4j</artifactId>
           <version>1.2.17</version>
         </dependency>
         <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-api</artifactId>
           <version>1.7.21</version>
         </dependency>
         <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-log4j12</artifactId>
           <version>1.7.21</version>
         </dependency>
       </dependencies>
      
      
    2. 编写配置文件

      #将等级为DEBUG的日志信息输出到console和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/dar.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
      
      
    3. 配置settings为log4j实现

       <settings>
              <setting name="logImpl" value="LOG4J"/>
       </settings>
      
    4. 测试运行

       @Test
          public void testLog4j(){
             logger.info("info:进入了testLog4j");
             logger.debug("debug:进入了testLog4j");
             logger.error("error:进入了testLog4j");
          }
      

      运行结果

      [class com.dar.dao.StudentMapperTest]-info:进入了testLog4j
      [class com.dar.dao.StudentMapperTest]-debug:进入了testLog4j
      [class com.dar.dao.StudentMapperTest]-error:进入了testLog4j
      
    5. 打印的日志信息存放在指定的文件中

    在这里插入图片描述

6.分页(减少数据的处理量)

6.1使用MyBatis实现分页,核心SQL

  1. 接口

     List<Student> getStudentByLimit(Map<String,Integer> map);
    
  2. Mapper.xml

     <select id="getStudentByLimit"  parameterType="map" resultType="Student">
          select * from school.student limit #{startIndex},#{pageSize};
     </select>
    
  3. 测试

    @Test
        public void getStudentByLimit(){
            //1.获取sqlSession对象
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            //执行SQL
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    
            HashMap<String, Integer> map = new HashMap<String, Integer>();
            map.put("startIndex",0);
            map.put("pageSize",2);
            List<Student> studentList = mapper.getStudentByLimit(map);
            for (Student student : studentList){
                System.out.println(student);
            }
            sqlSession.close();
        }
    
  4. 运行结果

    Student{num='1', id='3', name='wdd', sex='3', score='null'}
    Student{num='2', id='1', name='2', sex='2', score='null'}
    

6.2 RowBounds分页

不再使用SQL实现分页

  1. 接口

    List<Student> getStudentByBounds();
    
  2. Mapper.xml

    <select id="getStudentByBounds" resultMap="Students">
          select * from school.student;
    </select>
    
  3. 测试

     @Test
        public void getStudentByBounds(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
    
            //RowBounds实现
            RowBounds rowBounds = new RowBounds(1, 2);
            //通过java代码层面实现分页
            List<Student> studentList = sqlSession.selectList("com.dar.dao.StudentMapper.getStudentByBounds",null,rowBounds);
            for (Student student : studentList){
                System.out.println(student);
            }
            sqlSession.close();
        }
    
  4. 运行结果

    Student{num='2', id='1', name='2', sex='2', score='2'}
    Student{num='3', id='2', name='32', sex='21', score='12'}
    

6.3 分页插件

在这里插入图片描述

7.注解

7.1 面向接口编程

面向接口编程是开发程序的功能先定义接口,接口中定义约定好的功能方法声明,通过实现该接口进行功能的实现,完成软件或项目的要求.软件或项目随着时间的不断变化,软件的功能要进行升级或完善,开发人员只需要创建不同的新类重新实现该接口中所有方法,就可以达到系统升级和扩展的目的.

7.2使用注解开发

  1. 注解在接口上实现

     @Select("select * from student")
        List<Student> getStudents();
    
  2. 在核心配置文件中绑定接口

    <!--绑定接口-->
        <mappers>
            <mapper class="com.dar.dao.StudentMapper"/>
        </mappers>
    
  3. 测试

    @Test
        public void getStudents(){
            SqlSession sqlSession = MybatisUtils.getSqlSession();
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            List<Student> students = mapper.getStudents();
            for (Student student : students){
                System.out.println(student);
            }
            sqlSession.close();
        }
    

本质:反射机制实现

底层:动态代理

在这里插入图片描述

MyBatis详细执行流程

在这里插入图片描述

7.3 注解CURD

//方法存在多个参数,所有的参数必须加上@Param("id")注解
    @Select("select * from student where id = #{id}")
    Student getStudentById(@Param("id") String id);

关于@Param( )注解

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

8.Lombok

lombok是一个可以通过简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 Java 代码,lombok能够达到的效果就是在源码中不需要写一些通用的方法,但是在编译生成的字节码文件中会帮我们生成这些方法。

  1. 在IDEA中安装Lombok插件

  2. 在项目中导入lombok的jar包

    <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>RELEASE</version>
          <scope>compile</scope>
        </dependency>
    
  3. 在程序上加上注解

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Student {
        private String num;
        private String id;
        private String name;
        private String sex;
        private String score;
    
    }
    

9.多对一处理

多个学生对应一个老师

9.1环境搭建

  1. 创建表

    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 `students` (
    	`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 `students`(`id`,`name`,`tid`) VALUES ('1','小明','1');
    INSERT INTO `students`(`id`,`name`,`tid`) VALUES ('2','小红','1');
    INSERT INTO `students`(`id`,`name`,`tid`) VALUES ('3','小张','1');
    INSERT INTO `students`(`id`,`name`,`tid`) VALUES ('4','小李','1');
    INSERT INTO `students`(`id`,`name`,`tid`) VALUES ('5','小王','1');
    
  2. 导入lombok

  3. 新建实体类Teacher,Student

    //teacher
    @Data
    public class Teacher {
        private int id;
        private String name;
    }
    
    //Students
    @Data
    public class Students {
        private int id;
        private String name;
        //学生要关联一个老师
        private Teacher teacher;
    }
    
  4. 建立Mapper接口

  5. 建立Mapper.xml文件

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

  7. 测试查询是否能够成功

9.2按照查询嵌套处理

<!--通过子查询
	思路:
        1. 查询所有的学生信息
        2. 根据查询出来的学生的tid寻找特定的老师 (子查询)
-->
    <select id="getStudents" resultMap="StudentTeacher">
        select * from students
    </select>
    <resultMap id="StudentTeacher" type="students">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
<!--        复杂的属性我们需要单独处理 对象  association  集合  collection -->
        <association property="teacher" column="tid" javaType="teacher" select="getTeacher"/>
    </resultMap>

    <select id="getTeacher" resultType="teacher">
        select * from teacher where id = #{id}
    </select>

9.3按照结果嵌套处理

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

回顾Mysql多对一查询方式:

  • 子查询 (按照查询嵌套)
  • 联表查询 (按照结果嵌套)

10.一对多处理

一个老师对应多个学生

10.1环境搭建(同上)

实体类

//teacher
@Data
public class Teacher {
    private int id;
    private String name;
    //一个老师多个学生
    private List<Students> students;
}
@Data
public class Students {
    private int id;
    private String name;
    private int tid;
}

10.2按照查询嵌套处理

<!--    子查询-->
    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from teacher where id = #{tid}
    </select>
    <resultMap id="TeacherStudent2" type="teacher">
        <collection property="students" javaType="ArrayList" ofType="students" select="getStudentByTeacherId" column="id"/>
    </resultMap>

    <select id="getStudentByTeacherId" resultType="students">
        select * from students where tid = #{tid}
    </select>

10.3按照结果嵌套处理

<!--按照结果嵌套查询-->
    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid, s.name sname, t.name tname, t.id tid
        from students s,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"/>
<!--        复杂的属性我们需要单独处理 对象  association  集合  collection
            javaType="" 指定属性类型
            集合中的泛型信息,我们使用ofType获取
            -->
        <collection property="students" ofType="students">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        </collection>
    </resultMap>

10.4小结

  1. 关联 - association 【多对一】

  2. 集合 - collection 【一对多】

  3. javaType & ofType

    JavaType用来指定实体类中的类型
    ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

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

11.动态SQL

什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

所谓的动态SQL,本质上还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

11.1搭建环境

  1. 建表

    @Data
    public class Blog {
        private int id;
        private String title;
        private String author;
    
        private Date createTime;// 属性名和字段名不一致
        private int views;
    }
    
    
  2. 创建一个基础工程

    (1)导包

    (2)编写配置文件

    (3)编写实体类

    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }
    

    (4)编写实体类对应Mapper接口和Mapper.xml文件

11.2 IF标签

<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <if test="title!=null">
            and title = #{title}
        </if>
        <if test="author!=null">
            and author = #{author}
        </if>
    </where>
</select>

11.3 choose (when, otherwise)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
        select * from blog
        <where>
            <choose>
                <when test="title !=null" >
                    title = #{title}
                </when>
                <when test="author !=null" >
                   and author = #{author}
                </when>
                <otherwise>
                    and views = #{views}
                </otherwise>
            </choose>
        </where>
    </select>

11.4 trim、where、set

<update id="updateBlog" parameterType="map">
        update blog
        <set>
            <if test="title != null">
                title = #{title},
            </if>
            <if test="author != null">
                author = #{author}
            </if>
        </set>
        where id = #{id}
    </update>

11.5 SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便使用!

  1. 使用SQL标签抽取公共部分

     <sql id="if-title-author">
            <if test="title != null">
                and title = #{title}
            </if>
            <if test="author != null">
                and author = #{author}
            </if>
        </sql>
    
  2. 在需要使用的地方使用Include标签引用即可

    <select id="queryBlogIF" parameterType="map" resultType="blog">
            select * from blog
            <where>
                <include refid="if-title-author"></include>
            </where>
        </select>
    

注意事项:

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

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:

  • 先在Mysql中写出完整的SQL,再对应的去修改成我们的动态SQL实现通用即可
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值