Mybatis 入门

2023-11-06

1. Mybatis 项目构建

  1. 新建数据库
CREATE DATABASE `mybatis`;
USE `mybatis`;
DROP TABLE IF EXISTS `user`;

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,'yifang','123456'),
(2,'xiaoma','123456'),
(3,'root','123456');

在这里插入图片描述

  1. 导入依赖
<!-- MySQL -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>
<!-- Mybatis -->
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
<!-- Junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13</version>
    <scope>test</scope>
</dependency>
  1. 配置resources,避免资源导出失败
<!--在build中配置resources,来防止我们资源导出失败的问题-->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
  1. 编写核心配置文件mybatis-config.xml
image-20210308152739667
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf-8&amp;serverTimezone=UTC&amp;useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/yifang/mapper/UserMapper.xml"/>
    </mappers>
</configuration>
  1. 编写mybatis工具类

在这里插入图片描述

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取SqlSession连接
    public static SqlSession getSession(){
        return sqlSessionFactory.openSession();
    }
}
  1. 创建实体类User
image-20210308153006936
public class User {
    
    private int id; //id
    private String name; //姓名
    private String pwd; //密码
    
    //构造,有参,无参
    //set/get
    //toString()
}
  1. 编写UserMapper接口类
image-20210308154035676
public interface UserMapper {
    List<User> selectUser();
}
  1. 编写UserMapper.xml配置文件(代替以往的UserDaoImpl.java)
image-20210308154242259
<?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">
<!-- 绑定一个对应的Dao/Mapper接口 -->
<mapper namespace="com.yifang.dao.UserMapper">
    <!-- SQL查询语句 -->
    <select id="selectUser" resultType="com.yifang.pojo.User">
        select * from user
    </select>
</mapper>
  1. 在mybatis-config.xml中注册UserMapper.xml
image-20210308155636025
<mappers>
    <mapper resource="com/yifang/dao/UserMapper.xml"></mapper>
</mappers>

问题:[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platfor

Maven 打包时有标题中警告,需要在pom.xml文件中添加
<properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>

  1. 创建test类
public class test {
    @Test
    public void selectUser() {
        SqlSession session = null;
        try {
            session = MybatisUtils.getSession();

            UserMapper mapper = session.getMapper(UserMapper.class);
            List<User> users = mapper.selectUser();
            for (User user: users){
                System.out.println(user.toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

在这里插入图片描述

2. CRUD

  • crud:增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete)-
  1. UserMapper接口类

在这里插入图片描述

public interface UserMapper {

    // 添加用户(增)
    int addUser(User user);

    // 删除用户(删)
    int deleteUser(int id);

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

    // 列出所有用户(查)
    List<User> getUserList();

    // 根据ID查询所有用户(查)
    User getUserById(int id);
}
  1. UserMapper.xml
image-20210308194945810
<?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.yifang.mapper.UserMapper">
    <insert id="addUser" parameterType="com.yifang.pojo.User">
        insert into user (id, name, pwd) values (#{id}, #{name}, #{pwd});
    </insert>

    <delete id="deleteUser" parameterType="com.yifang.pojo.User">
        delete from user where id = #{id};
    </delete>

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

    <select id="getUserList" resultType="com.yifang.pojo.User">
        select * from user;
    </select>

    <select id="getUserById" parameterType="int" resultType="com.yifang.pojo.User">
        select * from user where id = #{id};
    </select>
</mapper>
  1. test测试类

在这里插入图片描述

public class test {
    // 增删改查需要提交事务
    @Test
    public void addUser() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        
        mapper.addUser(new User(4, "Elen", "123456"));

        session.commit();   // 提交事务
        session.close();
    }

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

        mapper.deleteUser(4);

        session.commit();   // 提交事务
        session.close();
    }

    @Test
    public void updateUser() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);

        mapper.updateUser(new User(4, "Mikasa", "123456"));

        session.commit();   // 提交事务
        session.close();
    }

    @Test
    public void getUserList() {
        SqlSession session = MybatisUtils.getSession();

        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> users = mapper.getUserList();
        for (User user: users){
            System.out.println(user.toString());
        }
        session.close();
    }

    @Test
    public void getUserById() {
        SqlSession session = MybatisUtils.getSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
        session.close();
    }
}
  1. 万能Map
  • UserMapper接口
int addUser2(Map<String, Object> map);
  • UserMapper.xml
<insert id="addUser2" parameterType="map">
    insert into user (id, name, pwd) values (#{id}, #{name}, #{pwd});
</insert>
  • Test测试类
@Test
public void addUser2() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);

    Map<String, Object> map = new HashMap<>();
    map.put("id", 6);
    map.put("name", "Mikasa");
    map.put("pwd", "123456");

    mapper.addUser2(map);
    session.commit();   // 提交事务
    session.close();
}

在这里插入图片描述

  1. 模糊查询
  • UserMapper接口
List<User> getUserByName(String value);
  • UserMapper.xml
<select id="getUserByName" resultType="com.yifang.pojo.User">
    select * from user where name like "%"#{value}"%";
</select>
  • Test测试类
@Test
public void getUserByName() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);

    List<User> users = mapper.getUserByName("i");
    for (User user: users){
        System.out.println(user.toString());
    }
    session.close();
}

