学习Mybatis

Mybatis

第一节 引言

1. 什么是框架

框架是一个半成品,解决了软件开发过程中的普遍性问题,简化了开发步骤,提高了开发效率。

2. 什么是ORM

ORM全称为Object Relational Mapping,意为对象关系映射,主要实现了将程序中的一个对象与表中的一行数据对应。ORM框架提供了持久化类与表的映射关系,在运行时把对象持久化到数据库中。

3. JDBC操作数据库的缺点

  • 存在大量的冗余代码。
  • 手工创建 Connection、Statement 等,效率低下。
  • 手工将结果集封装成实体对象。
  • 查询效率低,没有对数据访问进行优化。

Hibernate、JPA、Mybatis、Mybatis-plus、tk-mybatis

第二节 Mybatis框架

1. Mybatis简介

MyBatis 本是 apache 的一个开源项目 iBatis, 2010年这个项目由 apache software foundation 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github。

iBatis 一词来源于 “internet” 和 “abatis” 的组合,是一个基于Java的持久层框架。iBatis 提供的持久层框架包括 SQL Maps 和 Data Access Objects(DAOs)

MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 POJO(Plain Ordinary Java Objects,普通 Java 对象)为数据库中的记录。

2. 如何获取 Mybatis

官方网站: https://mybatis.org/mybatis-3/

最新版本Maven配置:

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

3. 如何使用 Mybatis

3.1 工程搭建

创建maven工程mybatis01,并引入依赖库

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.7</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.17</version>
</dependency>
3.2 config 配置文件

在resources目录下创建 config.xml

<!--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">
<!--MyBatis配置-->
<configuration>
    <!--JDBC环境配置、选中默认环境-->
    <environments default="dev">
        <!--MySql数据库环境配置-->
        <environment id="dev">
            <!--事务管理,这里的JDBC是一个类的别名:
             org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory-->
            <transactionManager type="JDBC"/>
            <!--连接池,这里的POOLED也是一个类的别名:
             org.apache.ibatis.datasource.pooled.PooledDataSourceFactory-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/lesson?serverTimezone=Asia/Shanghai&amp;tinyInt1isBit=false"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    <!--Mapper注册-->
    <mappers>
        <!--注册Mapper文件的所在位置-->
    </mappers>
</configuration>
3.3 创建表

在使用的数据库中创建数据表 user

DROP TABLE IF EXISTS user;
CREATE TABLE user(
  	username varchar(50) NOT NULL PRIMARY KEY COMMENT '账号',
  	password varchar(50) NOT NULL COMMENT '密码',
  	salt varchar(50) NOT NULL COMMENT '随机盐',
    name varchar(20) NOT NULL COMMENT '姓名',
    sex tinyint(1) UNSIGNED NOT NULL COMMENT '性别',
    address varchar(50) NOT NULL COMMENT '地址'
) ENGINE=InnoDB CHARSET=utf8;
3.4 创建实体类
public class User{
    
    private String username;
    
    private String password;
    
    private String salt;
    
    private String name;
    
    private int sex;
    
    private String address;
    //省略getter和setter
    //构造方法:要么无参,要么全参
}
3.5 创建Mapper接口
public interface UserMapper {
    
    User getUserByUsername(String username);
}
3.6 创建Mapper接口的映射文件

在 resources 目录下创建 mapper 目录来存放 Mapper 接口映射文件,方便管理。在 mapper 目录下创建userMapper.xml

<!--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">
<!--namespace = 所需实现的接口全限定名-->
<mapper namespace="com.qf.mybatis.mapper.UserMapper">
    <!--id表示接口中的方法名,resultType表示查询结果每一行数据对应的转换类型-->
    <select id="getUserByUsername" resultType="com.qf.mybatis.model.User">
        <!--#{arg0}表示获取方法参数列表中的第一个参数值-->
        <!--#{param1}表示获取方法参数列表中的第一个参数值-->
        SELECT username,password,salt,name,sex,address FROM user WHERE username=#{arg0}
    </select>
</mapper>
3.7 注册Mapper接口
<!--Mapper文件注册位置-->
<mappers>
    <!--注册Mapper文件-->
    <mapper resource="mapper/userMapper.xml"/>
</mappers>
3.8 测试
public class UserMapperTest{
    
    @Test
    public void getUserByUsernameTest() throws IOException{
        //创建SqlSessionFactory构建者
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //读取配置文件信息
        InputStream is = Resources.getResourceAsStream("config.xml");
        //SqlSessionFactory构建者根据配置文件信息构建SqlSessionFactory
        SqlSessionFactory factory = builder.build(is);
        //SqlSession工厂开启SqlSession => Sql会话 => Connection上进行信息传输就是会话
        SqlSession session = factory.openSession();
        //从Sql会话中获取UserMapper接口的代理对象
        UserMapper userMapper = session.getMapper(UserMapper.class);
        //调用接口方法进行查询
        User user = userMapper.getUserByUsername("admin");
        System.out.println(user);
    }
}

