Mybatis基本使用

什么是MyBatis?

MyBatis是一个优秀的持久层框架,它对jdbc的操作进行了封装,使得数据库的操作不再繁琐,避免大量的代码编写,使开发人员将更多的精力放在sql语句上。

MyBatis的优点

  1. 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。
  2. 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。它只是一种帮助程序,让程序开发者自己设计数据库表结构和关系。每个sql语句可以独立配置,非常灵活。
  3. 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  4. 提供映射标签,支持对象与数据库的ORM字段关系映射
  5. 提供对象关系映射标签,支持对象关系组建维护
  6. 提供xml标签,支持编写动态sql

Mybatis的简单使用

创建使用的数据库

create database mybatis;

use mybatis;

CREATE TABLE user (
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    pwd VARCHAR(100) DEFAULT(NULL),
    PRIMARY KEY (id)
)ENGINE=Innodb,CHARSET=UTF8;

insert into user(id,name,pwd) VALUES
(1,'孙悟空','666666'),
(2,'御坂美琴','233333'),
(3,'白井黑子','123456');

创建maven项目,并导入依赖

    <dependencies>
        <!-- MyBatis 核心依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.10</version> <!-- 请使用最新版本 -->
        </dependency>

        <!-- 数据库驱动(例如 MySQL) -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version> <!-- 请根据数据库版本选择 -->
        </dependency>

        <!-- JUnit 5 核心依赖 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.10.0</version> <!-- 请使用最新版本 -->
            <scope>test</scope>
        </dependency>

        <!-- JUnit 5 测试引擎 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.10.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

创建实体类

package com.myLearning.pojo;

import java.io.Serializable;

public class User implements Serializable {
    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;
    }
}

在resources目录下创建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="com.mysql.cj.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>
    <mappers>
    <!-- 这里之后会配置 -->
       <mapper resource="com/myLearning/Dao/UserMapper.xml"/>
    </mappers>
</configuration>

创建一个用于获取SqlSession的工具类

package com.myLearning.util;

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;

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        String resource = "org/mybatis/example/mybatis-config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

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

创建Dao层的接口类

package com.myLearning.Dao;

import com.myLearning.pojo.User;

import java.util.List;

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

创建Mapper层的映射文件UesrMapper.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">
<!--用于绑定刚刚创建的Dao(Mapper)接口-->
<mapper namespace="com.myLearning.Dao.UserDao">
<!--    这里id填写接口中的方法,resultType填写集合中的泛型的类型-->
    <select id="getUserList" resultType="com.myLearning.pojo.User">
        select * from user
    </select>
</mapper>

修改之前的mybatis-config.xml文件

在配置文件中配置Mapper的路径

<?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?useSSL=true&amp;useUnicode=true&amp;characterEncoding=utf-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
    <!-- 加上刚刚创建的Mapper.xml路径 -->
      <mapper resource="com/myLearning/Dao/UserMapper.xml"/>
    </mappers>
</configuration>

修改pom.xml文件,防止资源导出时的问题

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

编写测试类测试

package com.myLearning.Dao;

import com.myLearning.pojo.User;
import com.myLearning.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class UserDaoTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();

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

继续增加CRUD操作

修改数据库接口类(这里将UserDao.java重命名为UserMapper.java)

package com.myLearning.Dao;

import com.myLearning.pojo.User;

import java.util.List;

public interface UserMapper {
    // 获取所有用户列表
    List<User> getUserList();

    // 插入一个新的用户
    int insertUser(User user);

    // 更新一个用户
    int updateUser(User user);

    // 删除一个用户
    int deleteUser(int id);
}

修改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">
<!--用于绑定刚刚创建的Dao(Mapper)接口-->
<mapper namespace="com.myLearning.Dao.UserMapper">
<!--    这里id填写接口中的方法,resultType填写集合中的泛型的类型-->
    <select id="getUserList" resultType="com.myLearning.pojo.User">
        select * from user
    </select>

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

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

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

测试

package com.myLearning.Dao;

import com.myLearning.pojo.User;
import com.myLearning.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.jupiter.api.Test;