在这里插入图片描述

3. 配置解析

3.1 引入外部配置文件(properties)

  1. 新建外部配置文件(数据库的配置文件)db.properties

在这里插入图片描述

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&useSSL=false
username=root
password=123456
  1. 修改mybatis-config.xml
<!-- 引入外部配置文件 -->
<properties resource="db.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>
image-20210309093716033

3.2 配置别名(typeAliases)

image-20210309100259264
<!-- 可以给实体类起别名 -->
<typeAliases>
    <package name="com.yifang.pojo"/>
</typeAliases>
image-20210309095735796
  • resultType中的名称默认是com.yifang.pojo下 Java Bean 的名称,官方推荐首字母小写(大写也能识别)

  • 可以通过添加注解@Alias(“别名”),更改别名

image-20210309100340766

Java 类型对应的别名

image-20210309152853611 image-20210309152904184

3.3 映射器(Mapper)

  • Mapper:定义映射SQL语句文件 ,即告诉 MyBatis 到哪里去找到这些语句
<mappers>
    <mapper resource="com/yifang/mapper/UserMapper.xml"/>
</mappers>
image-20210309102754319

UserMapper.xml

image-20210309102841730

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

image-20210309111416812
  • 如果表user中的字段pwd,不叫pwd,改为password,而在Mybatis中我们想使用pwd字段,这时候就得使用ResultMap

UserMapper.xml中使用ResultMap

image-20210309111815886
<select id="getUserByIdMap" resultMap="UserMap">
    select * from user where name like "%"#{value}"%";
</select>

<resultMap id="UserMap" type="User">
    <result column="pwd" property="password"/>
</resultMap>
image-20210309112643833

5. 实现分页

5.1 日志工厂

对于以往的开发过程,我们会经常使用到debug模式来调节,跟踪我们的代码执行过程。但是现在使用
Mybatis是基于接口,配置文件的源代码执行过程。因此,我们必须选择日志工具来作为我们开发,调
节程序的工具。

Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j (掌握)
  • STDOUT_LOGGING (掌握)
  • JDK logging
<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

在这里插入图片描述

输出:

image-20210309143129836

5.2 log4j

  • log4j是Apache的一个开源项目
  • 通过使用log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件…
  • 我们也可以控制每一条日志的输出格式;

使用步骤:

  1. 导入log4j的依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>
  1. 编写配置文件log4j.properties

    在这里插入图片描述

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/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
  1. mybatis-config.xml中修改setting设置
image-20210309145421475 image-20210309145519110
<settings>
    <setting name="logImpl" value="log4j"/>
</settings>
  1. test类中使用Log4j进行输出!
//注意导包:org.apache.log4j.Logger
static Logger logger = Logger.getLogger(test.class);

@Test
public void getUserByName2() {
    logger.info("info:进入selectUser方法");
    logger.debug("debug:进入selectUser方法");
    logger.error("error: 进入selectUser方法");
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.getUserByName("i");
    for (User user: users){
        System.out.println(user);
    }
    session.close();
}

结果输出:

image-20210309150105354

5.3 limit实现分页

