MyBatis_Learning_大三课程预习

MyBatis_Learning_大三课程预习

  • 1. 第一个Mybatis程序
    • 1. 搭建环境
      • 1.1 搭建数据库
      • 1.2 新建项目
    • 2. 创建一个模块
      • 2.1 编写mybatis核心配置文件
      • 2.2 编写mybatis工具类
    • 3. 编写代码
      • 3.1 实体类
      • 3.2 Dao接口
      • 3.3 接口实现类
    • 4. 测试
    • 5. 测试效果
  • 2. CRUD
    • 1. namespace
    • 2. select
      • 2.1 编写接口
      • 2.2 编写对应的sql中的语句
      • 2.3 测试
    • 3. insert
    • 4. update
    • 5. delete
    • 6. 模糊查询实现(like)
      • 6.1 编写接口
      • 6.2 编写对应的sql中的语句
      • 6.3 测试
  • 3. 配置解析
    • 1. 核心配置文件
    • 2. 环境配置(environments)
      • 2.1 事务管理器(transactionManager)
      • 2.2 数据源(dataSource)
    • 3. 属性(properties)
    • 4. 映射器(mappers)
    • 5. 作用域(Scope)和生命周期
  • 4. 解决属性名和字段名不一致的问题(ResultMap)
    • 1. 问题出现
    • 2. resultMap结果集映射
  • 5. 日志
    • 1. 日志工厂
    • 2. LOG4J
      • 2.1 配置log4j
      • 2.2 使用log4j
  • 6. 使用注解开发
    • 1. 使用注解开发
    • 2. MyBatis详细执行流程
    • 3. CRUD
  • 7. 多对一与一对多
    • 1. 复杂查询环境搭建
      • 1.1 表建立
      • 1.2 新建实体类Teacher,Student
      • 1.3 建立Mapper接口
      • 1.4 建立Mapper.xml文件
      • 1.5 在核心配置文件中注册绑定Mapper.xml
      • 1.6 文件结构一览
      • 1.7 测试
    • 2. 多对一处理
      • 2.1 按照查询嵌套处理
      • 2.2 按照结果嵌套处理
    • 3. 一对多
      • 3.1 修改实体类
      • 3.2 按照结果嵌套处理
      • 3.3 按照查询嵌套处理
    • 4. 小结
  • 8. 动态SQL
    • 1. 描述
    • 2. 搭建环境
      • 2.1创建数据库
      • 2.2创建基础工程
    • 3. if
    • 4. choose、when、otherwise
    • 5. trim、where、set
    • 6. SQL片段
    • 7. foreach
    • 8. 小结
  • 9. 缓存
    • 1. 简介
    • 2. MyBatis缓存
    • 3. 一级缓存
      • 3.1 概述
      • 3.2 步骤
    • 4. 二级缓存
      • 4.1 概述
      • 4.2 步骤

1. 第一个Mybatis程序

1. 搭建环境

1.1 搭建数据库

CREATE DATABASE `mybatis`;

USE `mybatis`;

CREATE TABLE `user` (
	`id` INT ( 20 ) NOT NULL PRIMARY KEY,
	`NAME` VARCHAR ( 20 ) DEFAULT NULL,
	`psd` VARCHAR ( 20 ) DEFAULT NULL
) ENGINE = INNODB DEFAULT CHARSET = utf8;

INSERT INTO `user` ( `id`, `name`, `psd` ) VALUES
	( 1, '张作鹏', '123456' ),
	( 2, '张三', '123456' ),
	( 3, '李四', '123456' )

1.2 新建项目

1.新建一个普通maven项目
2.删除src目录(建立父工程)
3.导入maven依赖
pom.xml(父工程中)


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.zhanggroupId>
    <artifactId>Mybatis-StudyartifactId>
    <packaging>pompackaging>
    <version>1.0-SNAPSHOTversion>
    <modules>
        <module>mybatis-01module>
    modules>

    
    <dependencies>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.49version>
        dependency>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.2version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
    dependencies>

    
    <build>
        <resources>
            <resource>
                <directory>src/main/resourcesdirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
            <resource>
                <directory>src/main/javadirectory>
                <includes>
                    <include>**/*.propertiesinclude>
                    <include>**/*.xmlinclude>
                includes>
                <filtering>truefiltering>
            resource>
        resources>
    build>

project>

2. 创建一个模块

2.1 编写mybatis核心配置文件

mybatis-config.xml




<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        <mapper resource="UserMapper.xml"/>
    mappers>
configuration>