import java.util.List;

public class UserMapperTest {
    @Test
    public void getUserListtest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();

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

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

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

        User user = new User(4,"上条当麻","123666");

        int ret = mapper.insertUser(user);
        System.out.println(ret);
        // 增删改操作一定要提交事务!!!
        sqlSession.commit();
        sqlSession.close();

    }

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

        User user = new User(4,"上条当麻","123456789");

        int ret = mapper.updateUser(user);
        // 增删改需要提交事务
        sqlSession.commit();
        System.out.println(ret);
        sqlSession.close();
    }

    @Test
    public void deleteUserTest(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        int ret = mapper.deleteUser(4);
        sqlSession.commit();
        System.out.println(ret);
        sqlSession.close();
    }
}

万能的Map

Map可以用作参数传递

添加UserMapper接口中的方法

    // 更新一个用户(使用Map)
    int updateUser2(Map<String,Object> map);

编写UserMapper.xml中的SQL语句

    <update id="updateUser2" parameterType="map">
        update mybatis.user set pwd=${mima} where id=${key}
    </update>

测试

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

        Map<String, Object> map = new HashMap<>();
        map.put("mima","233333333333");
        map.put("key","4");

        mapper.updateUser2(map);
        sqlSession.commit();
        sqlSession.close();
    }

配置文件

核心配置文件

mybatis-config.xml,这是MyBatis的核心配置文件,它包含了MyBatis的所有全局配置信息,如数据库连接信息、事务管理、映射文件等。

Environment环境配置

MyBatis可以配置多个环境,每个环境对应一个数据库连接。在<environments>标签中,可以配置多个<environment>标签,每个<environment>标签对应一个数据库连接。

<!-- 这里选择使用哪个环境配置 -->
<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=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </dataSource>
    </environment>

        <environment id="test">
        <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=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=UTC"/>
            <property name="username" value="root"/>
            <property name="password" value="123456"/>
        </dataSource>
    </environment>
</environments>

Properties配置

可以在核心配置文件中引入外部配置文件

编写一个db.properties文件

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf-8
username=root
passward=123456

在核心配置文件中引入外部配置文件

<?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>
    <properties resource="db.properties">
<!-- 这里还可以继续添加更多的配置,但如果同名,优先使用配置文件中的配置-->
    </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="${passward}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/myLearning/Dao/UserMapper.xml"/>
    </mappers>
</configuration>

typeAliases别名配置

可以在核心配置文件中配置别名,方便使用

    <typeAliases>
        <typeAlias type="com.myLearning.pojo.User" alias="User"/>
    </typeAliases>

也可以使用包扫描的方式,扫描指定包下的所有类,并自动为这些类注册别名,默认别名为类名,且不区分大小写,如果需要自定义,可以在类上使用@Alias注解自定义别名

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