使用limit实现分页

#语法
SELECT * FROM table LIMIT stratIndex,pageSize
SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15  

#如果只给定一个参数,它表示返回最大的记录行数目:
SELECT * FROM table LIMIT 5; //检索前 5 个记录行
#换句话说,LIMIT n 等价于 LIMIT 0,n。

在Mybatis中使用limit实现分页

  1. UserMapper接口
// 选择全部用户实现分页(查)
List<User> selectUser(Map<String,Integer> map);
  1. UserMapper.xml
<select id="selectUser" parameterType="map" resultType="user">
    select * from user limit #{startIndex},#{pageSize}
</select>
  1. test
//分页查询 , 两个参数startIndex , pageSize
@Test
public void testSelectUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    int currentPage = 2;    // 第几页
    int pageSize = 2;       // 每页显示几个
    Map<String,Integer> map = new HashMap<String,Integer>();
    map.put("startIndex", (currentPage-1)*pageSize);
    map.put("pageSize", pageSize);
    List<User> users = mapper.selectUser(map);
    for (User user: users){
        System.out.println(user);
    }
    session.close();
}

输出结果:

image-20210309153717658

5.4 PageHelper

image-20210309154528784

万一哪一天用到了呢

https://pagehelper.github.io/

6. Mybatis执行流程

image-20210309164337125

6. 注解开发

  • sql 类型主要分成 :
    • @select ()
    • @update ()
    • @Insert ()
    • @delete ()

**【注意】**利用注解开发就不需要mapper.xml映射文件了 .

6.1 查(注解)

  1. mybatis-config.xml(核心配置文件)中注入 com.yifang.mapper.UserMapper
<!-- 使用class绑定接口 -->
<mappers>
    <mapper class="com.yifang.mapper.UserMapper"/>
</mappers>
  1. UserMapper接口中添加注解
// 查询所有用户
@Select("select * from user")
List<User> getAllUser();
  1. test
@Test
public void testGetAllUser() {
    SqlSession session = MybatisUtils.getSession();
    // 本质上利用了jvm的动态代理机制
    UserMapper mapper = session.getMapper(UserMapper.class);
    List<User> users = mapper.getAllUser();
    for (User user : users){
        System.out.println(user);
    }
    session.close();
}

6.2 Mybatis自动提交事务

MybatisUtils下修改

在这里插入图片描述

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

6.3 增删改

6.3.1 增

// 添加一个用户
@Insert("insert into user(id,name,pwd) values (#{id},#{name},#{pwd})")
int addUser(User user);
@Test
public void addUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    mapper.addUser(new User(6, "Armin", "123456"));
    session.close();
}

6.3.2 删

在这里插入图片描述

// 删除用户
@Delete("delete from user where id=#{id}")
int delete(@Param("id") int id);
@Test
public void deleteUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    mapper.delete(6);
    session.close();
}

6.3.3 改

// 更新用户
@Update("update user set name=#{name}, pwd=#{pwd} where id=#{id}")
int updateUser(User user);
@Test
public void updateUser() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    mapper.updateUser(new User(6, "Ymir", "123456"));
    session.close();
}
  • 参数有intString 等Java内置类的时候加入 @Param(“内容”)

6.4 Lombok插件使用

  • Lombok用于简化pojo处的代码,代码简洁,但降低了代码的可读性
  1. 添加Lombok依赖
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>
  1. @Data
@Data
  • 使用**@Data**会自动生成 无参构造器,get/set,equals,hashCode,toString
image-20210310093538629
  1. @AllArgsConstructor
@AllArgsConstructor
  • 使用**@AllArgsConstructor**会自动生成 有参构造器
image-20210310094322315
  1. @NoArgsConstructor
@NoArgsConstructor
  • 使用NoArgsConstructor会自动生成 无参构造器
image-20210310094224683
  1. 也可以自己写构造器,并不冲突
image-20210310094434957

7. 多对一的处理

  1. 新建多对一的表:teacher和student
USE `mybatis`;
DROP TABLE IF EXISTS `teacher`;

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, 'yifang');

DROP TABLE IF EXISTS `student`;

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, 'Elen', 1),
(2, 'Mikasa', 1),
(3, 'Armin', 1),
(4, 'Ymir', 1),
(5, 'Reiner', 1);

