MyBatis 精讲

1.简介

什么是Mybatis

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
  • MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis。
  • 2013年11月迁移到Github。

如何获取MyBatis

  • maven仓库

<dependency>
    <groupId>org.mybatisgroupId>
    <artifactId>mybatisartifactId>
    <version>3.5.7version>
dependency>

持久化

  • 持久化就是将程序的数据在持久状态和顺势状态转化的过程
  • 内存:断电即失
  • 数据库(jdbc),io文件持久化
    在这里插入图片描述

为什么需要持久化?

  • 有一些对象,不能让他丢掉。
  • 内存价格昂贵

持久层

Dao层,Service层,Controller层…

  • 完成持久化工作的代码块
  • 层界限十分明显

为什么需要Mybatis

  • 方便使用,帮助程序猿将数据存入到数据库中
  • 传统的JDBC代码太过复杂,Mybatis进行简化

2.第一个Mybatis程序

搭建环境

新建数据库

    create database `mybatis`;

    use `mybatis`;

    create table `user`(
        id int(20) not null ,
        name varchar(30) default null,
        pwd varchar(30) default null,
        primary key(id)
    )engine=INNODB DEFAULT CHARSET=utf8;

    insert into user (id,name,pwd) values
    (1,'遇见','123456'),
    (2,'gao','123456'),
    (3,'妮妮','123456')

新建项目

1.新建一个普通的Maven项目
2.删除src目录
3.导入maven依赖

  • mysql
  • mybatis
  • junit

<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.yujiangroupId>
    <artifactId>Mybatis_StudyartifactId>
    <version>1.0-SNAPSHOTversion>

    
    <dependencies>
        
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.26version>
        dependency>
        
        
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.7version>
        dependency>

        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
            <scope>testscope>
        dependency>
    dependencies>

project>

创建模块

  • 编写mybatis核心配置文件

在resources下新建一个mybatis-config.xml


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/mybatis?				  useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                	
                <property name="username" value="root"/>	
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>

configuration>
  • 编写mybatis工具类(读取mybatis-config资源,并将方法封装成类,避免每次重复读取)

MyBatis 精讲_第1张图片

package com.yujian.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();
    }
}

编写代码

  • 实体类(在pojo包中编写实体类)

MyBatis 精讲_第2张图片

package com.yujian.pojo;
//实体类
public class User {
    private int id;
    private String name;
    private String pwd;
    //无参构造
    public User() {}
    
    //有参构造
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    
    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 getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  • Dao接口
package com.yujian.dao;

import com.yujian.pojo.User;

import java.util.List;

public interface UserDao {
    List<User> getUserList();
}
  • 接口实现类(由原来的Impl转变为一个Mapper配置文件)

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

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

测试

注意点:
Type interface com.guan.dao.UserDao is not known to the MapperRegistry
MapperRegistry:每一个Mapper.xml都需要在Mybatis核心配置文件中注册

maven配置文件到处问题
由于maven约定大于配置,可能遇到配置文件无法被导出或生效,结局方案

<build>
     <resources>
         <resource>
             <directory>src/main/resourcesdirectory>
             <includes>
                 <include>**/*.propertiesinclude>
                 <include>**/*.xmlinclude>
             includes>
             <filtering>falsefiltering>
         resource>
         <resource>
             <directory>src/main/javadirectory>
             <includes>
                 <include>**/*.propertiesinclude>
                 <include>**/*.xmlinclude>
             includes>
             <filtering>falsefiltering>
         resource>
     resources>
build>
  • junit测试
package com.yujian.dao;

import com.yujian.pojo.User;
import com.yujian.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();

        //方式一:执行SQL(getMapper)
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList(); //select * from mybatis.user

        for (User user : userList) {
            System.out.println(user);
        }
        //关闭sqlSession
        sqlSession.close();
    }
}

3.CRUD

1.namespace

namespace中的包名要和Mapper接口的包名保持一致

2.select

选择,查询语句

  • id:对应的namespace中的方法名
  • resultType:Sql语句执行的返回值
  • parameterType:传入参数类型
  1. 编写接口