使用别名

    <insert id="insertUser" parameterType="user">
        insert into mybatis.user(id,name,pwd) values(#{id},#{name},#{pwd})
    </insert>

settings配置

常用的setting配置有:mapUnderscoreToCamelCase(开启驼峰命名映射),logImpl(指定日志实现),lazyLoadingEnabled(延迟加载),aggressiveLazyLoading(是否需要立即加载),cacheEnabled(是否开启二级缓存)

mappers配置

mappers配置主要用于指定mybatis映射文件的位置,主要有三种方式:

  1. 使用resource属性指定映射文件的位置
    <mappers>
        <mapper resource="com/myLearning/Dao/UserMapper.xml"/>
    </mappers>
  1. 使用class属性指定接口的全类名,要求接口和映射文件同名,并且在同一目录下
    <mappers>
        <mapper class="com.myLearning.Dao.UserMapper"/>
    </mappers>
  1. 使用package属性指定包名,要求接口和映射文件同名,并且在同一目录下
    <mappers>
        <package name="com.myLearning.Dao"/>
    </mappers>

resultMap

resultMap放在Mapper.xml中进行配置,resultMap用于自定义结果集映射,可以解决实体类属性名和数据库表字段名不一致的问题。

假设数据库表user有id、name、pwd三个字段,实体类User有id、name、password三个属性,id和name属性名一致,password属性名和数据库表字段名不一致,可以使用resultMap自定义结果集映射。

    <resultMap id="userMap" type="User">
        <id property="id" column="id"/>
        <result property="name" column="name"/>
        <result property="password" column="pwd"/>
    </resultMap>

在select语句中可以使用resultMap属性指定resultMap的id。

    <select id="getUserById" resultMap="userMap">
        select * from user where id=#{id}
    </select>

日志

mybatis内置了多种日志实现,可以通过在mybatis配置文件中配置logImpl属性来指定使用的日志实现,常用的日志实现有:

  • SLF4J
  • LOG4J
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING
  • NO_LOGGING

在配置文件中配置logImpl属性

    <settings>
    <!-- 标准日志工厂实现 -->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

配置完后,mybatis会使用指定的日志实现来记录日志。

使用log4j2记录日志

导入log4j2的依赖

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>2.20.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-api</artifactId>
            <version>2.20.0</version>
        </dependency>

在 src/main/resources 目录下创建一个 log4j2.xml 文件,配置 Log4j2 的日志输出

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" shutdownHook="disable">
    <!-- 定义属性 -->
    <Properties>
        <!-- 日志文件输出目录 -->
        <Property name="LOG_HOME">./logs/</Property>
        <!-- 日志文件名称 -->
        <Property name="LOG_FILE_NAME">test.log</Property>
        <!-- 日志文件格式 -->
        <Property name="LOG_PATTERN">%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n</Property>
    </Properties>

    <!-- 定义 Appenders -->
    <Appenders>
        <!-- 控制台输出 -->
        <Console name="Console" target="SYSTEM_OUT">
            <PatternLayout pattern="${LOG_PATTERN}"/>
        </Console>

        <!-- 滚动文件输出 -->
        <RollingFile name="RollingFile" fileName="${LOG_HOME}/${LOG_FILE_NAME}"
                     filePattern="${LOG_HOME}/app-%d{yyyy-MM-dd}-%i.log.gz">
            <PatternLayout pattern="${LOG_PATTERN}"/>
            <Policies>
                <!-- 按时间滚动(每天) -->
                <TimeBasedTriggeringPolicy interval="1" modulate="true"/>
                <!-- 按文件大小滚动(10MB) -->
                <SizeBasedTriggeringPolicy size="10 MB"/>
            </Policies>
            <!-- 最多保留 30 个日志文件 -->
            <DefaultRolloverStrategy max="30"/>
        </RollingFile>

        <!-- 异步日志 -->
        <Async name="Async">
            <AppenderRef ref="RollingFile"/>
        </Async>
    </Appenders>

    <!-- 定义 Loggers -->
    <Loggers>
        <!-- 根日志记录器 -->
        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="Async"/>
        </Root>

        <!-- 自定义包或类的日志级别 -->
        <Logger name="com.myapp" level="debug" additivity="false">
            <AppenderRef ref="Console"/>
        </Logger>

        <!-- 禁用某些类的日志 -->
        <Logger name="org.apache" level="off" additivity="false"/>
    </Loggers>
</Configuration>

在mybatis-config.xml中配置log4j2


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

在代码中使用 Log4j2 记录日志

// 获取Logger对象
private static final Logger logger = LogManager.getLogger(UserMapper.class);
@Test
public void loggerTest(){
    logger.info("测试log4j2的日志使用");
}

分页

分页在mybatis中可以通过sql实现,也可以通过rowbounds实现,现在基本不再使用rowbounds进行分页了
此外,还可以使用插件进行分页

使用注解开发

使用注解开发,可以减少配置文件,但是注解开发不能实现动态sql,所以注解开发一般用于简单的sql语句

简单示例

创建TestMapper接口

package com.myLearning.Dao;

import com.myLearning.pojo.User;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface TestMapper {

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

}

在mybatis-config.xml中配置

    <mappers>
        <mapper resource="com/myLearning/Dao/UserMapper.xml"/>
        <mapper class="com.myLearning.Dao.TestMapper"/>
    </mappers>

测试

其他的增删改都是一样的,只是注解不同,@Insert、@Update、@Delete

关于@Param注解

当接口中的方法参数只有一个时,可以省略@Param注解,但是当接口中的方法参数有多个时且为基本类型或String类型时,必须使用@Param注解,否则会报错

Lombok的使用

Lombok是什么?

Lombok是一个Java库,可以自动生成一些常见的代码,比如getter、setter、toString、equals、hashCode等,可以减少代码量,提高开发效率

Lombok的使用

下载Lombok插件(新版IDEA已经内置了Lombok插件,无需下载)

添加依赖

在pom.xml中添加Lombok的依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>

使用Lombok

在需要生成代码的类上添加注解,比如@ToString、@Getter、@Setter等,就可以自动生成对应的代码了

Lombok的注解

@Getter和@Setter

生成getter和setter方法

@ToString

生成toString方法

@EqualsAndHashCode

生成equals和hashCode方法

@NoArgsConstructor

生成无参构造方法

@AllArgsConstructor

生成全参构造方法

@Data

生成getter、setter、toString、equals、hashCode、无参构造方法

@Builder

生成Builder模式

@Slf4j

生成日志对象

多对一的sql查询(以多个Student与一个Teacher为例)

创建数据库表

create table student(
  id int PRIMARY KEY AUTO_INCREMENT,
  `name` VARCHAR(255) not null,
  tid int not null,
  FOREIGN KEY (tid) REFERENCES teacher(id)
)ENGINE=INNODB,CHARSET=utf8;

CREATE table teacher(
  id int PRIMARY KEY AUTO_INCREMENT,
  `name` VARCHAR(255) not null
)ENGINE=INNODB,CHARSET=utf8;


INSERT INTO teacher(id,name) VALUES(1,"利姆露老师");


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

创建实体类

package com.myLearning.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {
    private int id;
    private String name;

    private Teacher teacher;

}


package com.myLearning.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher implements Serializable {
    private int id;
    private String name;
}


创建Mapper接口

package com.myLearning.Dao;

import com.myLearning.pojo.Student;

import java.util.List;

public interface StudentMapper {
    List<Student> getAllStudent();
}


package com.myLearning.Dao;


import com.myLearning.pojo.Teacher;

import java.util.List;

public interface TeacherMapper {
    List<Teacher> getAllTeacher();
}

创建Mapper.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">
<!--用于绑定刚刚创建的Dao(Mapper)接口-->
<mapper namespace="com.myLearning.Dao.StudentMapper">
    <select id="getAllStudent" resultMap="StudentTeacher">
        select * from student;
    </select>
</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">
<!--用于绑定刚刚创建的Dao(Mapper)接口-->
<mapper namespace="com.myLearning.Dao.TeacherMapper">
    <select id="getAllTeacher" resultType="teacher">
        select * from teacher;
    </select>
</mapper>

在mybatis-config.xml中注册Mapper.xml

    <mappers>
        <mapper resource="com/myLearning/Dao/StudentMapper.xml"/>
        <mapper resource="com/myLearning/Dao/TeacherMapper.xml"/>
    </mappers>

为了成功完成Student类的创建,我们需要修改StudentMapper.xml,使用结果集映射的方法

这里使用多一种查询的方式完成,即在另一个查询中获得teacher的信息,然后使用resultMap进行映射,其中teacher的属性使用association进行映射
association中的select制定了查询teacher的sql语句,column制定了查询teacher的id,property制定了查询teacher的属性

<?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.myLearning.Dao.StudentMapper">
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="id"/>
        <result property="name" column="name"/>
        <association property="teacher" column="tid" javaType="Teacher" select="getAllTeacher"/>
    </resultMap>

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

    <select id="getAllTeacher" resultType="Teacher">
        select * from teacher where id=#{tid};
    </select>

</mapper>

我们也有另一种方法完成任务,就是直接在一个select语句中完成查询,获得构建对象所有需要的信息,使用resultMap进行映射,其中teacher的属性使用association直接进行映射

<?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.myLearning.Dao.StudentMapper">
    <resultMap id="StudentTeacher" type="Student">
        <result property="id" column="sid"/>
        <result property="name" column="sname"/>
        <association property="teacher" javaType="Teacher">
            <result property="id" column="tid"/>
            <result property="name" column="tname"/>
        </association>
    </resultMap>

    <select id="getAllStudent" resultMap="StudentTeacher">
        select s.id sid,t.id tid,s.name sname,t.name tname
        from student s,teacher t
        where s.tid = t.id;
    </select>
</mapper>

一对多sql查询(以一个老师与多个学生举例)

修改实例类

package com.myLearning.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student implements Serializable {
    private int id;
    private String name;
    private int tid;

}


package com.myLearning.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.List;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Teacher implements Serializable {
    private int id;
    private String name;
    List<Student> students;
}

修改TeacherMapper接口

package com.myLearning.Dao;


import com.myLearning.pojo.Teacher;


public interface TeacherMapper {
    Teacher getTeacherById(int id);
}

修改TeacherMapper.xml

第一种方法,使用嵌套查询的方法得到想要的结果

我们先查出指定id老师的信息,然后再利用这个信息去查询学生表得到学生信息,使用collection进行结果的映射

<?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.myLearning.Dao.TeacherMapper">
    <select id="getTeacherById" resultMap="teacherWithStudents">
        select * from teacher where id=#{id};
    </select>

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

    <resultMap id="teacherWithStudents" type="Teacher">
        <collection property="students" column="id" javaType="ArrayList" ofType="Student" select="getAllStudent"/>
    </resultMap>


</mapper>

第二种方法,我们直接使用一条SQL语句查询出所需要的所有信息, 然后直接在resultMap中的collection内进行映射

<?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.myLearning.Dao.TeacherMapper">
    <select id="getTeacherById" resultMap="teacherWithStudents">
        select s.id sid, t.id tid, s.name sname, t.name tname from teacher t,student s where s.tid=t.id and t.id=#{id};
    </select>

    <resultMap id="teacherWithStudents" type="Teacher">
        <result column="tid" property="id"/>
        <result column="tname" property="name"/>
         <collection property="students" ofType="Student">
            <result column="sid" property="id"/>
             <result column="sname" property="name"/>
             <result column="tid" property="tid"/>
        </collection>
    </resultMap>

</mapper>

动态SQL

动态SQL是什么?

动态SQL指的是根据不同的条件生成不同的SQL语句

使用动态SQL

搭建环境

创建所需数据库

create table `blog`(
  `id` VARCHAR(50) not null comment '博客ID',
  `title` VARCHAR(100) not null,
  `author` varchar(30) not null,
  `create_time` datetime not null,
  `views` int(30) not null
)ENGINE=InnoDB Default charset=utf8;

改动mybatis-config.xml

    <settings>
        <!-- 标准日志工厂实现 -->
<!--        <setting name="logImpl" value="STDOUT_LOGGING"/>-->
        <setting name="logImpl" value="LOG4J2"/>
<!-- 开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>

创建实体类

package com.myLearning.pojo;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
public class Blog implements Serializable {
    private String id;
    private String title;
    private String author;
    private Date createTime;
    private int views;
}

创建BlogMapper接口以及对应的xml文件,同时记得在mybatis-config.xml中注册

package com.myLearning.Dao;

import com.myLearning.pojo.Blog;

public interface BlogMapper {
    int addBlog(Blog blog) ;
}
<?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.myLearning.Dao.BlogMapper">
    <insert id="addBlog" parameterType="blog">
        insert into blog(id,title,author,create_time,views)
        values(#{id},#{title},#{author},#{createTime},#{views})
    </insert>
</mapper>

插入数据

package com.myLearning.Dao;

import com.myLearning.pojo.Blog;
import com.myLearning.util.IDUtils;
import com.myLearning.util.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.Date;

public class BlogMapperTest {
    @Test
    public void addBlogTest() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);

        Blog blog = new Blog();
        blog.setId(IDUtils.getID());
        blog.setAuthor("心理学家");
        blog.setCreateTime(new Date());
        blog.setViews(100);
        blog.setTitle("思考,快与慢");
        blogMapper.addBlog(blog);

        blog.setId(IDUtils.getID());
        blog.setAuthor("物理学家");
        blog.setCreateTime(new Date());
        blog.setViews(1000);
        blog.setTitle("广义相对论");
        blogMapper.addBlog(blog);

        blog.setId(IDUtils.getID());
        blog.setAuthor("哲学家");
        blog.setCreateTime(new Date());
        blog.setViews(10000);
        blog.setTitle("马克思主义");
        blogMapper.addBlog(blog);

        blog.setId(IDUtils.getID());
        blog.setAuthor("经济学家");
        blog.setCreateTime(new Date());
        blog.setViews(100000);
        blog.setTitle("宏观经济学");
        blogMapper.addBlog(blog);


        blog.setId(IDUtils.getID());
        blog.setAuthor("文学家");
        blog.setCreateTime(new Date());
        blog.setViews(1000);
        blog.setTitle("雪国");
        blogMapper.addBlog(blog);

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

if标签的使用

Mapper内添加接口

    List<Blog> getBlogIf(Map<String, Object> map);

xml实现

    <select id="getBlogIf" 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 testGetBlogIf() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);

        HashMap<String, Object> map = new HashMap<String, Object>();
        map.put("title", "雪国");
//        map.put("author", "文学家");

        List<Blog> blogs = blogMapper.getBlogIf(map);
        for (Blog blog : blogs) {
            System.out.println(blog);
        }

        sqlSession.close();
    }

