学习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{@Testpublic void getUserByUsernameTest() throws IOException{//创建SqlSessionFactory构建者SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();//读取配置文件信息InputStream is = Resources.getResourceAsStream("config.xml");//SqlSessionFactory构建者根据配置文件信息构建SqlSessionFactorySqlSessionFactory 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},'%')ANDsex = #{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},'%')ANDsex = #{sex}
</select>
  • 多个对象参数
//在UserMapper接口中添加接口方法
List<User> findUsers(String address, UserCondition userCondition);
<!--在userMapper.xml中添加查询标签-->
<select id="findUsers" resultType="user">SELECTusername,password,salt,name,sex,addressFROMUSERWHEREaddress 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">SELECTusername,password,salt,name,sex,addressFROMUSERWHEREaddress 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">SELECTusername,password,salt,name,sex,addressFROMUSERWHEREaddress 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">SELECTa.id,a.name,a.sex,a.birthday,b.id passportId,b.nationality,b.office,b.valid_time validTimeFROMpassenger a,passport bWHEREa.id = b.passenger_id</select><!--<select id="getAllPassengers" resultMap="passengerMap">SELECTid,name,sex,birthdayFROMpassenger</select><select id="getPassport" resultType="com.qf.mybatis.model.Passport">SELECTid,office,valid_time validTime,nationalityFROMpassportWHERE 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">SELECTa.id,a.name,b.id sid,b.name snameFROMclass a,student bWHEREa.id = b.class_id</select><!-- <select id="getClazzList" resultMap="clazzMap">SELECTid,nameFROMclass</select><select id="getStudents" resultType="com.qf.mybatis.model.Student">SELECTid,nameFROMstudentWHEREclass_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`WHEREusername = #{abcde}
</select><select id="searchUsers" resultType="user">SELECT<include refid="fields" />FROM`user`WHEREname LIKE CONCAT('%', #{name}, '%')AND address LIKE CONCAT('%', #{address}, '%')
</select><select id="queryUsers" resultType="user">SELECT<include refid="fields" />FROM`user`WHEREname LIKE CONCAT('%', #{c.name}, '%')AND address LIKE CONCAT('%', #{c.address}, '%')
</select><select id="findUsers" resultType="user">SELECT<include refid="fields" />FROM`user`WHEREsex = #{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`WHEREsex = #{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.mzph.cn/diannao/40397.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

usecallback()与usememo()

简单的说 都是用来监听数据变化 来进行控制渲染、减少不必要的渲染 、优化性能 usecallback()是用来监听数据变化从而调用方法 usememo()是用来监听数据变化从而改变数据 使用return返回变化的数据 当然return 也可以返回方法 所以usememo()可以代替usecallback() 下面详解 …

常见的编码技术简介

常见的编码技术简介 文章目录 常见的编码技术简介1. 字符编码1.1 ASCII1.2 Unicode 2. 数据传输编码2.1 Base系列编码2.1.1 Base642.1.2 Base162.1.3 Base322.1.4 Base852.1.5 其他Base编码 2.2 URL编码2.3 JSON2.4 XML2.5 Protobuf (Protocol Buffers) 1. 字符编码 1.1 ASCII…

AI是在帮助开发者还是取代他们?——探讨AI在软件开发中的角色与未来

引言 随着人工智能技术的迅猛发展&#xff0c;AI工具在软件开发中的应用越来越广泛。有人认为AI可以显著提升开发者的效率&#xff0c;而也有人担心AI会取代开发者的工作。本文将从三个方面探讨AI在软件开发中的角色&#xff1a;AI工具现状、AI对开发者的影响以及AI开发的未来…

学习springAOP

第三章 Spring AOP 第一节 AOP 简介 1. 概念 AOP全称为Aspect Oriented Programming&#xff0c;表示面向切面编程。何为切面呢&#xff1f; 由此可以得出&#xff0c;切面是一种将那些与业务无关&#xff0c;但业务模块都需要使用的功能封装起来的技术。这样便于减少系统的…

昇思25天学习打卡营第4天|应用实践

昇思25天学习打卡营第4天 文章目录 昇思25天学习打卡营第4天基于 MindSpore 实现 BERT 对话情绪识别模型简介环境配置数据集数据加载和数据预处理input_idsattention_mask 模型构建模型验证模型推理自定义推理数据集 打卡记录 基于 MindSpore 实现 BERT 对话情绪识别 模型简介…

奥比中光astra_pro相机使用记录

一、信息获取 1、官网 用于了解产品信息 http://www.orbbec.com.cn/sys/37.html 2、开发者社区 咨询问题下载开发部https://developer.orbbec.com.cn/ 二 、windowvs19 1、相机型号 orbbec_astro_pro 根据对应的型号找到需要的包工具 踩坑1&#xff0c;因为这个相机型号…

第20章 Mac+VSCode配置C++环境

1. 下载VSCode VSCode下载地址在mac终端里输入xcode- select --install命令&#xff0c;根据提示安装xcode工具。 2. 安装插件&#xff08;4个&#xff09; 打开VScode&#xff0c;点击应用右侧菜单栏 C/C&#xff08;必装&#xff09; Code Runner&#xff08;必装&#xf…

UCOS-III 任务调度与就绪列表管理

01. 就绪优先级位图 在实时操作系统中&#xff0c;任务调度的效率至关重要。UCOS-III通过就绪优先级位图来快速查找最高优先级的就绪任务&#xff0c;从而实现高效调度。就绪优先级位图是一个按位表示的结构&#xff0c;每个位代表一个优先级&#xff0c;当某个优先级上有任务就…

高效管理 TensorFlow 2 GPU 显存的实用指南

前言 在使用 TensorFlow 2 进行训练或预测时&#xff0c;合理管理 GPU 显存至关重要。未能有效管理和释放 GPU 显存可能导致显存泄漏&#xff0c;进而影响后续的计算任务。在这篇文章中&#xff0c;我们将探讨几种方法来有效释放 GPU 显存&#xff0c;包括常规方法和强制终止任…

【FFmpeg】avcodec_open2函数

目录 1. avcodec_open21.1 编解码器的预初始化&#xff08;ff_encode_preinit & ff_decode_preinit&#xff09;1.2 编解码器的初始化&#xff08;init&#xff09;1.3 释放编解码器&#xff08;ff_codec_close&#xff09; FFmpeg相关记录&#xff1a; 示例工程&#xff…

Windows编程之多线程事件对象(Event Object)用法详解

目录 一、前言 二、基础用法 三、API详解 1.创建事件对象 2控制事件状态 3.等待事件对象&#xff1a; 四、实战案例 1.案例描述 2.代码设计 3.总设计代码 4.运行结果 一、前言 事件对象&#xff08;Event Object&#xff09;是我们在大型项目中&#xff0c;进行多线…

竞赛选题 医学大数据分析 - 心血管疾病分析

文章目录 1 前言1 课题背景2 数据处理3 数据可视化4 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的心血管疾病分析 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9…

AI绘画Stable Diffusion 解锁精美壁纸创作:利用SD与LLM定制你的专属壁纸,AI副业变现指南!

大家好&#xff0c;我是画画的小强 今天给大家分享一下用AI绘画Stable Diffusion 制作精美手机壁纸&#xff0c;这也可能是当前最快AIGC变现的一种途径。虽然本文的主题为手机壁纸&#xff0c;当调整不同的比例的分辨率宽高比例&#xff0c;就可以直接复用到手机、电脑和平板、…

旋转和镜像的关系

旋转矩阵行列式与 在E(3)三维空间中&#xff0c;旋转矩阵的行列式可以用来判断该旋转是否包含镜像变换。 行列式为正&#xff1a; 表示纯旋转&#xff0c;不包含镜像。 旋转矩阵保持向量的长度和角度不变&#xff0c;只是改变向量的方向。 行列式为负&#xff1a; 表示旋转…

机器学习原理之 -- 支持向量机分类:由来及原理详解

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是统计学习理论的一个重要成果&#xff0c;广泛应用于分类和回归问题。SVM以其高效的分类性能和良好的泛化能力在机器学习领域中占据重要地位。本文将详细介绍支持向量机的由来、基本原理、构建过程及其优缺点。…

LVS负载均衡群集部署之——DR模式的介绍及搭建步骤

一、LVS-DR集群介绍1.1 LVS-DR 工作原理1.2 数据包流向分析1.3 LVS-DR 模式的特点1.4 LVS-DR中的ARP问题1.4.1 问题一1.4.2 问题二二、构建LVS-DR集群2.1 构建LVS-DR集群的步骤&#xff08;理论&#xff09;1.配置负载调度器&#xff08;192.168.80.30&#xff09;&#xff08;…

5分钟教你用AI把老照片动起来,别再去花49块9的冤枉钱了

文章目录 需要的工具 最近&#xff0c;AI视频在各大平台上&#xff0c;又火了。 只是火的形式&#xff0c;变成了将老照片动起来&#xff0c;打情感牌&#xff0c;或者做很多经典电视剧的再整活。 直接把可灵的生成时间&#xff0c;从以前的4分钟&#xff0c;生生的干成了20分钟…

鸿蒙应用笔记

安装就跳过了&#xff0c;一直点点就可以了 配置跳过&#xff0c;就自动下了点东西。 鸿蒙那个下载要12g个内存&#xff0c;大的有点吓人。 里面跟idea没区别 模拟器或者真机运行 真机要鸿蒙4.0&#xff0c;就可以实机调试 直接在手机里面跑&#xff0c;这个牛逼&#xf…

国标GB/T 28181详解:国标GBT28181-2022 SIP服务器发起广播的命令流程

目录 一、定义 二、作用 1、实现信息的集中管理和分发 &#xff08;1&#xff09;信息集中 &#xff08;2&#xff09;信息分发 2、提高信息传输的可靠性和效率 &#xff08;1&#xff09;可靠性 &#xff08;2&#xff09;提高效率 3、支持多种设备和系统的互通 &am…

mongdb学习与使用

1. 基础概念 MongoDB简介&#xff1a; MongoDB是一个基于文档的NoSQL数据库&#xff0c;具有高性能、高可用性和易扩展性。数据存储在类似JSON的BSON格式中。 基本术语&#xff1a; Database&#xff08;数据库&#xff09;&#xff1a; 集合的容器。Collection&#xff08;集合…