//查询全部用户
List<User> getUserList();
//根据ID查询用户
User getUserById(int id);
// 使用Java Bean 来传递参数
List<User> getUserList2(User user);
  • 当参数个数大于 5 个时,建议使用 JavaBean 方式。
  1. 编写对应的mapper中的sql语句
<mapper namespace="com.yujian.dao.UserMapper">
	
    <select id="getUserList" resultType="com.yujian.pojo.User">
    select * from mybatis.user
  select>

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

#{}”表示一个占位符,相当于“?”,而“#{id}”表示该占位符待接收参数的名称为 name。
3. 测试

@Test
public void test(){

    //第一步:获取sqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一:执行SQL(getMapper)
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = userMapper.getUserList();

    for (User user : userList) {
        System.out.println(user);
    }
    //关闭sqlSession
    sqlSession.close();
}

//根据id查询用户
@Test
public void getUserById(){
    //第一步:获取sqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一:执行SQL(getMapper)
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.getUserById(1);

    System.out.println(user);
    
	//关闭sqlSession
    sqlSession.close();
}

以下是CRUD(增删改查),记得增删改查要提交事务

3.insert

  1. 编写接口
//insert一个用户
int insertUser(User user)
  1. 编写对应的mapper中的sql语句
<insert id="insertUser" parameterType="com.yujian.pojo.User">
    insert into user (id,name,pwd) values (#{id},#{name},#{pwd});
insert>
  1. 测试
//insert用户
@Test
public void insertUser(){
    //第一步:获取sqlSession对象
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一:执行SQL(getMapper)
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int result = userMapper.insertUser(new User(5, "小hong", "123456"));
    if (result>0){
        System.out.println("插入成功");
    }
    sqlSession.commit();
    sqlSession.close();
}

主键(自动递增)回填

我们知道,MySQL、SQL Server 等数据库表可以采用自动递增的字段作为其主键,当向这样的数据库表插入数据时,即使不指定自增主键的值,数据库也会根据自增规则自动生成主键并插入到表中。

一些特殊情况下,我们可能需要将这个刚刚生成的主键回填到请求对象(原本不包含主键信息的请求对象)中,供其他业务使用。此时,我们就可以通过在 insert 标签中添加 keyProperty 和 useGeneratedKeys 属性,来实现该功能。

下面我们通过一个示例,来演示主键(自动递增)回填功能。

  1. 为 UserMapper.xml 中 id 为 addUser的 insert 标签添加 keyProperty 和 useGeneratedKeys 属性,具体代码如下:

<insert id="addUser" parameterType="com.yujian.pojo.User" keyProperty="id" useGeneratedKeys="true">
    insert into Website (name,url) values(#{name},#{url})
insert>

4.update

  1. 编写接口
//update一个用户
int updateUser(User user);
  1. 编写对应的mapper中的sql语句
<update id="updateUser" parameterType="com.yujian.pojo.User">
    update user set  name = #{name}  where id = #{id};
update>
  1. 测试
//update用户
@Test
public void updateUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一:执行SQL(getMapper)
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int i = userMapper.updateUser(new User(5, "xiaohong", "123456")); //将 小hong 改为 xiaohong
    sqlSession.commit();
    sqlSession.close();
}

5.delete

  1. 编写接口
//删除(delete)一个用户
int deleteUser(int id);
  1. 编写对应的mapper中的sql语句
<delete id="deleteUser" parameterType="int">
    delete from user where id=#{id};
delete>
  1. 测试
//delete用户
@Test
public void deleteUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //方式一:执行SQL(getMapper)
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int i = userMapper.deleteUser(5);
    sqlSession.commit();
    sqlSession.close();
}

注意:增删改查需要提交事务

6.万能Map

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

添加一个用户

//第二种:insert一个用户
int insertUser2(Map<String,Object> map);

<insert id="insertUser2" parameterType="map">
    insert into user (id,name,pwd) values (#{userID},#{userName},#{password});
insert>
//第二种:insert一个用户
@Test
public void insertUser2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    Map<String, Object> map = new HashMap<String, Object>();

    map.put("userID",5);
    map.put("userName","泡泡");
    map.put("password","123098");

    mapper.insertUser2(map);

    sqlSession.commit();
    sqlSession.close();
}

查询用户