where标签的使用

where标签可以生成where语句,如果where语句接的第一个是and,会自动去掉第一个and

使用where标签改进刚刚的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">
<!--用于绑定刚刚创建的Dao(Mapper)接口-->
<mapper namespace="com.myLearning.Dao.BlogMapper">
    <insert id="addBlog" parameterType="blog">
        insert into blog(id,title,author,create_time,views)
        values(#{id},#{title},#{author},#{createTime},#{views})
    </insert>

    <select id="getBlogIf" 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>
</mapper>

set标签的使用

set标签主要用于update语句,与where标签类似,set标签可以生成set语句,如果set标签生成的sql语句最后一个是‘,’会自动去掉最后一个‘,’

trim标签的使用

trim标签可以用于生成自定义的sql语句,where标签和set标签可以用trim标签替代
即trim标签可以生成where语句,也可以生成set语句

trim标签的属性:

  • prefix:在trim标签生成的sql语句前加上指定的前缀
  • suffix:在trim标签生成的sql语句后加上指定的后缀
  • prefixOverrides:在trim标签生成的sql语句前去掉指定的前缀
  • suffixOverrides:在trim标签生成的sql语句后去掉指定的后缀

choose标签的使用

choose标签类似于java中的switch语句,当choose标签中的when标签中的条件成立时,就会执行when标签中的sql语句,如果所有的when标签中的条件都不成立,就会执行otherwise标签中的sql语句

简单示例

Mapper类中添加方法

    List<Blog> getBlogChoose(Map<String, Object> map);

Mapper.xml中添加sql语句

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

测试

    @Test
    public void getBlogChooseTest() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        Map<String,Object> map = new HashMap<String,Object>();
//        map.put("author","经济学家");
        map.put("views",100);
        List<Blog> blogs = blogMapper.getBlogChoose(map);
        for(Blog blog : blogs){
            System.out.println(blog);
        }
        sqlSession.close();
    }