设计teacher对应多个student

在这里插入图片描述

  1. pojo下新建对应的Java Bean

在这里插入图片描述

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
    private int id;
    private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private int id;
    private String name;
    private int tid;
}
  1. 编写对应的Mapper接口
image-20210310105018218
  1. 新建对应的Mapper.xml(不一定会使用,但也要写,以备不时之需)
image-20210310105057706
<?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.yifang.dao.TeacherMapper">

</mapper>
<?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.yifang.dao.StudentMapper">

</mapper>

8. 一对多的处理

9. 动态SQL

  • 什么是动态SQL:动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.

  • 动态SQL关键字:

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

9.1 搭建环境

新建一个数据库表:blog
字段:id,title,author,create_time,views

USE `mybatis`;
DROP TABLE IF EXISTS `blog`;

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

在这里插入图片描述

  1. 创建IdUtils工具类
image-20210311090347398
public class IdUtils {
    public static String genId() {
        return UUID.randomUUID().toString().replace("-", "");
    }
}
  1. 编写Blog Java Bean
image-20210311090452663
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}
  1. mybatis-config.xml
  • 下划线驼峰自动转换
<settings>
    <setting name="logImpl" value="log4j"/>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
  1. BlogMapper.javaBlogMapper.xml
public interface BlogMapper {
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.yifang.dao.BlogMapper">

</mapper>
  1. 初始化数据

BlogMapper.java

//新增一个博客
int 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>

初始化博客方法

@Test
public void addInitBlog(){
    SqlSession session = MybatisUtils.getSession();
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    Blog blog = new Blog();
    blog.setId(IdUtils.genId());
    blog.setTitle("Mybatis如此简单");
    blog.setAuthor("yifang");
    blog.setCreateTime(new Date());
    blog.setViews(9999);
    mapper.addBlog(blog);

    blog.setId(IdUtils.genId());
    blog.setTitle("Java如此简单");
    blog.setAuthor("yifang");
    blog.setCreateTime(new Date());
    blog.setViews(41241);
    mapper.addBlog(blog);

    blog.setId(IdUtils.genId());
    blog.setTitle("Spring如此简单");
    blog.setAuthor("yifang");
    blog.setCreateTime(new Date());
    blog.setViews(412412);
    mapper.addBlog(blog);

    blog.setId(IdUtils.genId());
    blog.setTitle("微服务如此简单");
    blog.setAuthor("yifang");
    blog.setCreateTime(new Date());
    blog.setViews(4894);
    mapper.addBlog(blog);

    session.close();
}
image-20210311091617010

9.2 if

BlogMapper.java

List<Blog> queryBlogIf(Map map);

BlogMapper.xml

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

test测试类

@Test
public void testQueryBlogIf(){
    SqlSession session = MybatisUtils.getSession();
    BlogMapper mapper = session.getMapper(BlogMapper.class);

    HashMap<String, String> map = new HashMap<String, String>();
    // map.put("title","Mybatis如此简单");
    map.put("author","yifang");

    List<Blog> blogs = mapper.queryBlogIf(map);
    System.out.println(blogs);
    session.close();
}

9.3 where

  • where 元素知道只有在一个以上的if条件有值的情况下才去插入“WHERE”子句。而且,若最后的内容是“AND”或“OR”开头的,where 元素也知道如何将他们去除。

见9.2的例子

9.4 set

  • 用于动态更新语句的解决方案叫做 set。set 元素可以被用于动态包含需要更新的列,而舍去其他的 。

BlogMapper.java

int updateBlog(Map map);

BlogMapper.xml

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

test测试类

@Test
public void testUpdateBlog(){
    SqlSession session = MybatisUtils.getSession();
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    HashMap<String, String> map = new HashMap<String, String>();
    map.put("title","动态SQL");
    map.put("author","yifang");
    map.put("id","7ab145b0cf8f4b10a4a080d009c495b5");
    mapper.updateBlog(map);
    session.close();
}

9.5 choose