User getUserByID2(Map<String,Object> map);
<select id="getUserByID2" parameterType="map" resultType="com.yujian.pojo.User">
    select * from user where id = #{id}
select>
@Test
public void getUserByID2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("id",2);

    User userByID2 = mapper.getUserByID2(map);
    System.out.println(userByID2);
    sqlSession.close();
}

Map传递参数,直接在sql中取出key即可

对象传递参数,直接在sql中取对象的属性即可

只有一个基本类型参数的情况下,可以直接在sql中取出

7.模糊查询

在sql拼接中使用通配符!

  1. 编写接口
List<User> getUserLike(String value);
  1. 编写对应的mapper中的sql语句
<select id="getUserLike" resultType="com.yujian.pojo.User" parameterType="string">
    select * from user where name like #{value};
select>
  1. 测试
@Test
public void getUserLike(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.getUserLike("%小%");
    for (User user : userList) {
        System.out.println(user);
    }
}

8. 使用Limit分页

SELECT & FROM 表 LIMIT startIndex,pageSize

使用Mybatis实现分页,核心SQL
1.接口
List getUserByLimit(Map map);

2.Mapper.xml

<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
    select * from user limit #{startIndex},#{pageSize}
select>

3.测试

@Test
public void getUserByLimit(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("startIndex",3);
    map.put("pageSize",3);

    List<User> userByLimit = mapper.getUserByLimit(map);
    for (User user : userByLimit) {
        System.out.println(user);
    }
}

4.配置解析

1.核心配置文件

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

DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <properties />
    <settings />
    <typeAliases />
    <typeHandlers />
    <objectFactory />
    <plugins />
    <environments>
        <environment>
            <transactionManager />
            <dataSource />
        environment>
    environments>
    <databaseIdProvider />
    <mappers />
configuration>

mybatis-config.xml 文件中的元素节点是有一定顺序的,节点位置必须按以上位置排序,否则会编译错误。

重新回顾一下创建mybatis的步骤

  1. 编写 mybatis-config.xml 配置文件 (在 resources 包下)

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/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
    
    <mappers>
        <mapper resource="com/yujian/dao/UserMapper.xml">mapper>
    mappers>

configuration>
  1. 编写utils工具类(MybatisUtils)
package com.yujian.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();
    }
}
  1. 编写pojo实体类
package com.yujian.pojo;
//实体类
public class User {
    private int id;
    private String name;
    private String pwd;
    public User() {}
    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }
    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 getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  1. 编写dao接口
  • UserMapper.java接口
package com.yujian.dao;

import com.yujian.pojo.User;

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

public interface UserMapper {

    //查询全部用户
    List<User> getUserList();

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

    //insert一个用户
    int insertUser(User user);

    //修改(update)一个用户
    int updateUser(User user);