4. properties 文件配置

Mybatis支持properties文件的引入,这样做的目的就是为了区分配置:不同的文件中描述不同的配置,这样方便管理。 在 resources 目录下新建 jdbc.properties 文件,然后在 config.xml 中引入

#jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/lesson?characterEncoding=utf8&tinyInt1isBit=false
jdbc.username=root
jdbc.password=root
<!--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">
<!--MyBatis配置-->
<configuration>
    <!--引入jdbc.properties文件-->
    <properties resource="jdbc.properties" />
    <!--JDBC环境配置、选中默认环境-->
    <environments default="dev">
        <!--MySql数据库环境配置-->
        <environment id="dev">
            <!--事务管理,这里的JDBC是一个类的别名-->
            <transactionManager type="JDBC"/>
            <!--连接池,这里的POOLED也是一个类的别名-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driverClassName}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--Mapper注册-->
    <mappers>
        <!--注册Mapper文件-->
    	<mapper resource="mapper/userMapper.xml"/>
    </mappers>
</configuration>

5. 类型别名

在Mapper接口映射文件中,存在如下配置片段:

<!--userMapper.xml-->
<select id="getUserByUsername" resultType="com.qf.mybatis.model.User">
    ...
</select>

resultType 属性的配置比较繁琐,当大量使用该属性时,开发效率将变得非常低下。为了提高开发效率,Mybatis提供了为类型定义别名的功能。该功能需要在 config.xml 中进行配置

<!--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">
<!--MyBatis配置-->
<configuration>
    <!--引入jdbc.properties文件-->
    <properties resource="jdbc.properties" />
    <!--配置类型的别名:typeAlias方式和package方式只能选择其中之一-->
    <typeAliases>
        <!--配置单个类的别名-->
        <typeAlias方式和 type="com.qf.mybatis.model.User" alias="user" />
        <!--配置需要取别名的类的包,该包中所有类的别名均为类名-->
        <package name="com.qf.mybatis.model" />
    </typeAliases>
    ...
</configuration>

配置类型别名后,在接口的映射文件中就可以使用别名了。

<!--userMapper.xml-->
<select id="getUserByUsername" resultType="user">
    ...
</select>

6. 日志配置

Mybatis本身有提供日志功能,开启日志需要在 config.xml 进行配置

<!--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">
<!--MyBatis配置-->
<configuration>
    <!--引入jdbc.properties文件-->
    <properties resource="jdbc.properties" />
    <!-- 常用配置标签的先后顺序
        properties,
        settings,
        typeAliases,
        typeHandlers,
        plugins,
        environments,
        mappers 
        如果配置文件中同时存在这些配置标签,它们之间的顺序必须按照上述列表排列
	-->
    <settings>
        <!-- 打印SQL语句 STDOUT_LOGGING是一个类的别名:
            org.apache.ibatis.logging.stdout.StdOutImpl-->
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>
    <!--配置类型的别名:typeAlias方式和package方式只能选择其中之一-->
    <typeAliases>
        <!--配置单个类的别名-->
        <typeAlias type="com.qf.mybatis.model.User" alias="user" />
        <!--配置需要取别名的类的包,该包中所有类的别名均为类名-->
        <package name="com.qf.mybatis.model" />
    </typeAliases>
    ...
</configuration>

第三节 Mybatis增删改查

1. 参数取值

在Mybatis中,参数取值有两种方式:一种是#{表达式}, 另一种是 **${表达式} ** ;

#{表达式} 采用的是JDBC中的预编译来实现,因此可以防止SQL注入。

**${表达式} ** 采用的是字符串拼接,因此常用在排序字段变化、分组字段变化、查询表名变化等场景。

在Mapper接口中,如果接口方法带有多个参数,如何对这些参数取值呢? Mybatis提供了两种表达式的写法来进行参数取值,一种是通过arg参数下标取该参数的值;一种是通过param参数位置,后面采用JDBC设置参数值的方法,需要注意的是,参数位置是从1开始

当接口方法的参数列表中只有1个参数时,表达式的写法将没有限制,任意内容均可获取到该参数的值