forEach标签

foreach标签主要用于循环遍历集合,常用于in条件中,如in (12,13,14), 可自行指定生成字符串的前缀、后缀、分隔符等。

简单示例

添加UserMapper接口中的方法

    List<Blog> getBlogForeach(Map<String, Object> map);

在mapper.xml中添加sql语句,其中使用foreach标签实现遍历views集合,使得查询结果的views均在在设定的集合内

    <select id="getBlogForeach" parameterType="map" resultType="blog">
        select * from blog
        <where>
           <foreach collection="views" item="view" open="views in (" close=")"
                    separator=",">
               #{view}
           </foreach>
        </where>
    </select>
测试
    @Test
    public void getBlogForeachTest() {
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
        Map<String,Object> map = new HashMap<String,Object>();
//        map.put("author","经济学家");
        List<Integer> views = new ArrayList<Integer>();
        views.add(100);
        views.add(1000);
        views.add(10000);
        map.put("views", views);
        List<Blog> blogs = blogMapper.getBlogForeach(map);
        for(Blog blog : blogs){
            System.out.println(blog);
        }
        sqlSession.close();
    }

sql片段

sql片段可以用来定义可重用的sql语句,在需要使用的地方使用include标签引入

例如,我们可以使用sql片段将我们写的if标签放在sql片段中,然后在需要使用的地方使用include标签引入

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

    <select id="getBlogIf" parameterType="map" resultType="com.zhang.pojo.Blog">
        select * from blog
        <where>
            <include refid="if-title-author"></include>
        </where>
    </select>