    //删除(delete)一个用户:根据id删除一个用户
    int deleteUser(int id);
}
  • UserMapper.xml

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.yujian.dao.UserMapper">

    
    <select id="getUserList" resultType="com.yujian.pojo.User">
        select * from mybatis.user
    select>

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

    <insert id="insertUser" parameterType="com.yujian.pojo.User">
        insert into user (id,name,pwd) values (#{id},#{name},#{pwd});
    insert>

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

    <delete id="deleteUser" parameterType="int">
        delete from user where id=#{id};
    delete>
mapper>
  1. 编写test测试类

MyBatis 精讲_第3张图片

package com.yujian.dao;

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

import java.util.HashMap;
import java.util.List;

public class UserDaoTest {


    @Test
    public void test(){

        //第一步:获取sqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //方式一:执行SQL(getMapper)
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();

        for (User user : userList) {
            System.out.println(user);
        }
        //关闭sqlSession
        sqlSession.close();
    }
}

2.环境配置(environments)

MyBatis可以配置成适应多种环境
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境

学会使用配置多套运行环境

Mybatis默认的事务管理器为JDBC,连接池POOLED

3.属性(properties)

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

  1. 在resources下编写一个配置文件db.properties
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8 
username=root
password=123456

注:在配置文件中properties必须写在最上面

  1. 在核心配置文件中引入
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8 

因为在外部定义了driver 与 url,在配置文件中,只需要使用resource进行引用即可

1.指定文件

<properties resource="mybatisDemo/resources/database.properties"/>

2. properties子元素配置

通过 properties 子元素 property 配置 username 和 password 变量,然后在 environments 节点中引用这些变量,代码如下。


<properties resource="db.properties">
   
   <property name="username" value="root"/>
   <property name="password" value="123456"/>
properties>

原本配置文件中是这样子引用的

MyBatis 精讲_第4张图片

  • 可以直接引入外部文件
  • 可以在其中增加属性配置
  • 如果两个文件同一个字段,优先使用外部配置文件
  • 同一字段引用顺序:
    • 元素体内指定属性
    • 外部文件属性
    • properties方法体内参数

4.类型别名(typeAliases)

  • 类型别名可为 Java 类型设置一个缩写名字。
  • 它仅用于 XML 配置,意在降低冗余的全限定类名书写。
<typeAliases>
    <typeAlias type="com.yujian.pojo.User" alias="User">typeAlias>
typeAliases>

也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean

意思就是:如果你的实体类名称为User,当你在返回resultType与parameterType时,只用填你实体类名称(首字母小写)

<typeAliases>
	<package name="com.yujian.pojo"/>
typeAliases>

扫描实体类的包,默认别名为这个类的类名

实体类较少使用第一种,实体类较多使用第二种,也可以在实体类上添加注解:@Alias(“User”)

5.设置(settings)

settings 标签用于配置 MyBatis 的运行时行为,它能深刻的影响 MyBatis 的底层运行,一般不需要大量配置,大部分情况下使用其默认值即可。

settings 的配置项很多,但是真正用到的不会太多,我们把常用的配置项研究清楚就可以了。

settings 配置项说明

配置项 作用 配置选项 默认值
cacheEnabled 该配置影响所有映射器中配置缓存的全局开关 true|false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。在特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态 true|false false
aggressiveLazyLoading 当启用时,对任意延迟属性的调用会使带有延迟加载属性的对象完整加载;反之,每种属性将会按需加载 true|false 版本3.4.1 (不包含) 之前默认值为 true,之后为 false
autoMappingBehavior 指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射。 PARTIAL 表示只会自动映射,没有定义嵌套结果集和映射结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套) NONE、PARTIAL、FULL PARTIAL
defaultExecutorType 配置默认的执行器。SIMPLE 是普通的执行器;REUSE 会重用预处理语句(prepared statements);BATCH 执行器将重用语句并执行批量更新 SIMPLE、REUSE、BATCH SIMPLE
mapUnderscoreToCamelCase 是否开启自动驼峰命名规则映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射 true|false false

6. dataSource标签

用于配置数据库的连接属性,例如要连接的数据库的驱动程序名称、URL、用户名和密码等。

dataSource 中的 type 属性用于指定数据源类型,有以下 3 种类型。

1)UNPOOLED

UNPOOLED 没有数据库连接池,效率低下。MyBatis 需要打开和关闭每个数据库操作的连接,它有点慢,通常应用于简单的应用程序。

2)POOLED

对于 POOLED 数据源类型,MyBatis 将维护一个数据库连接池。并且对于每个数据库的操作,MyBatis 都会使用连接池中的连接,并在操作完成后将它们返回到池中。减少了创建新连接所需的初始连接和身份验证时间。

3)JNDI

对于 JNDI 的数据源类型,MyBatis 将从 JNDI 数据源中获取连接。

dataSource 标签示例代码如下:

<dataSource type="POOLED">
    
    <property name="driver" value="com.mysql.jdbc.Driver" />
    
    <property name="url"
        value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8" />
    <property name="username" value="root" />
    <property name="password" value="root" />
dataSource>

7.映射器(mapper)

MapperRegistry:注册绑定Mapper文件 (mybatis-config.xml中)
方式一:[推荐使用]


<mappers>
    <mapper resource="com/yujian/dao/UserMapper.xml">mapper>
mappers>

方式二:

<mappers>    
    <mapper class="com.yujian.dao.UserMapper">mapper>
mappers>

注意点:

  • 接口和Mapper配置文件必须同名!
  • 接口和Mapper配置文件必须在同一个包下!

方式三:

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

注意点:

  • 接口和Mapper配置文件必须同名!
  • 接口和Mapper配置文件必须在同一个包下!

