欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

爬梯:MyBatis全操作

程序员文章站 2022-07-13 08:35:50
...

学习资源整理自:B站《狂神说》

扎实基础,将Mybatis全面走一遍!

Mybatis中文官网

MyBatis全操作

1、Hello MyBatis

数据库表环境

CREATE TABLE `smart_user`  (
`ID` int(11) NOT NULL,
`NAME` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`PASSWORD` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of smart_user
-- ----------------------------
INSERT INTO `smart_user` VALUES (1, '阿猫', '123');
INSERT INTO `smart_user` VALUES (2, '阿狗', '1234');
INSERT INTO `smart_user` VALUES (3, '阿猪', '112233');
INSERT INTO `smart_user` VALUES (4, '阿马', NULL);

手写一个纯净的Mybatis项目

从官网入手:https://mybatis.org/mybatis-3/zh/getting-started.html

  1. 配置mybatis-config.xml
<?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="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>
  1. 构建数据库链接对象

sql需要发送到数据库,则需要SqlSession,编写工具类

public class MybatisUtils {

    //链接工厂
    private static SqlSessionFactory sqlSessionFactory;

    static{
        try {
            //构建sqlSession
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取SqlSession
     * @return
     */
    private static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
  1. 编写dao/mapper

想要在数据库进行操作,就得通过sql语句

package com.ssx.dao;
import com.ssx.entity.User;
import java.util.List;
public interface UserMapper {
    List<User> getUserList();
}

实现dao接口的映射文件

<!--命名空间 绑定dao/mapper接口-->
<mapper namespace="com.ssx.dao.UserMapper">
    <select id="getUserList" resultType="com.ssx.entity.User">
    select * from smart_user
  </select>
</mapper>
  1. 执行sql读取数据
@Test
public void test(){
    //1、获取SqlSession
    SqlSession sqlSession = MybatisUtils.getSqlSession();

    //2、执行sql
    //方式一,使用mapper
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> userList = mapper.getUserList();

    //方式二,全限定名 不推荐
    //List<User> userList = sqlSession.selectList("com.ssx.dao.UserMapper.getUserList");

    userList.forEach(System.out::println);
    sqlSession.close();
}

console

User(id=1, name=阿猫, password=123)
User(id=2, name=阿狗, password=1234)

2、CRUD

id : 对应mapper接口中的方法

resultType:返回值类型

parameter:参数类型

Test

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserById(1);

        userList.forEach(System.out::println);
        sqlSession.close();
    }
    @Test
    public void searchUserByName(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.searchUserByName("猫");

        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setId(3);
        user.setName("阿猪");
        user.setPassword("112233");
        mapper.insertUser(user);

        sqlSession.commit();//提交事务
        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }
    @Test
    public void insertUserWithMap() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String,Object> user = new HashMap();
        user.put("id",4);
        user.put("userName","阿马");
        user.put("psw","87664");
        mapper.insertUserWithMap(user);

        sqlSession.commit();//提交事务
        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setId(3);
        user.setName("阿鸡");
        user.setPassword("223344");

        mapper.updateUser(user);
        sqlSession.commit();
        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        mapper.deleteUser(3);
        sqlSession.commit();

        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }


UserMapper.java

    List<User> getUserById(int id);
    List<User> searchUserByName(String name);

    void insertUser(User user);
    void insertUserWithMap(Map<String, Object> map);

    void updateUser(User user);

    void deleteUser(int id);

UserMapper.xml

<mapper namespace="com.ssx.dao.UserMapper">
    <select id="getUserList" resultType="com.ssx.entity.User">
        select * from smart_user
    </select>
    <select id="getUserById" resultType="com.ssx.entity.User" parameterType="int">
        select * from smart_user where id = #{id}
    </select>
    <select id="searchUserByName" resultType="com.ssx.entity.User" parameterType="String">
        select * from smart_user where name like concat("%",#{name},"%")
    </select>


    <insert id="insertUser" parameterType="com.ssx.entity.User">
        insert into smart_user(id,name,password) values(#{id},#{name},#{password})
    </insert>
    <insert id="insertUserWithMap" parameterType="java.util.Map">
        insert into smart_user(id,name,password) values(#{id},#{userName},#{psw})
    </insert>

    <update id="updateUser" parameterType="com.ssx.entity.User">
        update smart_user set name=#{name},password=#{password} where id = #{id}
    </update>

    <delete id="deleteUser" parameterType="int">
        delete from smart_user where id = #{id}
    </delete>
</mapper>

3、配置解析

mybatis.xml的标签是有序的。

引用官网资料

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

环境配置(environments)

首先可以配置多个连接环境,但SqlSessionFactory实例只有一个

transactionManager

默认使用jdbc事务,还有一个managed几乎不用(EJB)

dataSource

有三种数据源类型:unpooled/pooled(默认)/jndi

属性(properties)

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

<properties resource="org/mybatis/example/config.properties">
  <property name="username" value="dev_user"/>
  <property name="password" value="F2Fa3!33TYyg"/>
</properties>

设置好的属性可以在整个配置文件中用来替换需要动态配置的属性值。比如:

<dataSource type="POOLED">
  <property name="driver" value="${driver}"/>
  <property name="url" value="${url}"/>
  <property name="username" value="${username}"/>
  <property name="password" value="${password}"/>
</dataSource>

类型别名(typeAliases)

单个实体类设置别名

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

<typeAliases>
  <typeAlias alias="Author" type="domain.blog.Author"/>
  <typeAlias alias="Blog" type="domain.blog.Blog"/>
  <typeAlias alias="Comment" type="domain.blog.Comment"/>
  <typeAlias alias="Post" type="domain.blog.Post"/>
  <typeAlias alias="Section" type="domain.blog.Section"/>
  <typeAlias alias="Tag" type="domain.blog.Tag"/>
</typeAliases>

当这样配置时,Blog 可以用在任何使用 domain.blog.Blog 的地方。

扫描整个entity包*

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

<typeAliases>
  <package name="domain.blog"/>
</typeAliases>

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

使用注解设置别名

若有注解,则别名为其注解值。见下面的例子:

@Alias("author")
public class Author {
    ...
}

设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

设置名 描述 有效值 默认值
cacheEnabled 全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 true | false true
lazyLoadingEnabled 延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。 true | false false
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING 未设置

映射器(mappers)

既然 MyBatis 的行为已经由上述元素配置完了,我们现在就要来定义 SQL 映射语句了。 但首先,我们需要告诉 MyBatis 到哪里去找到这些语句。 在自动查找资源方面,Java 并没有提供一个很好的解决方案,所以最好的办法是直接告诉 MyBatis 到哪里去找映射文件。 你可以使用相对于类路径的资源引用,或完全限定资源定位符(包括 file:/// 形式的 URL),或类名和包名等。例如:

<!-- 使用相对于类路径的资源引用 推荐使用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>
<!-- 使用完全限定资源定位符(URL) -->
<mappers>
  <mapper url="file:///var/mappers/AuthorMapper.xml"/>
  <mapper url="file:///var/mappers/BlogMapper.xml"/>
  <mapper url="file:///var/mappers/PostMapper.xml"/>
</mappers>
<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>
<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

这些配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了,也就是接下来我们要讨论的。

作用域(Scope)和生命周期

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

SqlSessionFactoryBuilder

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

SqlSessionFactory

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

SqlSession

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

4、结果映射 resultMap

当数据库字段名跟实体类的字段名不一致时,有专门的处理办法。(除去小学生使用的as别名)

5、日志

官网资料

设置名 描述 有效值 默认值
logImpl 指定 MyBatis 所用日志的具体实现,未指定时将自动查找。 SLF4J 、 LOG4J 、 LOG4J2 、 JDK_LOGGING 、 COMMONS_LOGGING 、 STDOUT_LOGGING 、 NO_LOGGING 未设置

mybatis.xml

STDOUT_LOGGING 控制台输出

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

爬梯:MyBatis全操作

LOG4J

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

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

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

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

mybatis.xml

<settings>
    <!--<setting name="logImpl" value="STDOUT_LOGGING"/>-->
    <setting name="logImpl" value="LOG4J"/>
</settings>

添加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/kuang.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

6、分页

limit和Rowbounds

mapper.xml

    <select id="getUserByIdOnLimit" resultMap="resultUserMap" parameterType="map">
        select * from smart_user limit #{pagestart},#{pagesize}
    </select>
    <select id="getUserByIdOnRowbounds" resultMap="resultUserMap">
        select * from smart_user
    </select>

test

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

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

    Map<String,Integer> map = new HashMap<>();
    map.put("pagestart",0);
    map.put("pagesize",2);
    List<User> userList = mapper.getUserByIdOnLimit(map);

    userList.forEach(System.out::println);
    sqlSession.close();
}

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

    RowBounds rowBounds = new RowBounds(0, 2);
    List<User> userList = sqlSession.selectList("com.ssx.dao.UserMapper.getUserByIdOnRowbounds",null,rowBounds);

    userList.forEach(System.out::println);
    sqlSession.close();
}

分页插件

https://pagehelper.github.io/

7、注解CRUD

mybatis.xml

<mappers>
    <mapper class="com.ssx.dao.UserMapper"/>
</mappers>

mapper.java

public interface UserMapper {

    @Select("select * from smart_user")
    List<User> getUserList();
    @Select("select * from smart_user where id = #{id}")
    List<User> getUserById(@Param("id") int id2);

    @Insert("insert into smart_user(id,name,password) values(#{id},#{name},#{password})")
    void insertUser(User user);

    @Update("update smart_user set name = #{name} where id = #{id}")
    void updateUser(User user);

    @Delete("delete from smart_user where id = #{id}")
    void deleteUser(@Param("id") int id2);
}

test

public class MybatisTest05 {

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

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

        List<User> userList = mapper.getUserList();

        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserById(1);

        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setId(3);
        user.setName("阿猪");
        user.setPassword("112233");
        mapper.insertUser(user);

        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setId(3);
        user.setName("阿鸡");

        mapper.updateUser(user);
        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }

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

        mapper.deleteUser(3);

        List<User> userList = mapper.getUserList();
        userList.forEach(System.out::println);
        sqlSession.close();
    }
} 

@Param

  • 基本类型或String类型需要加上,引用类型不需要加
  • 如果只有一个基本类型可以忽略,但建议加上
  • sql语句中使用的参数名是@Param()中的设定属性名(给类型取了别名)

8、连表查询

数据库表环境

-- ----------------------------
-- Table structure for smart_teacher
-- ----------------------------
CREATE TABLE `smart_teacher`  (
`tid` int(11) NOT NULL,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`tid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of smart_teacher
-- ----------------------------
INSERT INTO `smart_teacher` VALUES (1, '王老师');
INSERT INTO `smart_teacher` VALUES (2, '李老师');

-- ----------------------------
-- Table structure for smart_student
-- ---------------------------- 
CREATE TABLE `smart_student`  (
`sid` int(11) NOT NULL COMMENT ' ',
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`tid` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`sid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of smart_student
-- ----------------------------
INSERT INTO `smart_student` VALUES (1, '小电', 1);
INSERT INTO `smart_student` VALUES (2, '小绿', 2);
INSERT INTO `smart_student` VALUES (3, '小牧', 1);
INSERT INTO `smart_student` VALUES (4, '小八', 1);
INSERT INTO `smart_student` VALUES (5, '小闹', 2);

实体类

public class Student {

    private int sid;
    private String name;

    private Teacher teacher;
}
public class Teacher {

    private int tid;
    private String name;

    private List<Student> students;

}

多对一

studentMapper.xml

<!--绑定dao/mapper接口-->
<mapper namespace="com.ssx.dao.StudentMapper">

    <!--内联查询语句,将会执行第一个select后,逐条再执行子查询-->
    <select id="getStudentList" resultMap="studentResultMap">
        select * from smart_student
    </select>
    <resultMap id="studentResultMap" type="Student">
        <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
    </resultMap>
    <select id="getTeacher" resultType="Teacher" parameterType="int">
        select * from smart_teacher where tid = #{tid}
    </select>

    <!--结果定制,一条sql返回结果,然后对结果进行解析-->
    <select id="getStudentList2" resultMap="studentResultMap2">
        select s.*,t.name tname
        from smart_student s
        left join smart_teacher t on s.tid = t.tid
    </select>
    <resultMap id="studentResultMap2" type="Student">
        <result property="sid" column="sid"/>
        <result property="name" column="name"/>
        <association property="teacher" javaType="Teacher">
            <result column="tid" property="tid"/>
            <result column="tname" property="name"/>
        </association>
    </resultMap>

</mapper>

一对多

<!--连表方式查询-->
<select id="getTeacherWithStudentList" resultMap="teacherWithStudents">
    select st.tid,st.name tname,ss.sid,ss.name sname
    from smart_teacher st
    left join smart_student ss on st.tid = ss.tid
</select>
<resultMap id="teacherWithStudents" type="Teacher">
    <result column="tid" property="tid"/>
    <result column="tname" property="name"/>
    <collection property="students" ofType="Student">
        <result column="sid" property="sid"/>
        <result column="sname" property="name"/>
    </collection>
</resultMap>

<!--内联方式查询-->
<select id="getTeacherWithStudentList2" resultMap="teacherWithStudents2">
    select * from smart_teacher
</select>
<resultMap id="teacherWithStudents2" type="Teacher">
    <result column="tid" property="tid"/>
    <collection property="students" javaType="List" ofType="Student" column="tid" select="getStudetByTid"/>
</resultMap>
<select id="getStudetByTid" resultType="Student">
    select * from smart_student where tid = #{tid}
</select>

标签解释:

  1. association 关联单个记录(多对一)
  2. collection 关联集合(一对多)
  3. javaType 对应类型
  4. ofType 用在集合中的泛型

9、动态SQL

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

环境

-- ----------------------------
-- Table structure for smart_blog
-- ----------------------------
DROP TABLE IF EXISTS `smart_blog`;
CREATE TABLE `smart_blog`  (
  `ID` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `TITLE` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `AUTHOR` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `CREATE_TIME` datetime(0) NULL DEFAULT NULL,
  `views` int(30) NULL DEFAULT NULL,
  PRIMARY KEY (`ID`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

if天天用就不贴代码了。

choose (when,otherwise)

<select id="queryBlogWithChoose" parameterType="map" resultType="SmartBlog">
    select * from smart_blog where 1=1
    <choose>
        <when test="title != null">
            and title like concat("%",#{title},"%")
        </when>
        <when test="author != null">
            and author like concat("%",#{author},"%")
        </when>
        <otherwise>
            and title like "%今日焦点%"
        </otherwise>
    </choose>
</select>

where

<!--where 元素只会在子元素返回任何内容的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。-->
<select id="queryBlogWithWhere" parameterType="map" resultType="SmartBlog">
    select * from smart_blog
    <where>
        <if test="title != null">
            and title like concat("%",#{title},"%")
        </if>
        <if test="views != null">
            and views = #{views}
        </if>
    </where>
</select>

where标签其实就是trim的一种:where中的第一个如果是and或or就出掉。

<trim prefix="WHERE" prefixOverrides="AND |OR ">
  ...
</trim>

set

<!--set 元素会动态地在行首插入 SET 关键字,并会删掉额外的逗号-->
<update id="updateBlogWithSet" parameterType="SmartBlog">
    update smart_blog
    <set>
        <if test="title != null">
            title = #{title},
        </if>
        <if test="author != null">
            author = #{author},
        </if>
        <if test="views != null">
            views = #{views},
        </if>
    </set>
    where id = #{id}
</update>

set中,最后一个如果是“,”逗号,则去掉

<trim prefix="SET" suffixOverrides=",">
  ...
</trim>

foreach

<select id="queryBlogWithForeach" resultType="SmartBlog" parameterType="list">
    select * from smart_blog
    where 1=1
    and views in 
    <foreach collection="list" index="index" item="view" open=" (" separator="," close=") ">
        #{view}
    </foreach>
</select>

sql片段

<sql id="if-title-like">
    <if test="title != null">
        and title like concat("%",#{title},"%")
    </if>
</sql>

<select id="queryBlogWithSql" parameterType="map" resultType="SmartBlog">
    select * from smart_blog where 1=1
    <include refid="if-title-like"></include>
</select>

10、缓存

  • 默认开启一级缓存(SqlSession级别,也成为本地缓存,执行close()则失效)
  • 二级缓存需要手动配置和开启(namespace级别)
  • Cache接口,可以实现此接口来自定义缓存

官方解释

基本上就是这样。这个简单语句的效果如下:

  • 映射语句文件中的所有 select 语句的结果将会被缓存。
  • 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存
  • 缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
  • 缓存不会定时进行刷新(也就是说,没有刷新间隔)。
  • 缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
  • 缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

缓存清除策略

  • LRU – 最近最少使用:移除最长时间不被使用的对象。
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

一级缓存

显示的开启一级缓存

<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>

二级缓存(全局缓存)

开启二级缓存

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

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

缓存原理

爬梯:MyBatis全操作

自定义缓存

除了上述自定义缓存的方式,你也可以通过实现你自己的缓存,或为其他第三方缓存方案创建适配器,来完全覆盖缓存行为。

<cache type="com.domain.something.MyCustomCache"/>

可以使用mybatis-ehcache包

这块目前已经被行业遗弃了,因为有更高级的缓存可以替代了:Redis、Memcache…

相关标签: java mybatis