Mybatis缓存

缓存是什么?

在MyBatis中,缓存是一种用于提升数据库查询性能的机制,通过减少对数据库的直接访问来加快数据检索速度。

缓存的作用

缓存将查询结果存储在内存中,避免重复查询数据库,从而加快数据访问速度;减少数据库的访问次数,减轻数据库压力;直接从缓存获取数据,比从数据库查询更快。

MyBatis缓存分类

MyBatis提供了两种类型的缓存:一级缓存和二级缓存。

一级缓存

一级缓存是MyBatis在SqlSession级别维护的缓存,作用于SqlSession级别,默认情况下是开启的。当执行查询操作时,MyBatis会将查询结果存储在一级缓存中,当下一次相同的查询操作时,MyBatis会先从一级缓存中查找结果,如果找到了,就直接返回结果,避免了再次查询数据库。

一级缓存失效的情况
  1. 不同的SqlSession对应不同的一级缓存
  2. 同一个SqlSession但是查询条件不同
  3. 同一个SqlSession两次查询期间执行了增删改操作
  4. 同一个SqlSession两次查询期间手动清空了缓存,例如:sqlSession.clearCache();

二级缓存

二级缓存是MyBatis在SqlSessionFactory级别维护的缓存,作用于Mapper级别,默认情况下是关闭的。当执行查询操作时,MyBatis会先将查询结果放在一级缓存中,会话结束后,再存储在二级缓存中,当下一次相同的查询操作时,MyBatis会先从二级缓存中查找结果,如果找到了,就直接返回结果,避免了再次查询数据库。