2.2 编写mybatis工具类

MybatisUtils.java

package com.zhang.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 --> sqlSession
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static{
        try{
            //使用Mybatis第一步:获取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 命令所需的所有方法。
    //你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}


3. 编写代码

3.1 实体类

User.java

package com.zhang.pojo;

//实体类
public class User {
    private int id;
    private String name;
    private String psd;

    public User(){
    }
    public User(int id, String name, String psd){
        this.id = id;
        this.name = name;
        this.psd = psd;
    }

    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 String getPsd(){ return psd; }
    public void setPsd(String psd){ this.psd = psd; }

    @Override
    public String toString(){
        return "User{" +
                "id=" + id +
                ",name='" + name + '\'' +
                ",psd='" + psd + '\'' +
                "}";
    }
}

3.2 Dao接口

UserDao.java

package com.zhang.dao;

import com.zhang.pojo.User;

import java.util.List;

public interface UserDao {
    List<User> getUserList();
}

3.3 接口实现类

(由原来的UserDaolmpl转变为一个Mapper配置文件)
UserMapper.xml



<mapper namespace="com.zhang.dao.UserDao">
    <select id="getUserList" resultType="com.zhang.pojo.User">
        select * from mybatis.user
    select>
mapper>

4. 测试

注意点:org.apache.ibatis.binding.BindingException: Type interface com.zhang.dao.UserDao is not known to the MapperRegistry.

junit测试
UserDaoTest.java

package com.zhang.dao;

import com.zhang.pojo.User;
import com.zhang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {
    @Test
    public void test(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {
            //方式一:getMapper
            UserDao userDao = sqlSession.getMapper(UserDao.class);
            List<User> userList = userDao.getUserList();
            //方式二
            //List userList = sqlSession.selectList("com.zhang.dao.UserDao.getUserList");

            for (User user : userList){
                System.out.println(user);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //关闭SqlSession
            sqlSession.close();
        }
    }
}

5. 测试效果

正确输出了数据库中的内容
MyBatis_Learning_大三课程预习_第1张图片

建立好的目录一览
MyBatis_Learning_大三课程预习_第2张图片
PS:菜死了我,写了一天,发现是目录写错了,还有一个地方写错了一个字母,报错不停,教学视频看了三次,第一次预习,第二次跟着写代码,第三次查错误,终于晚上十一点搞出来了结果,路漫漫其修远兮。

2. CRUD

CRUD是指:增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete)
即:增删改查

1. namespace

namespace中的包名要和Dao/Mapper接口的包名一致。

2. select

id:就是对应的namespace中的方法名;
resultTpye:sql语句执行的返回值;
parameterType:参数类型。

2.1 编写接口

//根据id查询用户
User getUserById(int id);

2.2 编写对应的sql中的语句

<select id="getUserById" parameterType="int" resultType="com.zhang.pojo.User">
        select * from mybatis.user where id=#{id}
select>

2.3 测试

@Test
public void getUserById(){
	SqlSession sqlSession = MybatisUtils.getSqlSession();
	UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
	User user = userMapper.getUserById(1);
	System.out.println(user);
	sqlSession.close();
}

MyBatis_Learning_大三课程预习_第3张图片

3. insert


<insert id="addUser" parameterType="com.zhang.pojo.User">
	insert into mybatis.user (id, name, psd) value (#{id},#{name},#{psd});
insert>

MyBatis_Learning_大三课程预习_第4张图片
MyBatis_Learning_大三课程预习_第5张图片

4. update

<update id="updateUser" parameterType="com.zhang.pojo.User">
	update mybatis.user set name=#{name}, psd=#{psd}  where id=#{id};
update>

MyBatis_Learning_大三课程预习_第6张图片
MyBatis_Learning_大三课程预习_第7张图片

5. delete

<delete id="deleteUser" parameterType="com.zhang.pojo.User">
	delete from mybatis.user where id=#{id}
delete>

MyBatis_Learning_大三课程预习_第8张图片
MyBatis_Learning_大三课程预习_第9张图片

6. 模糊查询实现(like)

首先在数据库中再加一李姓人物
MyBatis_Learning_大三课程预习_第10张图片

6.1 编写接口

//模糊查询
List<User> getUserLike(String value);

6.2 编写对应的sql中的语句

<select id="getUserLike" resultType="com.zhang.pojo.User">
	select * from mybatis.user where name like #{value}
select>

6.3 测试

@Test
public void getUserLike(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = userMapper.getUserLike("%李%");
    for (User user : userList){
        System.out.println(user);
    }
    sqlSession.close();
}

MyBatis_Learning_大三课程预习_第11张图片
模糊查询应注意防止SQL注入

  1. Java代码执行的时候,传递通配符% %
List<User> userList = userMapper.getUserLike("%李%");
  1. 在SQL拼接中使用通配符
select * from mybatis.user where name like "%"#{value}"%"

3. 配置解析

1. 核心配置文件

mybatis-config.xml
MyBatis的配置文件包含了会深深影响MyBatis行为的设置和属性信息

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

2. 环境配置(environments)

  • MyBatis 可以配置成适应多种环境 尽

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

2.1 事务管理器(transactionManager)

有两个值,JDBC和MANAGED
MyBatis使用JDBC

<transactionManager type="JDBC"/>

2.2 数据源(dataSource)

有三个值,UNPOOLED、POOLED和JNDI
MyBatis使用POOLED

<dataSource type="POOLED">
	······
dataSource>

3. 属性(properties)

我们可以通过properties属性来实现引用配置文件
这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。
db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF8
username=root
password=123456

mybatis-config.xml


<properties resource="db.properties" />

对于同一字段,优先使用外部配置文件
MyBatis_Learning_大三课程预习_第12张图片

4. 映射器(mappers)

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

5. 作用域(Scope)和生命周期

理解我们之前讨论过的不同作用域和生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题
SqlSessionFactoryBuilder

  • 一旦创建了SqlSessionFactory,就不再需要它了;
  • 局部变量;
  • 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

SqlSessionFactory

  • 说白了就可以想象为:DBCP;
  • SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域
  • 最简单的就是使用单例模式或者静态单例模式。

SqlSession

  • 连接到连接池的一个请求;
  • 它的最佳的作用域是请求或方法作用域
  • 用完之后应当关闭,否则资源会被占用;

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

1. 问题出现

数据库中的字段
MyBatis_Learning_大三课程预习_第13张图片
新建项目,修改实体类,使字段不一致

private int id;
private String name;
private String password;

测试出现问题
MyBatis_Learning_大三课程预习_第14张图片
解决方法:

  • 起别名
select id,name,psd as password from mybatis.user where id=#{id}

2. resultMap结果集映射

<resultMap id="UserMap" type="com.zhang.pojo.User">
    
    
    <result column="psd" property="password"/>
resultMap>

<select id="getUserById" resultMap="UserMap">
    select * from mybatis.user where id=#{id}
select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素;
  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了;
  • 这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。

5. 日志

1. 日志工厂

如果一个数据库操作,出现了异常,我们需要排错,日志就是最好的助手!
曾经:sout、debug
现在:日志工厂
在这里插入图片描述

  • SLF4J
  • LOG4J(掌握)
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING(掌握)
  • NO_LOGGING

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

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

MyBatis_Learning_大三课程预习_第15张图片

2. LOG4J

何为log4j?

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件;
  • 我们也可以控制每一条日志的输出格式;
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程;
  • 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

2.1 配置log4j

  1. 导入log4j的包

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

导入完成后要刷新一下maven,让idea去下载包
MyBatis_Learning_大三课程预习_第16张图片

  1. log4j.properties
#将等级为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/zhang.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
  1. 配置log4j为日志的实现
<settings>
	<setting name="logImpl" value="LOG4J"/>
settings>
  1. log4j的使用
    MyBatis_Learning_大三课程预习_第17张图片

2.2 使用log4j

  1. 在要使用log4j的类中,导入包
import org.apache.log4j.Logger;
  1. 日志对象,参数为当前类的class
static Logger logger = Logger.getLogger(UserDaoTest.class);
  1. 日志级别
@Test
public void testLog4j(){
    logger.info("info:进入了testLog4j");
    logger.debug("debug:进入了testLog4j");
    logger.error("error:进入了testLog4j");
}

6. 使用注解开发

1. 使用注解开发

  1. 注解在接口上实现
@Select("select * from user")
List<User> getUsers();
  1. 需要在核心配置文件上绑定接口
<mappers>
    <mapper class="com.zhang.dao.UserMapper"/>
mappers>
  1. 测试

本质:反射机制实现
底层:动态代理

2. MyBatis详细执行流程

MyBatis_Learning_大三课程预习_第18张图片

3. CRUD

  1. 可以在工具类创建的时候就设置自动提交事务。
public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession(true);
}
  1. 编写接口,增加注解
  2. 测试

注意:必须将接口类注册到核心配置文件中

7. 多对一与一对多

1. 复杂查询环境搭建

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 `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.2 新建实体类Teacher,Student

Teacher.java(部分代码)

package com.zhang.pojo;

public class Teacher {
    private int id;
    private String name;
}

Student.java(部分代码)

package com.zhang.pojo;

public class Student {
    private int id;
    private String name;
    private Teacher teacher;
}

1.3 建立Mapper接口

StudentMapper.java(略)
TeacherMapper.java(部分代码)

@Select("select * from teacher where id=#{tid}")
Teacher getTeacher(@Param("tid") int id);

1.4 建立Mapper.xml文件

1.5 在核心配置文件中注册绑定Mapper.xml

    <mappers>
        <mapper resource="com/zhang/dao/StudentMapper.xml"/>
        <mapper resource="com/zhang/dao/TeacherMapper.xml"/>
    mappers>

1.6 文件结构一览

MyBatis_Learning_大三课程预习_第19张图片

1.7 测试

MyBatis_Learning_大三课程预习_第20张图片
至此,环境搭建完毕,可以进行多对一和一对多的学习。

2. 多对一处理

此时,我们要根据学生查出老师,即:在输出学生信息时,输出老师的信息

2.1 按照查询嵌套处理

    <select id="getStudent" resultMap="StudentTeacher">
        select * from student;
    select>

    <resultMap id="StudentTeacher" type="com.zhang.pojo.Student">
        <id property="id" column="id"/>
        <id property="name" column="name"/>



        <association property="teacher" column="tid" javaType="com.zhang.pojo.Teacher" select="getTeacher"/>
    resultMap>

    <select id="getTeacher" resultType="com.zhang.pojo.Teacher">
        select * from teacher where id=#{id};
    select>

2.2 按照结果嵌套处理


    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from student s,teacher t
        where s.tid=t.id;
    select>

    <resultMap id="StudentTeacher2" type="com.zhang.pojo.Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="com.zhang.pojo.Teacher">
            <result property="name" column="tname"/>
            <result property="id" column="tid"/>
        association>
    resultMap>

3. 一对多

此时,我们要根据老师查询学生,即:在输出老师信息时,输出学生的信息

3.1 修改实体类

Teacher.java(部分代码)

package com.zhang.pojo;

public class Teacher {
    private int id;
    private String name;
    private List<Student> studentList;
}

Student.java(部分代码)

package com.zhang.pojo;

public class Student {
    private int id;
    private String name;
    private int sid;
}

3.2 按照结果嵌套处理

    <select id="getTeacher" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from student s,teacher t
        where s.tid=t.id and t.id=#{tid}
    select>

    <resultMap id="TeacherStudent" type="com.zhang.pojo.Teacher">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        <collection property="studentList" ofType="com.zhang.pojo.Student">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        collection>
    resultMap>

3.3 按照查询嵌套处理

    <select id="getTeacher2" resultMap="TeacherStudent2">
        select * from teacher where id=#{tid}
    select>

    <resultMap id="TeacherStudent2" type="com.zhang.pojo.Teacher">
        <collection property="studentList" javaType="ArrayList" ofType="com.zhang.pojo.Student" select="getStudentByTeacherId" column="id"/>
    resultMap>

    <select id="getStudentByTeacherId" resultType="com.zhang.pojo.Student">
        select * from student where tid=#{tid}
    select>

4. 小结

  • 对象:associatioon
  • 集合:collection
  • javaTpye & ofType
  1. javaTpye 用来指定实体类中属性的类型
  2. ofType 用来指定映射到List或者集合中的pojo类型,泛型中的约束类型
  • MySql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

8. 动态SQL

1. 描述

官方描述
动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。
简言之
动态 SQL就是根据不同的条件生成不同的SQL语句。

2. 搭建环境

2.1创建数据库

CREATE TABLE `blog`(
	`id` VARCHAR(50) NOT NULL COMMENT '博客id',
	`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
	`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
	`create_time` DATETIME NOT NULL COMMENT '创建时间',
	`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8

2.2创建基础工程

  1. 导包
  2. 编写配置文件
  3. 编写实体类
package com.zhang.pojo;

public class Blog {
    private int id;
    private String title;
    private String author;
    private String createTime;
    private int views;

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

    public int getId() {
        return id;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    public int getViews() {
        return views;
    }

    public void setViews(int views) {
        this.views = views;
    }
}

  1. 编写实体类对应的Mapper接口以及Mapper.xml文件

3. if

select * from mybatis.blog where 1=1
<if test="title != null">
	and title=#{title}
if>
<if test="author != null">
	and author=#{author}
if>

4. choose、when、otherwise

select * from mybatis.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>

5. trim、where、set

where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。
而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。
where

select * from mybatis.blog
<where>
    <if test="title != null">
        title=#{title}
    if>
    <if test="author != null">
        and author=#{author}
    if>
where>       

set

update mybatis.blog
<set>
    <if test="title!=null">
        title=#{title},
    if>
    <if test="author!=null">
        author=#{author}
    if>
set>
where id=#{id}

6. SQL片段

有时候,我们将部分sql语句抽出来,方便复用

<sql id="if-title-author">
    <if test="title != null">
        title=#{title}
    if>
    <if test="author != null">
        and author=#{author}
    if>
sql>
<select id="queryBlogIF" parameterType="map" resultType="com.zhang.pojo.Blog">
    select * from mybatis.blog
    <where>
        <include refid="if-title-author"/>
    where>
select>
  • 最好基于单表
  • 不要封装where标签

7. foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)


<select id="queryBlogForeach" parameterType="map" resultType="com.zhang.pojo.Blog">
    select * from mybatis.blog
    <where>
        <foreach collection="ids" item="id" open="and (" close=")" separator=" or ">
            id=#{id}
        foreach>
    where>
select>
@Test
public void queryBlogForeach(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList<Integer>();
    map.put("ids",ids);
    ids.add(1);
    ids.add(2);
    ids.add(3);
    List<Blog> blogs = mapper.queryBlogForeach(map);
    for (Blog blog : blogs) {
        System.out.println(blog);
    }
    sqlSession.close();
}

MyBatis_Learning_大三课程预习_第21张图片

8. 小结

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

  • 在MySql中写出对应的sql,再对应修改为动态sql

9. 缓存

1. 简介

一次查询的结果,给他暂存在一个可以直接取到的地方!内存–>缓存
再次查询相同数据时,直接走缓存,就不查询数据库了
1.什么是缓存[ Cache ]?

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

2. MyBatis缓存

MyBatis包含一个非常强大的查询缓存特性, 它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存:一级缓存和二级缓存

  • 默认情况下,只有一 -级缓存开启。 (SqlSession级别的缓存, 也称为本地缓存)
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  • 为了提高扩展性,MyBatis定义了缓存接口Cache,我们可以通过实现Cache接口来实现二级缓存。

3. 一级缓存

3.1 概述

一级缓存也叫本地缓存:

  • 与数据库同一次会话期间查询到的数据会放在本地缓存中。
  • 以后如果需要获取相同的数据,直接从缓存中拿,没必须再去查询数据库。

3.2 步骤

  1. 开启日志
  2. 测试在一个session中查询两次记录
@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);
    System.out.println("===========================");
    User user2 = mapper.queryUserById(1);
    System.out.println(user2);
    sqlSession.close();
}
  1. 查看日志输出
    MyBatis_Learning_大三课程预习_第22张图片
    MyBatis_Learning_大三课程预习_第23张图片