  • 有些时候,我们不想用到所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的switch 语句

BlogMapper.java

List<Blog> queryBlogChoose(Map map);

BlogMapper.xml

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

test测试类

@Test
public void testQueryBlogChoose(){
    SqlSession session = MybatisUtils.getSession();
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    HashMap<String, Object> map = new HashMap<String, Object>();
    map.put("title","Java如此简单");
    map.put("author","yifang");
    map.put("views",9999);
    List<Blog> blogs = mapper.queryBlogChoose(map);
    System.out.println(blogs);
    session.close();
}

9.6 SQL片段

提取SQL片段:

<sql id="if-title-author">
    <if test="title != null">
        title = #{title}
    </if>
    <if test="author != null">
        and author = #{author}
    </if>
</sql>

引用SQL片段:

<select id="queryBlogIf" parameterType="map" resultType="blog">
    select * from blog
    <where>
    	<!-- 引用 sql 片段,如果refid 指定的不在本文件中,那么需要在前面加上 namespace-->
    <include refid="if-title-author"></include>
    	<!-- 在这里还可以引用其他的 sql 片段 -->
    </where>
</select>

注意:①、最好基于 单表来定义 sql 片段,提高片段的可重用性
②、在 sql 片段中不要包括 where

9.7 foreach

动态 SQL 的另外一个常用的必要操作是需要对一个集合进行遍历,通常是在构建 IN 条件语句的时候

BlogMapper.java

List<Blog> queryBlogForeach(Map map);

BlogMapper.xml

<select id="queryBlogForeach" parameterType="map" resultType="blog">
    select * from blog
    <where>
        <!--
        collection:指定输入对象中的集合属性
        item:每次遍历生成的对象
        open:开始遍历时的拼接字符串
        close:结束时拼接的字符串
        separator:遍历对象之间需要拼接的字符串
        select * from blog where 1=1 and (id=1 or id=2 or id=3)
        -->
        <foreach collection="ids" item="id" open="and (" close=")" separator="or">
            id=#{id}
        </foreach>
    </where>
</select>

test测试类

@Test
public void testQueryBlogForeach(){
    SqlSession session = MybatisUtils.getSession();
    BlogMapper mapper = session.getMapper(BlogMapper.class);
    HashMap map = new HashMap();
    List<Integer> ids = new ArrayList<Integer>();
    ids.add(1);
    ids.add(2);
    ids.add(3);
    map.put("ids",ids);
    List<Blog> blogs = mapper.queryBlogForeach(map);
    System.out.println(blogs);
    session.close();
}

小结:其实动态 sql 语句的编写往往就是一个拼接的问题,为了保证拼接准确,我们最好首先要写原生
的 sql 语句出来,然后在通过 mybatis 动态sql 对照着改,防止出错。多在实践中使用才是熟练掌握它
的技巧

10. 缓存

10.1 简介

  1. 什么是缓存 [ Cache ]?

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

    • 减少和数据库的交互次数,减少系统开销,提高系统效率。
  3. 什么样的数据能使用缓存?

    • 经常查询并且不经常改变的数据。

10.2 Mybatis缓存

  • MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的
    提升查询效率。
  • MyBatis系统中默认定义了两级缓存:一级缓存二级缓存
    • 默认情况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)
    • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
    • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二
      级缓存

10.3 一级缓存

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

10.4 一级缓存失效的四种情况

  • 一级缓存是SqlSession级别的缓存,是一直开启的,我们关闭不了它;
  • 一级缓存失效情况:没有使用到当前的一级缓存,效果就是,还需要再向数据库中发起一次查询请
    求!
  1. sqlSession不同

    • 每个sqlSession中的缓存相互独立
  2. sqlSession相同,查询条件不同

  3. sqlSession相同,两次查询之间执行了增删改操作

  4. sqlSession相同,手动清除一级缓存

@Test
public void testQueryUserById(){
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    
    mapper.操作1();
    
    session.clearCache();	//手动清除缓存
    
    mapper.操作2();

    session.close();
}

10.5 二级缓存

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

10.5.1 使用步骤

  1. mybatis-config.xml中开启全局缓存
<setting name="cacheEnabled" value="true"/>
  1. xxxMapper.xml中配置二级缓存
<cache/>