二级缓存开启步骤
  1. 在MyBatis的配置文件中开启二级缓存配置
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
  1. 在Mapper文件中开启二级缓存配置
<cache/>

配置时可以设置的属性:

  • eviction:缓存回收策略,默认为LRU(最近最少使用)
  • flushInterval:缓存刷新间隔,默认为无,即没有刷新间隔
  • size:缓存存放多少元素,默认为1024
  • readOnly:是否只读,默认为false,即非只读,可读写
  1. 在需要使用二级缓存的方法上添加@CacheNamespace注解
@CacheNamespace(blocking = true)
public interface BlogMapper {
    // ...
}
  1. 在实体类上添加@CacheNamespace注解
@CacheNamespace(blocking = true)
public class Blog {
    // ...
}
二级缓存失效的情况
  1. 同一个Mapper中两次查询期间执行了增删改操作
  2. 同一个Mapper两次查询期间手动清空了缓存,例如:sqlSession.clearCache();
查询顺序
  1. 先查询二级缓存,二级缓存没有则查询一级缓存
  2. 一级缓存没有则查询数据库

自定义缓存

MyBatis允许自定义缓存,只需要实现Cache接口即可。除此之外,还可以使用第三方缓存,如Ehcache、Redis等。

自定义缓存实现步骤
  1. 实现Cache接口
public class MyCache implements Cache {
    // ...
}
  1. 在Mapper文件中配置自定义缓存
<cache type="com.example.MyCache"/>

笔记总结于视频:https://www.bilibili.com/video/BV1NE411Q7Nx/?vd_source=16bf0c507e4a78c3ca31a05dff1bee4e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值