1.1 常用数据类型作为参数
//在UserMapper接口中添加接口方法
List<User> getUsers(String name, int sex);//根据姓名,性别查询用户信息
<!--在userMapper.xml中添加查询标签-->
<select id="getUsers" resultType="user">
	SELECT 
    	username,
    	password,
        salt,
        name,
        sex,
        address 
        FROM 
        user 
    WHERE 
    	name LIKE CONCAT('%', #{arg0},'%')
    AND
    	sex = #{arg1}
</select>
1.2 实体对象作为参数
  • 单个对象参数
//编写查询条件类
public class UserCondition{
    private String name;
    private int sex;
    //省略 getter 和 setter 方法
}

//在UserMapper接口中添加接口方法
public List<User> searchUsers(UserCondition condition);//根据姓名,性别查询用户信息
<!--在userMapper.xml中添加查询标签-->
<select id="getUsers" resultType="user">
	SELECT 
    	username,
    	password,
        salt,
        name,
        sex,
        address 
        FROM 
        user 
    WHERE 
    	name LIKE CONCAT('%', #{name},'%')
    AND
    	sex = #{sex}
</select>
  • 多个对象参数
//在UserMapper接口中添加接口方法
List<User> findUsers(String address, UserCondition userCondition);
<!--在userMapper.xml中添加查询标签-->
<select id="findUsers" resultType="user">
        SELECT
            username,
            password,
            salt,
            name,
            sex,
            address
        FROM
            USER
        WHERE
            address LIKE CONCAT('%', #{arg0}, '%')
        AND name LIKE CONCAT('%', #{arg1.name}, '%')
        AND sex = #{arg1.sex}
    </select>
1.3 Map作为参数【非常重要】

由于Map中存放的数据是通过键值对实现的,因此可以将Map当做一个实体类对象来看待。Map中的键就相当于实体类中的属性名,Map中的值就相当于实体类中的属性值。因此,其取值方式与实体类对象作为参数一样。

//在UserMapper接口中添加接口方法
List<User> queryUsers(Map<String, Object> params);
<!--在userMapper.xml中添加查询标签-->
<select id="findUsers" resultType="user">
    SELECT
        username,
        password,
        salt,
        name,
        sex,
        address
    FROM
    	USER
    WHERE
    	address LIKE CONCAT('%', #{address}, '%')
    AND name LIKE CONCAT('%', #{name}, '%')
    AND sex = #{sex}
</select>
1.4 参数注解

为了方便开发,Mybatis对参数提供了注解,从而可以给参数指定名称,方便在对应的Mapper映射文件中使用

//在UserMapper接口中添加接口方法
List<User> retrieveUsers(@Param("condition") Map<String,Object> params);
<!--在userMapper.xml中添加查询标签-->
<select id="findUsers" resultType="user">
    SELECT
        username,
        password,
        salt,
        name,
        sex,
        address
    FROM
    	USER
    WHERE
    	address LIKE CONCAT('%', #{condition.address}, '%')
    AND name LIKE CONCAT('%', #{condition.name}, '%')
    AND sex = #{condition.sex}
</select>

2. 增删改

<!--增加标签-->
<insert id="addUser">

</insert>
<!--修改标签-->
<update id="updateUser">

</update>
<!--删除标签-->
<delete id="deleteUser">

</delete>

3. 主键回填

当保存一条数据时,有时我们需要该数据的ID,ID 生成有两种方式:一种是数据库自动生成,另一种是程序通过编码生成。Mybatis 也提供了这两种方式来生成ID,ID生成后可以设置到给定的属性上,这个过程称之为主键回填。

-- 创建表
DROP TABLE IF EXISTS score;
CREATE TABLE score (
    -- 主键自增
    id bigint(20) NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '主键',
    name varchar(20) NOT NULL COMMENT '姓名',
    score double(5,2) DEFAULT NULL COMMENT '成绩'
) ENGINE=InnoDB CHARSET=UTF8;

DROP TABLE IF EXISTS article;
CREATE TABLE `article` (
    -- 主键需要传值
  `id` varchar(50) NOT NULL PRIMARY KEY COMMENT '主键',
  `title` varchar(50) NOT NULL COMMENT '标题',
  `content` varchar(255) NOT NULL COMMENT '内容',
  `author` varchar(20) NOT NULL COMMENT '作者'
) ENGINE=InnoDB CHARSET=UTF8
// 创建实体类 成绩
public class Score {
    
    private long id;
    
    private String name;
    
    private Double score;
    //省略getter和setter
    //构造方法:要么无参,要么全参
}
// 创建实体类 文章
public class Article {
    
    private String id;
    
    private String title;
    
    private String content;
    
    private String author;
    //省略getter和setter
    //构造方法:要么无参,要么全参
}

// 创建Mapper接口
public interface ScoreMapper {
    
    int addScore(@Param("score") Score score);
}
// 创建Mapper接口
public interface ArticleMapper {
    
    int addArticle(@Param("article") Article article);
}
<?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.qf.mybatis.mapper.ScoreMapper">
    <insert id="addScore">
        <!-- selectKey表示选择键 通常都是用于主键回填功能 keyProperty表示回填的值设置到哪个属性上
			resultType表示回填的值的数据类型  order表示主键回填的时机 AFTER表示数据保存后 BEFORE表
            示数据插入之前-->
        <selectKey keyProperty="score.id" resultType="long" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO score(name, score)VALUES(#{score.name}, #{score.score})
    </insert>
</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.qf.mybatis.mapper.ArticleMapper">
    <insert id="addArticle">
        <selectKey keyProperty="article.id" resultType="string" order="BEFORE">
            SELECT REPLACE(UUID(),'-','')
        </selectKey>
        INSERT INTO article(id, title, content, author)
        VALUES (#{article.id}, #{article.title}, #{article.content}, #{article.author})
    </insert>
</mapper>

主键回填的应用场景: 如果一个业务,需要增加一条记录,然后还需要增加的相关的记录,这个相关的记录就需要使用到前一条记录的主键。

4. 结果映射

在SQL查询时,我们经常会遇到数据库表中设计的字段名与对应的实体类中的属性名不匹配的情况,针对这种情况,Mybatis 提供了结果集映射,供用户自己实现数据库表中字段与实体类中属性进行匹配。

DROP TABLE IF EXISTS employee;
CREATE TABLE employee(
  id int NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '员工编号',
  name varchar(30) NOT NULL COMMENT '姓名',
  entry_time datetime NOT NULL COMMENT '入职时间',
  leave_time datetime DEFAULT NULL COMMENT '离职时间'
) ENGINE=InnoDB CHARSET=UTF8;
// 创建实体类 员工
public class Employee {
    
    private long id;
    
    private String name;
    
    private Date entryTime;
    
    private Date leaveTime;
     //省略getter和setter
    //构造方法:要么无参,要么全参
}

// 创建Mapper接口
public interface EmployeeMapper {

    List<Employee> getAllEmployees();
}
<?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.qf.mybatis.mapper.EmployeeMapper">

    <resultMap id="empMap" type="com.qf.mybatis.model.Employee">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <!--数据表中列名与实体类中的属性名匹配-->
        <result property="entryTime" column="entry_time" />
        <!--数据表中列名与实体类中的属性名匹配-->
        <result property="leaveTime" column="leave_time" />
    </resultMap>

    <select id="getAllEmployees" resultMap="empMap">
        SELECT id,name,entry_time,leave_time FROM employee
    </select>
</mapper>

第四节 Mybatis级联查询

1. 一对一级联查询

DROP TABLE IF EXISTS passenger;
CREATE TABLE passenger (
  id bigint NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '乘客编号',
  name varchar(50) NOT NULL COMMENT '姓名',
  sex tinyint(1) NOT NULL DEFAULT '0' COMMENT '性别',
  birthday date NOT NULL COMMENT '生日'
) ENGINE=InnoDB CHARSET=UTF8;

DROP TABLE IF EXISTS passport;
CREATE TABLE passport (
  id bigint NOT NULL AUTO_INCREMENT COMMENT '护照编号',
  office varchar(50) NOT NULL COMMENT '签证机关',
  valid_time tinyint NOT NULL COMMENT '有效期限',
  nationality varchar(50) NOT NULL COMMENT '国籍',
  passenger_id bigint NOT NULL COMMENT '乘客编号',
  PRIMARY KEY (id),
  FOREIGN KEY (passenger_id) REFERENCES passenger (id)
) ENGINE=InnoDB CHARSET=UTF8;
public class Passport {

    private long id;

    private String nationality;

    private int validTime;

    private String office;
    
    //省略getter和setter
    //构造方法:要么无参,要么全参
}

public class Passenger {

    private long id;

    private String name;

    private int sex;

    private Date birthday;

    private Passport passport; //对象作为属性

    //省略getter和setter
    //构造方法:要么无参,要么全参
}

public interface PassengerMapper {
    
    List<Passenger> getAllPassengers();
}
<?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.qf.mybatis.mapper.PassengerMapper">

    <resultMap id="passengerMap" type="com.qf.mybatis.model.Passenger">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <result property="sex" column="sex" />
        <result property="birthday" column="birthday" />
        <!-- 一对一 级联 方式一 -->
        <association property="passport" javaType="com.qf.mybatis.model.Passport">
            <id property="id" column="passportId" />
            <result property="nationality" column="nationality" />
            <result property="office" column="office" />
            <result property="validTime" column="validTime" />
        </association>
        <!-- 一对一 级联 方式二 {pid=id} 表示传递的参数值使用的id,传递过去的变量名为pid,传递多个参数时使用逗号分隔开-->
        <!--<association property="passport" select="getPassport" column="{pid=id}"/>-->
    </resultMap>

    <select id="getAllPassengers" resultMap="passengerMap">
        SELECT
            a.id,
            a.name,
            a.sex,
            a.birthday,
            b.id passportId,
            b.nationality,
            b.office,
            b.valid_time validTime
        FROM
            passenger a,
            passport b
        WHERE
            a.id = b.passenger_id
    </select>

    <!--<select id="getAllPassengers" resultMap="passengerMap">
        SELECT
            id,
            name,
            sex,
            birthday
        FROM
            passenger
    </select>

    <select id="getPassport" resultType="com.qf.mybatis.model.Passport">
        SELECT
            id,
            office,
            valid_time validTime,
            nationality
        FROM
            passport
        WHERE passenger_id = #{pid}
    </select>-->
</mapper>

2. 一对多级联查询

DROP TABLE IF EXISTS class;
CREATE TABLE class (
  id int NOT NULL AUTO_INCREMENT PRIMARY KEY COMMENT '班级编号',
  name varchar(50) NOT NULL COMMENT '名称'
) ENGINE=InnoDB CHARSET=UTF8;

DROP TABLE IF EXISTS student;
CREATE TABLE student (
  id bigint NOT NULL AUTO_INCREMENT COMMENT '学号',
  name varchar(50) NOT NULL COMMENT '姓名',
  class_id int NOT NULL COMMENT '班级编号',
  PRIMARY KEY (id),
  FOREIGN KEY (class_id) REFERENCES class (id)
) ENGINE=InnoDB CHARSET=UTF8;
public class Student {

    private long id;

    private String name;
}
public class Clazz {

    private int id;

    private String name;

    private List<Student> students; //集合作为属性
}

public interface PassengerMapper {

    List<Passenger> getAllPassengers();
}
<?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.qf.mybatis.mapper.ClassMapper">

    <resultMap id="clazzMap" type="com.qf.mybatis.model.Clazz">
        <id property="id" column="id" />
        <result property="name" column="name" />
        <!-- 一对多 级联 方式一 -->
        <collection property="students" ofType="com.qf.mybatis.model.Student" column="id">
            <id property="id" column="sid" />
            <result property="name" column="name" />
        </collection>
        <!-- 一对多 级联 方式二 -->
        <!--<collection property="students" select="getStudents" column="{cid=id}"/>-->
    </resultMap>

    <select id="getClazzList" resultMap="clazzMap">
        SELECT
            a.id,
            a.name,
            b.id sid,
            b.name sname
        FROM
            class a,
            student b
        WHERE
            a.id = b.class_id
    </select>

   <!-- <select id="getClazzList" resultMap="clazzMap">
        SELECT
            id,
            name
        FROM
            class
    </select>

    <select id="getStudents" resultType="com.qf.mybatis.model.Student">
        SELECT
            id,
            name
        FROM
            student
        WHERE
            class_id = #{cid}
    </select>-->
</mapper>

第五节 动态SQL

1. sql 标签

为了方便SQL代码的重复利用,Mybatis 提供了 sql 标签为特定的SQL代码进行重用

<!--多条SQL都会使用的字段可以使用sql标签来定义,使用时通过include标签来引入-->
<sql id="fields">
    username, password,salt,sex,address
</sql>

<select id="getUserByUsername" resultType="user">
    SELECT
    <include refid="fields" />
    FROM
    `user`
    WHERE
    username = #{abcde}
</select>

<select id="searchUsers" resultType="user">
    SELECT
    <include refid="fields" />
    FROM
    `user`
    WHERE
    name LIKE CONCAT('%', #{name}, '%')
    AND address LIKE CONCAT('%', #{address}, '%')
</select>

<select id="queryUsers" resultType="user">
    SELECT
    <include refid="fields" />
    FROM
    `user`
    WHERE
    name LIKE CONCAT('%', #{c.name}, '%')
    AND address LIKE CONCAT('%', #{c.address}, '%')
</select>

<select id="findUsers" resultType="user">
    SELECT
    <include refid="fields" />
    FROM
    `user`
    WHERE
    sex = #{arg0}
    AND name LIKE CONCAT('%', #{arg1.name}, '%')
    AND address LIKE CONCAT('%', #{arg1.address}, '%')
</select>

<select id="retrieveUsers" resultType="user">
    SELECT
    <include refid="fields" />
    FROM
    `user`
    WHERE
    sex = #{sex}
    AND name LIKE CONCAT('%', #{name}, '%')
    AND address LIKE CONCAT('%', #{address}, '%')
</select>

2. if 标签

在日常开发过程中,我们经常会遇到带条件查询,但用户通常不会将所有的查询条件都填写,只是填写其中部分,每个用户填写的查询条件也不完全相同,那么在编写SQL语句时就难以确定查询条件。为了解决这个问题,Mybatis 提供了 if 标签来进行验证,如果满足,才将标签内的内容拼接至SQL语句中。

//ScoreMapper中新增接口 
List<Score> getScores(@Param("params") Map<String,Object> params);
<!-- scoreMapper.xml 中新增查询标签 -->
<select id="getScores" resultType="score">
    SELECT id,name,score FROM score WHERE 1=1
    <if test="params.name != null and params.name != ''">
        AND name LIKE CONCAT('%', #{params.name}, '%')
    </if>
    <if test="params.scoreFrom != null and params.scoreFrom != ''">
        AND score >= #{params.scoreFrom}
    </if>
    <if test="params.scoreTo != null and params.scoreTo != ''">
        <![CDATA[
            AND score <= #{params.scoreTo}
        ]]>
    </if>
</select>

3. where标签

在条件查询中,有时存在有效查询条件,有时不存在有效查询条件,那么 SQL 代码中 WHERE 的使用就显得比较繁琐了,为了解决这个问题,Mybatis 提供了 where 标签来解决这个问题。当 where 标签内存在查询条件时, where 标签会在SQL代码中添加 WHERE 关键字; 当 where 标签内不不存在查询条件时, where 标签将忽略 WHERE 关键字的添加。除此之外,where 标签还将自动忽略其后的 AND 或者 OR 关键字。

<!-- scoreMapper.xml 中getSCores修改 -->
<select id="getScores" resultType="score">
    SELECT id,name,score FROM score
    <where>
        <if test="params.name != null and params.name != ''">
            AND name LIKE CONCAT('%', #{params.name}, '%')
        </if>
        <if test="params.scoreFrom != null and params.scoreFrom != ''">
            AND score >= #{params.scoreFrom}
        </if>
        <if test="params.scoreTo != null and params.scoreTo != ''">
            <![CDATA[
                AND score <= #{params.scoreTo}
            ]]>
        </if>
    </where>
</select>

4. set 标签

在日常开发过程中经常会遇到动态更新的情况,面对这个场景,Mybatis 提供了 set 标签来解决此类问题。

set 标签还具有忽略最后一个SQL子句的后缀,比如逗号。

//ScoreMapper中新增接口 
int updateScore(@Param("s") Score score);
<!-- scoreMapper.xml 中新增修改标签 -->
<update id="updateScore">
    UPDATE score
    <set>
        <if test="s.name != null and s.name != ''">
            name = #{s.name},
        </if>
        <if test="s.score != null and s.score != ''">
            score = #{s.score},
        </if>
    </set>
    <where>
        <if test="s.id != null and s.id != ''">
            AND id = #{s.id}
        </if>
    </where>
</update>

5. trim 标签

Mybatis 提供了 trim 标签来代替 where 标签和 set 标签。其语法如下:

<!-- 其中 prefixOverrides 属性表示要被重写的前缀,prefix 属性表示用来替换重写的前缀内容。suffix和suffixOvverdides 属性表示对后缀的处理-->
<trim prefix="" prefixOverrides="" suffix="" suffixOverrides=""></trim>
<select id="getScores" resultType="score">
    SELECT id,name,score FROM score
    <trim prefix="WHERE" prefixOverrides="AND">
        <if test="params.name != null and params.name != ''">
            AND name LIKE CONCAT('%', #{params.name}, '%')
        </if>
        <if test="params.scoreFrom != null and params.scoreFrom != ''">
            AND score >= #{params.scoreFrom}
        </if>
        <if test="params.scoreTo != null and params.scoreTo != ''">
            <![CDATA[
                AND score <= #{params.scoreTo}
            ]]>
        </if>
    </trim>
</select>

<update id="updateScore">
    UPDATE score
    <trim suffixOverrides="," suffix="">
        <if test="s.name != null and s.name != ''">
            name = #{s.name},
        </if>
        <if test="s.score != null and s.score != ''">
            score = #{s.score},
        </if>
    </trim>
    <where>
        <if test="s.id != null and s.id != ''">
            AND id = #{s.id}
        </if>
    </where>
</update>

6. foreach 标签

在查询条件中,有时我们会传递一个数组或者一个集合作为查询的条件,此时,需要遍历这个集合才能完成 SQL 语句的组装,为了解决这个问题,Mybatis 提供了 foreach 标签来进行遍历。其语法规则如下:

<!-- 
	collection表示遍历的元素类型,如果参数没有使用注解命名,那么该属性值只能是list,array,map其中之一;如果参数使用了注解命名,那么该属性值直接使用注解指定的名称即可。
	item表示每次遍历时使用的对象名
	open表示前面添加的内容
	close表示最后添加的内容
	seperator表示每次遍历时内容组装使用的分割符
	index表示遍历时的下标
-->
<foreach collection="" item="" open="" seperator="" close="" index="">

</foreach>
//ScoreMapper中新增接口 
int deleteScore(@Param("ids")int[] scoreIds);
<delete id="deleteScore">
    DELETE FROM score WHERE id IN
    <foreach collection="ids" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</delete>

第六节 Mybatis缓存

1. 缓存的定义

缓存就是存储在内存中的临时数据,将用户经常查询的数据放在缓存(内存)中,用户再次查询数据的时候就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,能够提高查询效率,解决了高并发系统的性能问题

2. 缓存的优势

减少和数据库的交互次数,减少系统开销,提高系统效率

3. 缓存使用场景

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

4. Mybatis 缓存

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

mybatis系统默认定义了两级缓存:一级缓存和二级缓存

  • 一级缓存:

    默认情况下只有一级缓存开启(SqlSession级别的缓存,也称为本地缓存),同一个 SqlSession 执行多次同构查询时,结果将放入一级缓存。

  • 二级缓存:

    需要手动开启和配置,它是基于SqlSessionFactory级别的缓存,同一个 SqlSessionFactory 构建的 SqlSession 发起的多次同构查询,如果SqlSession关闭,则会将数据保存在二级缓存中

4.1 全局缓存配置
 <!-- config.xml-->
<settings>
    <setting name="cacheEnabled" value="true"/>
</settings>
4.2 Mapper缓存配置
<!--
    cache标签表示使用缓存
    flushInterval:表示缓存刷新时间,单位是毫秒
    readyOnly:表示是否只读;true 只读,MyBatis 认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。MyBatis 为了加快获取数据,直接就会将数据在缓存中的引用交给用户。不安全,速度快。读写(默认):MyBatis 觉得数据可能会被修改
    size:表示存放多少条数据
    eviction: 缓存回收策略,有这几种回收策略
        LRU - 最近最少回收,移除最长时间不被使用的对象
        FIFO - 先进先出,按照缓存进入的顺序来移除它们
        SOFT - 软引用,移除基于垃圾回收器状态和软引用规则的对象
        WEAK - 弱引用,更积极的移除基于垃圾收集器和弱引用规则的对象
    -->
<cache flushInterval="300000" readOnly="true" size="10000" eviction="LRU"/>
4.3 二级缓存失效

二级缓存缓存数据的前提是查询的 SqlSession 关闭,如果 SqlSession 没有关闭,那么数据将不会进入二级缓存,再次进行同构查询时,二级缓存由于没有数据,查询将进入数据库,造成二级缓存失效的现象。另一种情况是,当前查询的 SqlSession 已经关闭,数据也进入了二级缓存,但在下一次查询之前,如果中间发生了更新操作,该操作更新的数据在的二级缓存中存在,那么二级缓存也将失效。

第七节 分页插件 PageHelper

1. 如何获取PageHelper

官方网站: https://pagehelper.github.io/

最新版本Maven配置:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.0</version>
</dependency>

2. 插件配置

<!-- config.xml中进行配置 -->
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

3. 测试分页

@Test
public void paginationTest(){
    SqlSession sqlSession = MybatisUtil.openSession();
    //从Sql会话中获取Mapper接口的代理实例
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    Map<String,Object> params = new HashMap<>();
    params.put("sex", 1);
    params.put("name", "理");
    params.put("address", "千");
    //设置分页
    PageHelper.startPage(1, 5);
    List<User> users = userMapper.retrieveUsers(params);
    PageInfo<User> pageInfo = new PageInfo<>(users);//将分页查询的结果集保存在PageInfo对象中
    System.out.println("总条数:" + pageInfo.getTotal());
    System.out.println("总页数:" + pageInfo.getPages());
    //当前页数据展示
    pageInfo.getList().forEach(System.out::println);
}

第八节 配置数据源 Druid

Druid 是阿里巴巴开源平台上的一个项目,是性能最好的数据库连接池,如何在Mybatis中配置该数据源呢?

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.8</version>
</dependency>

创建 DruidDataSourceFactory, 并继承 PooledDataSourceFactory,并替换数据源

public class DruidDataSourceFactory extends PooledDataSourceFactory {
    public DruidDataSourceFactory() {
        this.dataSource = new DruidDataSource();//替换数据源
    }
}
<!--config.xml-->
<dataSource type="com.qf.mybatis.datasource.DruidDataSourceFactory"><!--数据源工厂-->
...
</dataSource>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/769905.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SCI丨一篇待投2区,计算机结合复合材料

题目:基于空间状态xxxx智能复合材料板的声辐射控制 期刊&#xff1a;2区 状态&#xff1a;准备提交 摘要&#xff1a;研究了xxxxx无限流体介质相互作用的有源声辐射的影响。

JAVA实现二分查找,斐波那契数列,深度优先搜索详情教程【包含代码】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

计算机网络 | 期末复习

物理层&#xff1a; 奈氏准则&#xff1a;带宽&#xff08;w Hz&#xff09;&#xff0c;在不考虑噪音的情况下&#xff0c;最大速率&#xff08;2W&#xff09;码元/秒 信噪比S/N&#xff1a;以分贝&#xff08;dB&#xff09;为度量单位。信噪比&#xff08;dB&#xff09;…

ueditor集成秀米编辑器

ueditor集成秀米编辑器 一、背景二、集成秀米编辑器流程2.1、新增秀米插件的按钮&#xff0c;显示在我们的富文本编辑器上2.2、点击该按钮&#xff0c;可以呼出一个iframe&#xff0c;这个iframe引用的是秀米自己的编辑器页面2.3、要是有图片&#xff0c;需要再修改配置哈2.4、…

react ts 封装3D柱状图,支持渐变

留档&#xff0c;以防忘记 bar3D.tsx import React, { useEffect, useRef, useState } from react; import * as echarts from echarts; import echarts/lib/chart/bar; import echarts/lib/chart/pictorialBar; import echarts/lib/component/grid; import echarts/lib/comp…

HTML总结2

什么是HTML HTML&#xff08;Hypertext Markup Language&#xff09;&#xff0c;超文本标记语言&#xff0c;&#xff08;是一套标记标签&#xff0c;一般用来描述网页&#xff09;。 HTML标签 HTML标记标签&#xff0c;通常被称为HTML标签&#xff0c;或者HTML标记。 标签…

VScode使用ssh连接服务器

VScode是一款有丰富插件的编译器&#xff0c;非常好用&#xff01;除非你不会用&#xff0c;因为太过繁琐或着频繁出错导致想把电脑砸了&#xff1b; 插件选择 ssh 配置文件 Host myblablaHostName xxx.xx.xxx.xxxUser username用户名一般是服务器上创建有什么用户名&#xf…

【STM32】在标准库中使用DMA

1.MDA简介 DMA全称Direct Memory Access,直接存储区访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作&#xff0c;传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输&#xff0c;也没有中断处理方式那样保留现场和…

seq2seq+Attention机制原理介绍

一、Seq2seq的局限性 Seq2seq&#xff08;序列到序列&#xff09;模型我们在前面讲了它的原理&#xff0c;是一种广泛用于处理序列转换任务的深度学习架构&#xff0c;特别是在机器翻译、文本摘要、对话生成等应用中。然而&#xff0c;尽管seq2seq模型在某些领域取得了显著的成…

使用 Python2.7 抓取 systrace 文件

为了排查安卓终端系统底层问题&#xff0c;需要抓取终端的systrace文件分析&#xff0c;下面是操作步骤&#xff1a; 1、安装python 2.7 2、打开cmd执行命令安装python包&#xff1a;pip install pypiwin32 3、解压six-1.16.0.tar.gz&#xff0c;进入目录用命令安装six&#xf…

《UDS协议从入门到精通》系列——图解0x84:安全数据传输

《UDS协议从入门到精通》系列——图解0x84&#xff1a;安全数据传输 一、简介二、数据包格式2.1 服务请求格式2.2 服务响应格式2.2.1 肯定响应2.2.2 否定响应 Tip&#x1f4cc;&#xff1a;本文描述中但凡涉及到其他UDS服务的&#xff0c;均提供专栏内文章链接跳转方式以便快速…

Stable Diffusion最强功能—— 图片背景完美替换

今天分享 Stable Diffusion 图片背景完美替换 功能&#xff0c;通过 Stable Diffusion 图生图重绘蒙版进行背景图的二次重绘。 在广告产品图、头像背景替换、图片后期处理等场景下用到的都很频繁。 整体步骤&#xff1a; 通过 removebg 插件实现图片主体蒙版的抠图 结合图生…

提升研发效能的67个技术点丨IDCF

在当今快速变化的市场环境中&#xff0c;企业要想保持竞争力&#xff0c;就必须不断提高研发效率。高效的研发不仅能够帮助企业快速响应市场需求&#xff0c;还能降低成本、提高产品质量。本文让我们一起来看一下&#xff0c;作为微软18年MVP的技术大咖徐磊老师&#xff0c;梳理…

HTML CSS 基础复习笔记 - 列表使用

用于自己复习 自定义列表 示例代码 <!DOCTYPE html> <html> <head><title>Definition List Example</title> </head> <body><h1>古诗</h1><dl><dt>静夜思</dt><dd>床前明月光&#xff0c;疑…

使用dot来画流程图

Dot是一种图形描述语言&#xff0c;属于Graphviz软件的一部分。Graphviz是一个用于可视化图形&#xff08;图表、网络图等&#xff09;的开源工具集。使用Dot语言&#xff0c;你可以创建并描述节点和边&#xff0c;从而生成图形。以下是如何使用Dot语言画图的基本步骤&#xff…

修复 OpenSSH 爆出极其严重的安全漏洞!

最近几天OpenSSH爆出了一个高危漏洞&#xff1a;CVE-2024-6387&#xff0c;影响到了很多的Linux服务器系统。明月第一时间给所有的代维客户服务器进行了排查和漏洞修复&#xff0c;因此耽搁了一些时间。直到今天才算抽出空来给大家分享一下。严格上来说这个漏洞的危险性还是极高…

Beyond Compare 解锁版下载及安装教程 (文件和文件夹比较工具)

前言 Beyond Compare 是一款功能强大的文件和文件夹比较工具。它支持文件夹比较、文件夹合并与同步、文本比较、表格比较、图片比较、16进制比较、注册表比较、版本比较等多种功能。通过 Beyond Compare&#xff0c;您可以轻松调查文件和文件夹之间的不同之处&#xff0c;并使…

MySQL篇-SQL优化实战-减少子查询

回顾 上一篇了解了分析SQL使用的explain&#xff0c;可以点击查看MySQL篇-SQL优化实战了解我在写sql的注意事项还有explain的说明&#xff0c;这次拿一段生产使用的sql进行优化说明。从14s优化到2.6s 待优化的SQL SELECT DISTINCTswpe.tag_number,hca.ACCOUNT_NAME customer…

ELFK简介

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

K8S学习教程(二):在 PetaExpress KubeSphere容器平台部署高可用 Redis 集群

前言 Redis 是在开发过程中经常用到的缓存中间件&#xff0c;为了考虑在生产环境中稳定性和高可用&#xff0c;Redis通常采用集群模式的部署方式。 在制定Redis集群的部署策略时&#xff0c;常规部署在虚拟机上的方式配置繁琐并且需要手动重启节点&#xff0c;相较之下&#…