8.生命周期和作用域

生命周期类别是至关重要的,因为错误的使用会导致非常严重的并发问题

MyBatis 精讲_第5张图片

SqlSessionFactoryBuilder:

  • 一旦创建了SqlSessionFactory,就不再需要了
  • 局部变量

SqlSessionFactory:

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

SqlSession:

  • 连接到连接池的一个请求
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域
  • 用完之后赶紧关闭,否则资源被占用!

MyBatis 精讲_第6张图片

这里面的每一个Mapper,都代表了一个具体的业务

5.解决属性名和字段名不一样的问题

1.问题

数据库中的字段

MyBatis 精讲_第7张图片

新建一个项目 ,拷贝之前的 , 测试实体类字段不一致的情况

//实体类
public class User {
    private int id;
    private String name;
    private String password; //不是与数据库对应的pwd

测试出现问题

MyBatis 精讲_第8张图片

解决办法:

  • 起别名

    • 就是在mapper.xml中的查询语句中为pwd起一个password的别名

      select id,name,pwd as password
      from mybatis
      

MyBatis 精讲_第9张图片

2.resultMap

resultMap 是 MyBatis 中最复杂的元素,主要用于解决实体类属性名与数据库表中字段名不一致的情况,可以将查询结果映射成实体对象。下面我们先从最简单的功能开始介绍。

现有的 MyBatis 版本只支持 resultMap 查询,不支持更新或者保存,更不必说级联的更新、删除和修改。

resultMap元素的构成

resultMap 元素还可以包含以下子元素,代码如下。

<resultMap id="" type="">
    <constructor>
        <idArg/>
        <arg/> 
    constructor>
    <id/>
    <result/>
    <association property=""/>
    <collection property=""/>
    <discriminator javaType="">
        <case value=""/>
    discriminator>
resultMap>

其中:

  • 元素的 type 属性表示需要的 POJO,id 属性是 resultMap 的唯一标识。
  • 子元素
    元素 说明
    property 映射到列结果的字段或属性。如果 POJO 的属性和 SQL 列名(column元素)是相同的,那么 MyBatis 就会映射到 POJO 上
    column 对应 SQL 列
    javaType 配置 Java 类型。可以是特定的类完全限定名或 MyBatis 上下文的别名
    jdbcType 配置数据库类型。这是 JDBC 类型,MyBatis 已经为我们做了限定,基本支持所有常用数据库类型
    typeHandler 类型处理器。允许你用特定的处理器来覆盖 MyBatis 默认的处理器。需要指定 jdbcType 和 javaType 相互转化的规则

    结果集映射

    
        
        <resultMap id="UserMap" type="User">
            
            
            <result column="id" property="id" />
            <result column="name" property="name"/>
            <result column="pwd" property="password"/>
        resultMap>
        
        <select id="getUserById" resultMap="UserMap" parameterType="int">
            select* from user where id = #{id}
        select>
    
    • resultMap 元素是Mybatis中最重要最强大的元素

    • resultMap的设计思想是:对于简单的语句根本不需要配置显示的结果映射,而对于复杂一点的语句,只需要描述他们的关系就可以

    • ResultMap 的优秀之处——你完全可以不用显式地配置它们

    MyBatis 精讲_第10张图片

    6.日志

    6.1日志工厂