观察可得出,查询相同用户,sql语句只执行了一次,查询两个用户,sql语句执行了两次。

缓存失效情况:

  1. 增删改操作可能会改变原来的数据,会刷新缓存;
  2. 查询不同的东西
  3. 手动请理缓存
sqlSession.clearCache();
  1. 查询不同的Mapper.xml

4. 二级缓存

4.1 概述

  • 二级缓存也叫全局缓存, 一级缓存作用域太低了,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
  • 工作机制
  1. 一个会话查询一条数据,这个数据就会被放在当前会话的一-级缓存中;
  2. 如果当前会话关闭了,这个会话对应的一级缓存就没了:但是我们想要的是,会话关闭了,一级缓存中的数据被保存到二级缓存中;
  3. 新的会话查询信息,就可以从二级缓存中获取内容;
  4. 不同的mapper查出的数据会放在自己对应的缓存(map)中;

4.2 步骤

  1. 开启全局缓存
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
    <setting name="cacheEnabled" value="true"/>
settings>
  1. 在要使用全局缓存的mapper中开启
<cache/>

<cache
    eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/>
  1. 测试
@Test
public void test(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    SqlSession sqlSession2 = MybatisUtils.getSqlSession();

    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.queryUserById(1);
    System.out.println(user);
    sqlSession.close();

    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
    User user2 = mapper2.queryUserById(1);
    System.out.println(user2);
    sqlSession2.close();
}

MyBatis_Learning_大三课程预习_第24张图片

MyBatis_Learning_大三课程预习_第25张图片

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