Mybatis学习笔记

Mybatis学习笔记

笔记地址:https://github.com/userwusir/study-notes

资源

官网

https://mybatis.org/mybatis-3/zh/index.html

项目地址

https://github.com/mybatis/mybatis-3/releases

Maven配置

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>

第一个Mybatis程序

文件结构

image-20210412224509692

  1. sql

    create table user
    (
        id   int(10)     not null
        primary key,
        name varchar(15) null,
        pwd  varchar(15) null
    );
    
  2. pom.xml

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.18</version>
        </dependency>
    </dependencies>
    
    <build>
        <!--在build中配置resources,来防止我们资源导出失败的问题-->
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
        </resources>
    </build>
    
  3. 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.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="123456"/>
                </dataSource>
            </environment>
        </environments>
        <!--每一个Mapper文件都需要在核心配置文件中配置!-->
        <mappers>
            <mapper resource="com/wll/dao/UserMapper.xml"/>
        </mappers>
    </configuration>
    
  4. util工具类

    /**
     * @author wulele
     */
    public class MybatisUtil {
        /**
         * 每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例
         * 可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件
         * 或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例
         */
        private static SqlSessionFactory sqlSessionFactory;
    
        static {
            try {
                String resource = "mybaties-config.xml";
                InputStream inputStream = Resources.getResourceAsStream(resource);
                sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。
         * @return SqlSession
         */
        public SqlSession getSqlSession() {
            return sqlSessionFactory.openSession();
            //可以设置autocommit,设置为自动提交事务,不用sqlsession.commit()
            //return sqlSessionFactory.openSession(true);
        }
    }
    
  5. pojo层

    /**
     * @author wulele
     */
    @Getter
    @Setter
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class User {
        private int id;
        private String name;
        private String pwd;
    }
    
  6. UserDao--->UserMapper

    /**
     * @author wulele
     */
    public interface UserDao {
        /**
         * User list
         * @return User list
         */
        public List<User> getUerList();
    }
    
  7. UserDaoImpl--->UserMapper.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">
    <mapper namespace="com.wll.dao.UserDao">
        <select id="getUerList" resultType="com.wll.pojo.User">
            select *
            from mybatis.user
        </select>
    </mapper>
    
  8. test

    public class UserDaoTest {
        @Test
        public void test(){
            //建议写法,保证sqlSession能在finally被关闭
            SqlSession sqlSession = null;
            try {
                sqlSession = new MybatisUtil().getSqlSession();
                UserDao mapper = sqlSession.getMapper(UserDao.class);
                List<User> userList = mapper.getUerList();
                //不推荐使用
                //List<User> userList = sqlSession.selectList("com.wll.dao.UserDao.getUerList");
                for (User user : userList) {
                    System.out.println(user);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                sqlSession.close();
            }
        }
    }
    
  9. 注意点!

    • util工具类

      String resource = "mybaties-config.xml";

      不要写全路径

    • 如果自己写的xml在sources文件夹中,不能被打包到发布文件夹,记得pom.xml配置build的resources

    • Mapper.xml文件的namespace、resultType写完整包名,id为namespace对应包下的方法

    • 每一个Mapper文件都需要在核心配置文件中配置!

  10. 运行结果

image-20210412232746194

增删改查

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

​ 传递多个参数使用Map或者注解

/**
     * add user
     * @param user
     */
public void addUser(User user);
<insert id="addUser" parameterType="com.wll.pojo.User">
    insert into mybatis.user(id, name, pwd) value (#{id},#{name},#{pwd})
</insert>
@Test
public void addUser(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    mapper.addUser(new User(4,"bob","1234"));
    //提交事务!!!
    sqlSession.commit();
    sqlSession.close();
}

<delete id="delUserById" parameterType="int">
    delete
    from mybatis.user
    where id = #{id}
</delete>

<update id="updateUser" parameterType="com.wll.pojo.User">
    update mybatis.user
    set name = #{name},
    pwd  = #{pwd}
    where id = #{id}
</update>

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

配置进阶

配置顺序

配置有先后顺序

image-20210413124749011

environments

可以配置多个environment但只能使用一个

使用场景:正式+测试

<environments default="test">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url"
                      value="jdbc:mysql://192.144.231.70:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123123"/>
        </dataSource>
    </environment>
    <environment id="test">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="com.mysql.jdbc.Driver"/>
            <property name="url"
                      value="jdbc:mysql://192.144.231.70:3306/mybatis?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
            <property name="username" value="root"/>
            <property name="password" value="123123"/>
        </dataSource>
    </environment>
</environments>

properties

<!--假如外部配置文件也含有username属性,优先使用外部配置文件-->
<properties resource="db.properties">
    <property name="username" value="root"/>
</properties>

<environments default="development">
    <environment id="development">
        <transactionManager type="JDBC"/>
        <dataSource type="POOLED">
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
</environments>

settings

image-20210413131336025

image-20210413131426993

别名(typeAliases)

  1. 指定实体类取别名

    <typeAliases>
        <typeAlias type="com.wll.pojo.User" alias="User"/>
    </typeAliases>
    
  2. 扫描包

    扫描实体类所在包,如果不使用注解,其默认别名就是类首字母小写

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

    对比,第一种方式可以自定义别名,第二种需要在实体类加注解才可以自定义别名@Alias("hello")

映射器(mappers)

  1. 类路径资源引用

    image-20210413132149448

  2. mapper文件完全限定类名

    image-20210413132431686

  3. mapper文件包名

    image-20210413132451914

    注意点:第一种使用无特殊要求,第二三种使用需要 接口和mapper配置文件同名,并且在一个文件夹下!

结果映射(ResultMap)

如果pojo层对象名不与数据库列名一一对应,可以使用ResultMap来解决。

image-20210413140729803

日志

标准日志配置

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

image-20210413142152579

LOG4J配置

  1. 导包

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </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/wll.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
    
    # 输出消息编码
    log4j.appender.LOGFILE.encoding=UTF-8
    
  3. 核心配置文件

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    
  4. 补充

    Logger logger = Logger.getLogger(UserMapper.class);
    logger.info("开始了");
    logger.debug("哦哦哦");
    logger.error("错错错");
    

    image-20210413175342517

  5. 注意

    mybatis核心配置文件中不要使用或中使用package来指定要扫描的包,否则log文件打不开

分页

limit

  1. limit格式

    select * from user limit startIndex,pageSize;
    

    example

    --从0开始,一页三行
    select * from user limit 0,3;
    
  2. UserMapper

    /**
    * limit user list
    * @param map
    * @return List
    */
    List<User> limitUserList(Map<String, Integer> map);
    
  3. UserMapper.xml

    <select id="limitUserList" parameterType="map" resultType="User">
        select *
        from mybatis.user
        limit #{startIndex},#{pageSize}
    </select>
    
  4. Test

    @Test
    public void limitUserList(){
        SqlSession sqlSession = new MybatisUtil().getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> users = mapper.limitUserList(map);
        for (User user : users) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    

RowBounds

  1. UserMapper

    /**
    * rowBounds user list
    * @return List
    */
    List<User> rowBoundsUserList();
    
  2. UserMapper.xml

    <select id="rowBoundsUserList" resultType="User">
        select *
        from mybatis.user
    </select>
    
  3. Test

    @Test
    public void rowBoundsUserList(){
        RowBounds rowBounds = new RowBounds(0,2);
        SqlSession sqlSession = new MybatisUtil().getSqlSession();
        List<User> userList = sqlSession.selectList("com.wll.dao.UserMapper.rowBoundsUserList", null, rowBounds);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
    

Mybatis PageHelper插件

地址:https://pagehelper.github.io/

注解开发

example

​ UserMapper.java

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

本质:反射机制

底层:动态代理

使用场景:sql语句较为简单

增删改查

/**
* get User By id
*
* @param id
* @return
*/
@Select("select * from user where id = #{uid}")
User getUserById(@Param("uid") int id);

/**
* add user
*
* @param user
*/
@Insert("insert into user(id,name,pwd) values(#{id},#{name},#{pwd})")
void addUser(User user);

/**
* update user
*
* @param user
*/
@Update("update user set name = #{name}, pwd = #{pwd} where id = #{id}")
void updateUser(User user);

/**
* delete user
*
* @param id
*/
@Delete("delete from user where id = #{uid}")
void delUser(@Param("uid") int id);

#{}与${}的区别:

{}方式能够很大程度防止sql注入(安全),${}方式无法防止Sql注入

多对一操作

create table student
(
    id   int(10)     not null
    primary key,
    name varchar(30) null,
    tid  int(10)     null,
    constraint fktid
    foreign key (tid) references teacher (id)
);

create table teacher
(
    id   int(10)     not null
    primary key,
    name varchar(30) null
);

sql

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

image-20210414173028236

public class Student {
    private int id;
    private String name;
    //一个学生对应多个老师
    private Teacher teacher;
}

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

查询嵌套

StudentMapper

/**
* student list
* @return List
*/
List<Student> studentList();

StudentMapper.xml

<!--查询全部学生信息,学生tid对应老师id-->
<select id="studentList" resultMap="StudentTeacher">
    select * from student
</select>
<!--map集结果映射-->
<resultMap id="StudentTeacher" type="com.wll.pojo.Student">
    <id property="id" column="id"/>
    <id property="name" column="name"/>
    <!--对象处理association,映射老师对象到学生tid属性-->
    <!--集合处理collection-->
    <association property="teacher" column="tid" select="teacherList" javaType="com.wll.pojo.Teacher"/>
</resultMap>
<!--查询全部老师信息-->
<select id="teacherList" resultType="com.wll.pojo.Teacher">
    select * from teacher where id = #{tid}
</select>

结果:

image-20210414170928511

结果嵌套

<select id="studentList2" 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.wll.pojo.Student">
    <id property="id" column="sid"/>
    <id property="name" column="sname"/>
    <!--嵌套结果-->
    <association property="teacher" javaType="com.wll.pojo.Teacher">
        <!--返回teacher的id和name-->
        <id property="id" column="tid"/>
        <id property="name" column="tname"/>
    </association>
</resultMap>

结果:

image-20210414174446475

一对多

实体类:

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

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

结果嵌套

/**
* get Teacher
* @param id
* @return
*/
Teacher getTeacher(@Param("tid") int id);

/**
* get teacher
* @param id
* @return
*/
Teacher getTeacher2(@Param("tid")int id);
<select id="getTeacher" resultMap="TeacherStudent">
    select s.id sid, s.name sname, t.id tid, t.name tname
    from student 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"/>
    <!--javaType: 指定属性的类型
        集合中的泛型信息,我们使用ofType-->
    <collection property="students" ofType="student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <result property="tid" column="tid"/>
    </collection>
</resultMap>

结果:

Teacher(id=1, name=吴老师, 
students=[Student(id=1, name=小明, tid=1), 
		  Student(id=2, name=小红, tid=1), 
		  Student(id=3, name=小张, tid=1), 
		  Student(id=4, name=小李, tid=1), 
		  Student(id=5, name=小王, tid=1)])

查询嵌套

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

<resultMap id="TeacherStudent2" type="teacher">
    <result property="id" column="id"/>
    <collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTeacherId"
                column="id"/>
</resultMap>

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

动态sql

学习环境

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 '浏览量'
);

mybaties-config.xml

<!--开启数据库映射到实体类驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>

pojo

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

BlogMapper

/**
* add blog
* @param blog
*/
void addBlog(Blog blog);

BlogMapper.xml

<insert id="addBlog" parameterType="blog">
    insert into blog(id, title, author, create_time, views)
    values (#{id}, #{title}, #{author}, #{createTime}, #{views})
</insert>

UuidUtil

public class UuidUtil {
    public String getId(){
        return UUID.randomUUID().toString().replaceAll("-","");
    }
}

Test

public void test(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    Blog blog = new Blog();
    blog.setId(new UuidUtil().getId());
    blog.setTitle("study");
    blog.setAuthor("wll");
    blog.setCreateTime(new Date());
    blog.setViews(1000);
    mapper.addBlog(blog);

    blog.setId(new UuidUtil().getId());
    blog.setTitle("mybatis");
    blog.setCreateTime(new Date());
    mapper.addBlog(blog);

    blog.setId(new UuidUtil().getId());
    blog.setTitle("servlet");
    blog.setCreateTime(new Date());
    mapper.addBlog(blog);

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

结果:

image-20210416120722384

if

BlogMapper

/**
* IF find blog
* @param map
* @return
*/
List<Blog> findBlogIF(Map map);

BlogMapper.xml

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

Test

public void test(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("author","wll");
    List<Blog> blogList = mapper.findBlogIF(map);
    for (Blog blog : blogList) {
        System.out.println(blog);
    }
    sqlSession.close();
}

结果:

image-20210416123026683

where & trim & sql片段

消除第一个查询条件为空的情况下第二个查询条件前的AND或OR,类似于where 1=1

BlogMapper.xml & where

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

BlogMapper.xml & trim

<select id="findBlogIF" parameterType="map" resultType="blog">
    select * from blog
    <trim prefix="where" prefixOverrides="AND|OR">
        <if test="title != null">
            title = #{title}
        </if>
        <if test="author != null">
            and author = #{author}
        </if>
    </trim>
</select>

BlogMapper.xml & sql片段

提取公用部分sql

  1. 最好基于单表来定义sql片段

  2. 不要存在where标签

    image-20210416165236476

<sql id="IF-title-author">
    <if test="title != null">
        title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>
<select id="findBlogIF" parameterType="map" resultType="blog">
    select * from blog
    <trim prefix="where" prefixOverrides="AND|OR">
        <include refid="IF-title-author"></include>
    </trim>
</select>

choose

条件成立就执行,第一个成立就退出后面不执行,以此类推

BlogMapper

/**
* choose find blog
* @param map
* @return
*/
List<Blog> findBlogChoose(Map map);

BlogMapper.xml & where

<select id="findBlogChoose" 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>

BlogMapper.xml & trim

<select id="findBlogChoose" parameterType="map" resultType="blog">
    select * from blog
    <trim prefix="where" prefixOverrides="AND|OR">
        <choose>
            <when test="title != null">
                title = #{title}
            </when>
            <when test="author != null">
                and author = #{author}
            </when>
            <otherwise>
                and views = ${views}
            </otherwise>
        </choose>
    </trim>
</select>

Test

public void test(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("title","study");
    map.put("author","wll");
    map.put("views",1000);
    List<Blog> blogList = mapper.findBlogChoose(map);
    for (Blog blog : blogList) {
        System.out.println(blog);
    }
    sqlSession.close();
}

结果:

image-20210416130829950

set

BlogMapper

/**
* update blog
* @param map
*/
void updateBlog(Map map);

BlogMapper.xml & 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}
    </where>
</update>

BlogMapper.xml & trim

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

Test

public void test(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    map.put("title","studying");
    map.put("author","wll");
    map.put("id","3d14b89488284b0892bfdc51938d1d31");
    mapper.updateBlog(map);
    sqlSession.commit();
    sqlSession.close();
}

Foreach

image-20210416190626265

sql

--两种方式查询id是1,2,3中的信息
select * from blog where id in (1,2,3);
select * from blog where 1 = 1 and (id = 1 or id = 2 or id =3);

BlogMapper

/**
* dynamic sql
* @param map 
* @return
*/
List<Blog> DynamicSql(Map map);

BlogMapper.xml

<select id="DynamicSql" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <!--方式一-->
        <!-- <foreach collection="ids" item="id" open="id in(" separator="," close=")">-->
        <!-- #{id}-->
        <!-- </foreach>-->
        <!--方式二-->
        <foreach collection="ids" item="id" open="and (" separator="or" close=")">
            id = #{id}
        </foreach>
    </where>
</select>

Test

public void test(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
    
    HashMap map = new HashMap();
    ArrayList<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(2);
    map.put("ids",ids);
    
    List<Blog> blogIF = mapper.DynamicSql(map);
    for (Blog blog : blogIF) {
        System.out.println(blog);
    }
    sqlSession.close();
}

Mybatis缓存

My Batis系统中默认定义了两级缓存:一级缓存和二级缓存

  • 默认情况下,只有一级缓存开启。( Sqlsession级别的缓存,也称为本地缓存)

  • 二级缓存需要手动开启和配置,他是基于 namespace级别的缓存

    为了提高扩屐性, MyBatis定义了缓存接口 Cache。我们可以通过实现 Cache接口来自定义二级缓存

image-20210416192536579

一级缓存

public void myTest(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
    User user = mapper.getUserById(1);
    System.out.println(user);
    User user2 = mapper.getUserById(1);
    System.out.println(user2);
    
    sqlSession.close();
}

查询两次id都为1的user,发现之查询了一次

image-20210416194458022

查询一次id为1,一次为2的user,发现查询了两次

image-20210416194556646

public void myTest(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.getUserById(1);
    System.out.println(user);
    mapper.updateUser(new User(2,"kkk","123"));
    User user2 = mapper.getUserById(1);
    System.out.println(user2);
    sqlSession.close();
}

查询两次同一个人过程中更新另一个人信息,发现查询两次

image-20210416194815866

总结:

  1. 映射语句文件中的所有 select 语句的结果将会被缓存。
  2. 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
  3. 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  4. 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  5. 主动清理缓存(sqlSession.clearCache())

二级缓存

mybaties-config.xml

<!--默认是开启的,显示地表达开启缓存-->
<setting name="cacheEnabled" value="true"/>

在想开启二级缓存地Mapper.xml文件中

<cache/>

也可扩展

创建了一个 FIFO 缓存,每隔 60 秒刷新,最多可以存储结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此对它们进行修改可能会在不同线程中的调用者产生冲突

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

注意:若是不配置readOnly="true",且pojo没有序列化,会报错Cause: java.io.NotSerializableException: com.wll.pojo.User

Test

public void myTest(){
    SqlSession sqlSession = new MybatisUtil().getSqlSession();
    SqlSession sqlSession2 = new MybatisUtil().getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);

    User user = mapper.getUserById(1);
    System.out.println(user);
    sqlSession.close();

    User user2 = mapper2.getUserById(1);
    System.out.println(user2);
    sqlSession2.close();

}

两个sqlSession,第一个关闭后第二个查询,发现只查询一次(一级缓存存到二级缓存中去了)

image-20210416201422853

Ehcache

pom.xml

<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>

UserMapper.xml

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<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>
posted @ 2021-04-16 23:57  芜湖男酮  阅读(69)  评论(0)    收藏  举报