    如果一个数据库操作出现了异常,需要排错!日志是最好的助手!

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EpnCHrn4-1678614442786)(../JavaWeb.assets/kuangstudyfcd19ee8-93de-48db-90a9-893b9a4a69c5-16354093269931.jpg)]

    • SLF4J
    • LOG4J [掌握]
    • LOG4J2
    • JDK_LOGGING
    • COMMONS_LOGGING
    • STDOUT_LOGGING [掌握]
    • NO_LOGGING

    在Mybatis中具体使用哪个日志,在设置中设定
    STDOUT_LOGGING标准日志输出
    在Mybatis核心配置文件中,配置我们的日志

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

    MyBatis 精讲_第11张图片

    Log4j

    什么是Log4j?

    • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件

    • 我们可以控制每一条日志的输出格式

    • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程

    • 通过一个配置文件来灵活地进行配置,而不需要修改应用的代码

      1.导入Maven包

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

      2.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/guan.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.配置log4j为日志的实现

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

    4.Log4j的使用

    MyBatis 精讲_第12张图片

    简单使用

    1.在需要使用Log4j的类中,导入包import org.apache.log4j.Logger;

    2.日志对象,参数为当前类的class

    static Logger logger = Logger.getLogger(UserMapperTest.class);
    

    3.日志级别

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

    7.注解

    使用注解开发

    1.注解在接口上实现

    @Select("select * from user")
    List<User> getUsers();
    

    2.需要在核心配置文件中绑定接口

    
    <mappers>
        <mapper class="com.yujian.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();
    }
    

    3.测试
    本质:反射机制代理
    底层:动态代理

    MyBatis 精讲_第13张图片

    Mybatis详细的执行流程

    MyBatis 精讲_第14张图片

    CRUD

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

    public static SqlSession getSqlSession() { 
        return sqlSessionFactory.openSession(true); 
    }
    

    1.编写接口,增加注释

    @Select("select * from user")
    List<User> getUsers();
    
    @Select("select *from user where id=#{id} and name=#{name}")
    User getUserById(@Param("id")int id,@Param("name")String name);
    
    @Insert("insert into user(id,name,pwd)values(#{id},#{name},#{password})")
    int addUser(User user);
    
    //你在@Param()中填写了什么,你查询语句就要对应什么
    @Delete("delete from user where id =#{uid}")
    int deleteUser(@Param("uid") int id);
    
    @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
    int updateUser(User user);
    

    2.测试

    @Test
    public void getUserById(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserById(1, "遇见");
        System.out.println(user);
    
        sqlSession.close();
    }
    
    @Test
    public void addUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.addUser(new User(7, "路飞", "134123"));
        if (i>0){
            System.out.println("添加成功");
        }
    }
    
    @Test
    public void deleteUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.deleteUser(7);
        if (i>0){
            System.out.println("删除成功");
        }
    }
    
    @Test
    public void updateUser(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int i = mapper.updateUser(new User(7, "悟空", "111111"));
        if (i>0){
            System.out.println("修改成功");
        }
    }
    

    关于@Param()注解

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

    #{}和${}区别
    preparedStatement和Statement的区别,#{}可以防止sql注入

    8.Lombok

    使用步骤:
    1.在IDEA中安装
    2.导入Maven包

    
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.18.20version>
    dependency>
    

    3.在实体类上编写注解

    package com.yujian.pojo;
    
    import lombok.Data;
    
    //实体类
    @Data
    public class User {
        private int id;
        private String name;
        private String password;
        
        public User(int id, String name, String password) {
            this.id = id;
            this.name = name;
            this.password = password;
        }
    }
    

    说明:

    @Data:无参构造,get,set,toString,hashcode,equals
    @AllArgsConstructor:有参构造
    @NoArgsConstructor:无参构造

    9.多对一处理

    MyBatis 精讲_第15张图片

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

    创建数据库

    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);
    

    MyBatis 精讲_第16张图片

    1.测试环境搭建

    1.导入lombok依赖

    <dependencies>
    
        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <version>1.18.20version>
        dependency>
    
    dependencies>
    

    2.新建实体类Teacher,Student

    • 学生实体类
    package com.yujian.pojo;
    
    import lombok.Data;
    
    @Data
    public class Students {
        private int id;
        private String name;
    
        //学生需要关联一个老师
        private Teachers teachers;
    
        public Students(int id, String name, Teachers teachers) {
            this.id = id;
            this.name = name;
            this.teachers = teachers;
        }
    }
    
    
    • 教师实体类
    package com.yujian.pojo;
    
    import lombok.Data;
    
    @Data
    public class Teachers {
        private int id;
        private String name;
    
        public Teachers(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }
    

    3.建立Mapper接口

    • StudentsMapper接口
    package com.yujian.dao;
    
    public interface StudentsMapper {
    }
    
    • TeachersMapper接口
    package com.yujian.dao;
    
    import com.yujian.pojo.Teachers;
    import org.apache.ibatis.annotations.Param;
    import org.apache.ibatis.annotations.Select;
    
    public interface TeachersMapper {
        @Select("Select *from teacher where id =#{tid}")
        Teachers getTeacher(@Param("tid") int id);
    }
    

    4.建立Mapper.xml文件

    • TeachersMapper.xml
    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.yujian.dao.TeachersMapper">
        
    mapper>
    
    • StudentsMapper.xml
    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.yujian.dao.StudentsMapper">
    
    mapper>
    

    5.在核心配置文件中绑定注册Mapper接口或文件

    
    <mappers>
        <mapper class="com.yujian.dao.TeachersMapper">mapper>
        <mapper class="com.yujian.dao.StudentsMapper">mapper>
    mappers>
    

    6.测试查询是否成功

    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        TeachersMapper mapper = sqlSession.getMapper(TeachersMapper.class);
        Teachers teacher = mapper.getTeacher(1);
    
        System.out.println(teacher);
    
    }
    

    2.按照查询嵌套处理

    //查询所有学生的信息,以及对应老师的信息
    List<Students> getStudent();
    
    
    <select id="getStudent" resultMap="StudentTeacher">
        select * from student
    select>
    
    <select id="getTeacher" resultType="Teachers">
        select *from teacher where id = #{id}
    select>
    
    <resultMap id="StudentTeacher" type="Students">
        
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        
        
        <association property="teachers" column="tid" javaType="Teachers" select="getTeacher"/>
    
    resultMap>
    

    3.按照结果嵌套处理

    List<Students> getStudent2();
    
    
    <select id="getStudent2" resultMap="StudentTeacher2">
        select s.id as sid,s.name as sname,t.name as tname
        from student as s,teacher as t
        where s.tid = t.id
    select>
    
    <resultMap id="StudentTeacher2" type="Students">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teachers" javaType="Teachers">
            <result property="name" column="tname"/>
        association>
    resultMap>
    
    @Test
    public void getStudent2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        StudentsMapper mapper = sqlSession.getMapper(StudentsMapper.class);
        List<Students> student2 = mapper.getStudent2();
        for (Students student : student2) {
            System.out.println(student);
        }
    }
    

    回顾Mysql多对一查询

    • 子查询
    • 连表查询

    10.一对多处理

    1.环境搭建

    • 老师的实体类
    @Data
    public class Teachers {
        private int id;
        private String name;
    
        //一个老师有多个学生
        private List<Students> students;
    }
    
    • 学生的实体类
    @Data
    public class Students {
        private int id;
        private String name;
        private int tid;
    
    }
    

    按照结果嵌套处理

    
    <select id="getTeachers" resultMap="TeacherStudent">
        select s.id sid,s.name sname,t.name tname,t.id tid
        from `teacher` t,`student` s
        where s.tid = t.id and t.id = #{tid};
    select>
    
    <resultMap id="TeacherStudent" type="Teachers">
        <result property="id" column="tid"/>
        <result property="name" column="tname"/>
        
        <collection property="students" ofType="Students">
            <result property="id" column="sid"/>
            <result property="name" column="sname"/>
            <result property="tid" column="tid"/>
        collection>
    resultMap>
    

    按照查询嵌套处理

    <select id="getTeachers2" resultMap="TeacherStudent2">
        select *from teacher where id = #{tid}
    select>
    
    <resultMap id="TeacherStudent2" type="Teachers">
        <collection property="students" javaType="ArrayList" ofType="Students" select="getStudentByTeacherId" column="id"/>
    resultMap>
    
    <select id="getStudentByTeacherId" resultType="Students">
        select * from student where tid = #{tid}
    select>
    

    小结

    1. 关联 - association [多对一]

    2. 集合 - collection [一对多]

    3. javaType & ofType

      ​ 1.javaType 用来指定实体类中属性的类型

      ​ 2.ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

    11.动态SQL

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

    借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。
    if
    choose (when, otherwise)
    trim (where, set)
    foreach   
    

    搭建环境

    数据库搭建

    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
    

    创建一个基础工程(Mybatis-08)
    1.导包
    2.编写配置文件
    3.编写实体类

    package com.yujian.pojo;
    
    import lombok.Data;
    
    import java.util.Date;
    
    @Data
    public class Blog {
        private String id;
        private String title;
        private String author;
        private Date createTime;
        private int views;
    }
    

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

    IF

    接口

    //查询博客(输入标题查指定,输入作者查指定作者的所有博客,不输入查所有博客)
    List<Blog> queryBlogIf(Map map);
    

    xml文件

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

    测试类

    @Test
    public void queryBlogIF(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    
        HashMap map = new HashMap();
        map.put("title","Mybatis");
        map.put("author","遇见");
    
        List<Blog> blogs = mapper.queryBlogIF(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }
    

    choose(when,otherwise)

    使用choose的时候,只执行一个when中的代码

    <select id="queryBlogChoose" resultType="Blog" parameterType="map">
            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> 
    

    trim(where,set)

    • where

    使用where的好处:

    1. 当你的第一个查询条件成立的时候,它会自动将前面的and或者or帮你取消掉
    <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>
    
    • set

    使用set的好处

    1. set元素会动态前置SET关键字
    2. 同时会删除无关的逗号
    <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>
    

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

    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>
    
    1. 在需要使用的地方使用include标签引用
    <select id="queryBlogIF" parameterType="map" resultType="Blog">
        select * from blog
        <where>
            <include refid="if-title-author">include>
        where>
    select>
    

    注意事项

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

    Foreach

    MyBatis 精讲_第17张图片

    xml文件

    • collection:表示哪个集合
    • item:遍历的属性为
    • open:开头为
    • close:结尾为
    • separate:中间由什么关联
    
    <select id="queryBlogForeach" parameterType="map" resultType="Blog">
        select * from blog
        <where>
            <foreach collection="ids" item="id" open="and (" separator="or" close=")">
                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>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
    
        map.put("ids",ids);
        List<Blog> blogs = mapper.queryBlogForeach(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }
    }
    

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

    • 先在Mysql中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可

    12.缓存

    12.1简介

    查询:连接数据库,消耗资源!

    • 一次查询的结果,暂存在一个可以直接取到的地方!—> 内存:缓存
    • 再次查询相同数据的时候,直接走缓存,不用走数据库

    1.什么是缓存?

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

    12.2Mybatis缓存

    • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率

    • MyBatis系统中默认定了了两级缓存:

      一级缓存

      二级缓存

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

    12.3一级缓存

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

    测试步骤:

    1. 开启日志
      2.测试在一个Session中查询两次相同记录
      3.查看日志输出

    缓存失效情况:
    1.查询不同记录
    2.增删改操作,可能改变原来数据,必定会刷新缓存
    3.手动清理缓存

    sqlSession.clearCache();//手动清除缓冲
    

    12.4二级缓存

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

    步骤:
    1.开启缓存

    开启全局缓存
    <setting name="cacheEnable" value="true"/>
    

    2.在要使用二级缓存的Mapper中开启

    
    <cache/>
    

    也可以这么写

    
    <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
    

    3.测试

    小结

    • 只要开启了二级缓存,在同一个Mapper下就有效
    • 所有的数据到会先放在一级缓存中
    • 只有当会话提交,或者关闭的时候,才会提交到二级缓存中

    12.5Mybatis缓存原理

    MyBatis 精讲_第18张图片

    12.6自定义缓存Ehcache

    Ehcache是一种广泛使用的开源Java分布式缓存,主要面向通用缓存
    要在程序中使用ehcacche,要先导包

    <dependency>
        <groupId>org.mybatis.cachesgroupId>
        <artifactId>mybatis-ehcacheartifactId>
        <version>1.2.1version>
    dependency>
    

    ehcache.xml

    
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
             updateCheck="false">
        <diskStore path="./tmpdir/Tmp_EhCache"/>
        <defaultCache
                      eternal="false"
                      maxElementsInMemory="10000"
                      overflowToDisk="false"
                      diskPersistent="false"
                      timeToIdleSeconds="1800"
                      timeToLiveSeconds="259200"
                      memoryStoreEvictionPolicy="LRU"/>
        <cache
               name="cloud_user"
               eternal="false"
               maxElementsInMemory="5000"
               overflowToDisk="false"
               diskPersistent="false"
               timeToIdleSeconds="1800"
               timeToLiveSeconds="1800"
               memoryStoreEvictionPolicy="LRU"/>
    ehcache>
    

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