<cache
       eviction="FIFO"
       flushInterval="60000"
       size="512"
       readOnly="true"/>
  1. 类所有的实体类先实现序列化(Serializable)接口
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog implements Serializable {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

10.5.2 结论

  • 只要开启了二级缓存,我们在同一个Mapper中的查询,可以在二级缓存中拿到数据
  • 查出的数据都会被默认先放在一级缓存中
  • 只有会话提交或者关闭以后,一级缓存中的数据才会转到二级缓存中

10.6 Mybatis缓存原理

10.7 EhCache

  • 看看就行,缓存更多使用Redis

  • Ehcache是一种广泛使用的java分布式缓存,用于通用缓存;

  1. pom.xml
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
<dependency>
    <groupId>org.mybatis.caches</groupId>
    <artifactId>mybatis-ehcache</artifactId>
    <version>1.2.1</version>
</dependency>
  1. xxxMapper.xml
<cache
    type="org.mybatis.caches.ehcache.EhcacheCache"
    eviction="FIFO"
    flushInterval="60000"
    size="512"
    readOnly="true"/>
  1. ehcache.xml
image-20210311152659130
<?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:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位
    置。参数解释如下:
    user.home – 用户主目录
    user.dir – 用户当前工作目录
    java.io.tmpdir – 默认临时文件路径
    -->
    <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>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mybatis 入门 的相关文章

  • 使用 Netbeans 导出 JAR

    如何使用Netbeans将java项目导出到JAR 我找不到像 Eclipse 那样的选项 您需要启用该选项 Project Properties gt Build gt Packaging gt Build JAR after compi
  • 如何从c调用Java函数

    我被这个问题困扰了 我需要从 c c 调用 Java 函数 在示例和教程中 我只看到一个java应用程序调用一个c方法 并在同一个方法中调用另一个java方法 但我想做的是从代码的任何部分调用java方法 这就是我所拥有的 static J
  • 为什么这个递归连接会产生:数据太长

    我在 MySQL 8 上有这个表 create table tbl id varchar 2 val int insert into tbl values A 1 B 2 C 3 D 4 E 5 以下查询应找出哪些记录集的值之和不大于 6
  • android listviews:页眉和页脚视图

    在我的 ListActivity 中 我需要页眉和页脚视图 位于列表的顶部和底部 分别用作列表上的上一页和下一页按钮 因为我只想一次仅显示 20 个项目 我通过执行以下操作来设置头视图和脚视图 getListView addHeaderVi
  • 从 QueryDSL 谓词对象中获取参数

    我使用带有 Spring REST 端点的 QueryDSL 谓词对象来检索和查询参数值 GetMapping subjectId students RolesAllowed Roles PLATFORM ADMIN Roles USER
  • 添加 2 个不同表的总和

    我有这样的东西 2张桌子 视频 会员 在成员表中 我有每个成员的姓名 1 Tom 2 Bob 3 Zack 4 Dan 5 Casey 在视频表中 我有一列名为 成员 的列 其中的名称用逗号分隔 1 Tom Dan 2 Casey Zack
  • 从 MySQL 将数字数据加载到 python/pandas/numpy 数组的最快方法

    我想从 MySQL 表中读取一些数字 双精度 即 float64 数据 数据大小约为 200k 行 MATLAB 参考 tic feature accel off conn database c fetch exec conn select
  • Java 字节码中循环的检测 - 区分后沿类型

    背景 在提出问题之前 我想声明我已检查以下链接 识别java字节码中的循环 https stackoverflow com questions 6792305 identify loops in java byte code Java 字节
  • 使用git在测试和生产环境之间同步数据库

    我正在尝试在 php mysql 应用程序的开发过程中实现 git 到目前为止 我已经设置了 git repos 并且我们正在使用本地计算机进行测试 并且我们成功地将其用于文件 但我真的不知道如何处理数据库 服务器上有一个 cron 脚本
  • 强制连接第一个表中的所有行

    我有三张桌子 machines拿着自动售货机 products持有所有可能的产品 并且machines products这是两者的交集 给出了特定机器中每个产品线的库存数量 如果机器中没有库存产品 则第三个表中没有相应的行 DESCRIBE
  • 基本的 Swing 库? JGoodies,JFreeChart [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 什么是对象发布以及为什么我们需要它?

    在一次 Java 开发人员面试中 我被问到一个问题 什么是对象发布以及为什么我们需要它 我不确定我知道正确的答案 我认为对象发布是指将对象 变量 状态放入堆内存中 线程之间共享对象 变量 需要它 我对吗 如果我错了 请纠正我 我一直在搜索
  • java.util.Prefs 抛出 BackingStoreException - 为什么?

    我有一个系统可以缓存启动时 SOAP 调用的微小 简单结果 我需要实例能够在启动时重新加载其缓存 以防 SOAP 服务失效 并且还需要处理使用此缓存文件的多个实例的可能性 我选择使用java util prefs但是 Java 的内置自动同
  • MySQL空间几何验证wkt

    在 MySQL mysql gt select astext geomfromtext polygon astext geomfromtext polygon NULL 1 row in set 0 00 sec 但对于较新的 MySQL
  • 通过反思思考工厂设计模式

    我正在对工厂模式进行研发 我开发了下面的代码 现在我知道子类是 Dog 和 Cat 但是如果我想通过在 main 中传递类名来通过反射实现同样的事情 请告诉我该怎么做 爪哇 public abstract class Animal publ
  • Gradle:找不到受信任的证书

    我正在尝试使用 Gradle 在 Ubuntu 服务器上构建我的 Android 项目 在我的 Windows 10 PC 上使用 Android Studio 构建工作正常 但使用 gradlew build or gradlew cle
  • Hibernate:单表中的父/子关系

    我几乎没有看到任何关于以下与 Hibernate 相关问题的提示 这涉及使用具有父子关系的单个数据库表来实现继承 与自身的关系 例如 CREATE TABLE Employee empId BIGINT NOT NULL AUTO INCR
  • Java swing:为 JComboBox 实现我的 Combobox 模型

    我需要我的组合框包含组织的简称 问题是我can在下拉列表中查看组织名称 但是cant实际上选择它 我的错误在哪里 public class ToComboBoxModel extends AbstractListModel implemen
  • JavaFX - 当文本字段具有焦点时加速器不工作

    在我的应用程序中 我有一个使用加速器的屏幕 我正在使用功能键 F3 在我的应用程序中执行操作 它每次都工作正常 但是当我单击此屏幕上的任何文本字段时 功能键不会执行 这是我设置加速器的代码 scene getAccelerators put
  • SnakeYaml“无法找到属性错误”

    这是我的 config yml 的一部分 Authenctication AuthenticationConfig AuthencticationType LDAP LDAPConfig LDAPUrl ldap localhost 389

随机推荐

  • 超详细的计算机网络基础知识总结 第三章:数据链路层

    本文基于 王道计算机考研 计算机网络 其他文章 超详细的计算机网络基础知识 第一章 概述 超详细的计算机网络基础知识 第二章 物理层 超详细的计算机网络基础知识 第四章 数据链路层 超详细的计算机网络基础知识 第五章 传输层 超详细的计算机
  • redis文件中的dump.rdb文件

    dump rdb是由Redis服务器自动生成的 默认情况下 每隔一段时间redis服务器程序会自动对数据库做一次遍历 把内存快照写在一个叫做 dump rdb 的文件里 这个持久化机制叫做SNAPSHOT 有了SNAPSHOT后 如果服务器
  • Vue开发中的表格分页和常见bug

    Vue中的分页组件 组件自取 实际开发中处理数据时 这种分页功能时刚需技能 下面就聊一聊基本操作和常见bug 首先看一下两个重要的属性 current change 当前页发生改变时触发 size change 每页多少条发生改变时触发 先
  • 手把手教你制作Jlink-OB调试器(含原理图、PCB、外壳、固件)

    前言 好久没更新博客和公众号了 感谢大家还没取关哈 好吧 我承认是我太懒了 今天分享一个福利 趁着前段时间嘉立创和捷配打价格战 一天之内 多次降价 看着真是热闹 捷配降到最低3元一款 而嘉立创降到最低5元一款 都是顺丰包邮 不过嘉立创免颜色
  • springboot之事务aop

    项目结构 实现 pom
  • JAVA中Scanner类中,next()与nextLine()的异同

    在运用Scanner做语句解析的时候在next 与nextLine 之间小小的困惑了一下 下面是我的调试分享 next public static void main String args Scanner scanner new Scan
  • 抖音新秒注销,无需等7天的方法,机不可失马上和谐

    抖音注销账号新方法 快速安全 不再需要等待7天 立即与谐同步 随着社交媒体的普及和用户需求的变化 有些人可能希望注销自己在抖音上的账号 然而 传统的注销流程通常需要等待7天的冷静期 让很多用户感到不便和焦虑 今天 我将为大家介绍一种全新的方
  • 升级到Android Studio 3.2.1 ,报 org.gradle.internal.exceptions.LocationAwareException

    最近收到AS版本的推送就果断更新了 更新以后 打开自己最近的项目 报如下错误 No route to host connect failed Caused by org gradle internal exceptions Location
  • Python 我编码遇到的错误

    ValueError invalid literal for int with base 10 0 000 Traceback most recent call last File
  • Hadoop环境搭建(主机名、Ip地址、映射及网络配置)

    一 在安装的虚拟机上修改主机名地址 1 显示当前主机名命令 hostname 2 修改主机名命令 方法 输入 vi etc hostname 方法 输入 hostnamectl set hostname 进入后在编辑模式下 删除原来的主机名
  • java操作excel获取每列的信息并按照学号-姓名格式创建文件夹

    1 导入Maven依赖
  • 数据库连接工具类

    数据库连接 概述 一 jdbc 实验环境搭建 二 Druid连接数据库 实验环境搭建 三 Maven连接数据库 实验环境搭建 四 mybatis连接数据库 实验环境搭建 五 Spring连接数据库 六 SSM 概述 什么是JDBC Java
  • 前端实现Jest单元测试

    介绍 最近在学一些关于工程化的内容 里面正好提到了jest单元测试 首先简单理解一下什么是单元测试 举个例子 小明同学偶然发现海海同学做的组件库不错 想学习一下 于是就拉了代码 不过在看代码的过程中发现有的代码有更优性能的方法 但是呢他自己
  • ctf.show web web1-web10

    ctf show web web1 web10笔记 记录一些web的知识点 本人刚开始学习web很多资料都是借鉴大佬的 许多复现的过程都是大同小异的 写的菜了请大佬们下手轻点 web1 一道简单的入门题 打开环境发现只有一串英文 flag在
  • 唯一索引比普通索引快吗?运行原理是什么?

    推荐阅读 项目实战 AI文本 OCR识别最佳实践 AI Gamma一键生成PPT工具直达链接 玩转cloud Studio 在线编码神器 玩转 GPU AI绘画 AI讲话 翻译 GPU点亮AI想象空间 资源分享 史上最全文档AI绘画stab
  • 从源码角度深入分析iScroll中的scrollToElement方法

    问题1 官方解释 scrollToElement el time offsetX offsetY easing You re gonna like this Sit tight The only mandatory parameter is
  • cocos2d-x-2.2.4 (四) 将MyGame在Android上跑起来

    继续上一篇 我接着在MyGame工程干活 这次要将MyGame运行在Android设备上 要将cocos2dx的项目在Android上跑起来需要NDK和eclipse NDK用来编译cocos2dx的cpp文件 将其打包成动态库文件 例如l
  • 数字信号处理技术(二)变分模态分解(VMD)-Python代码

    本文仅对变分模态分解 VMD 的原理简单介绍和重点介绍模型的应用 1 VMD原理 变分模态分解 VMD 的原理在此不做详细介绍 推荐两个不错的解释参考连接 变分模态分解原理步骤 和VMD算法的介绍 官方源码 2 VMD应用实战 2 1 简介
  • AngularJS系列之JavaScript函数和对象

    转载请注明来源 http blog csdn net caoshiying viewmode contents 这篇文章针对的是有2年以上编程经验的朋友们参考的 作参考资料之用 不从基础讲起 在ES6之前 JavaScript没有class
  • Mybatis 入门

    1 Mybatis 项目构建 新建数据库 CREATE DATABASE mybatis USE mybatis DROP TABLE IF EXISTS user CREATE TABLE user id INT 20 NOT NULL