学习Mybatis

news/2024/7/8 3:36:43 标签: 学习, 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.niftyadmin.cn/n/5536380.html

相关文章

ArmPiPro-环境变量

V0.0 2024-07-04 V0.1 加入开发环境和PI4关于ROS的环境变量的对比 1.我们可以用env | grep ROS来查看Pi4中的ROS环境变量 如下图所示&#xff0c;不理解的&#xff0c;抛给AI快速了解一下。 2.ArmPiPro安装的ROS是ROS1-melodic 3.在开发时&#xff0c;需要在笔记本电脑上开一…

CSS弹性布局:打造响应式与灵活的网页设计

一、弹性布局是什么&#xff1f; 弹性布局&#xff08;Flexbox&#xff09;是一种CSS布局模型&#xff0c;它提供了一种更加高效的方式来对容器中的项目进行布局、对齐和分配空间。与传统的布局方式相比&#xff0c;Flexbox旨在提供一个更加灵活的方式来布局复杂的网页结构&am…

MATLAB和Python发那科ABB库卡史陶比尔工业机器人模拟示教框架

&#x1f3af;要点 &#x1f3af;模拟工业机器人 | &#x1f3af;可视化机器人DH 参数&#xff0c;机器人三维视图 | &#x1f3af;绘制观察运动时关节坐标位置、速度和加速度 | &#x1f3af;绘制每个关节处的扭矩和力 | &#x1f3af;图形界面示教机器人 | &#x1f3af;工业…

js 递归调用 相同对象--数组递归调用

<div class="save-cl"> <a-button @click="saveCl" >保存为常用策略</a-button> </div> saveCl(){ console.log(this.form.filterList[0],--------常用策略)// 此对象为上图对象 console.log(this.allElementsHaveValue(thi…

【多媒体】富客户端应用程序GUI框架 JavaFX 2.0 简介

JavaFX 最初是由 Oracle 推出的一个用于开发富客户端应用程序的框架&#xff0c;它提供了丰富的用户界面控件、布局容器、3D图形绘制、媒体播放和动画等功能&#xff0c;旨在取代较旧的 Swing 框架。JavaFX 于 2007 年推出&#xff0c;2011 年 10 月发布了2.0 版本。JavaFX 2.0…

gin框架解决跨域问题

文章目录 前言一、使用github.com/gin-contrib/cors 前言 今天遇到了前后端跨域问题&#xff0c;前后端跨域解决蛮简单的&#xff0c;下面是解决方案 一、使用github.com/gin-contrib/cors go get github.com/gin-contrib/cors在路由的地方 r : gin.Default()corsConfig : c…

【FPGA-常见问题及解决方案】

1、VIVADO的License无法加载&#xff1a;license文件必须在英文路径&#xff1b; 2、例程代码路径不能过长&#xff0c;也不允许有中文路径&#xff01;&#xff01;&#xff01; 3、明明加载了license&#xff0c;license也正确&#xff0c;例程无法完成综合&#xff1a;这种情…

群发机器人windows

##||##…欢迎使用…Windows群发机器人…\n______________________________\n##||##