学习资源:
b站:遇见狂神说
链接:https://www.bilibili.com/video/BV1NE411Q7Nx/?spm_id_from=333.999.0.0
使用环境:
- jdk1.8
- mysql5.7
- maven3.8
1、第一个Mybatis程序
1.1、搭建数据库
CREATE DATABASE `mybatis`
CREATE TABLE `user` (
`id` INT(20) NOT NULL PRIMARY KEY,
`name` VARCHAR(30) DEFAULT NULL,
`pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `user` VALUES
(1,'jack','123'),
(2,'tom','123'),
(3,'smith','123')
1.2、使用idea创建一个maven项目
导入依赖:
<!--数据库驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.7</version>
</dependency>
<!--junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<!--lombok依赖-->
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>compile</scope>
</dependency>
1.3、编写mybatis核心配置文件
<?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.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
1.4、创建工具类,获取sqlSessionFactory对象
package com.yang.utils;
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 = null;
static {
String resource = "mybatis-config.xml";
try {
// 获取sqlSessionFactory对象
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 从sqlSessionFactory对象获取sqlSession实例
* sqlSession:执行sql语句的对象
*/
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
}
1.5、编写测试代码
实体类:
package com.yang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
}
接口:
package com.yang.dao;
import com.yang.pojo.User;
import java.util.List;
public interface UserMapper {
List<User> getUserList();
}
接口对应的mapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:对应的dao接口-->
<mapper namespace="com.yang.dao.UserMapper">
<!--
id:对应dao接口的方法名
resultType:返回的类型
-->
<select id="getUserList" resultType="com.yang.pojo.User">
select * from user
</select>
</mapper>
在mybatis核心配置文件中(configuration标签内)注册mapper:
<mappers>
<mapper resource="com/yang/dao/UserMapper.xml" />
</mappers>
测试:
package com.yang.dao;
import com.yang.pojo.User;
import com.yang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserDaoTest {
@Test
public void test(){
// 1获取sqlSession实例
SqlSession sqlSession = MybatisUtils.getSqlSession();
// 2执行sql
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.getUserList();
for (User user : userList) {
System.out.println(user);
}
}
}
注意:如果mapper.xml定义在resources目录之外,需要在pom.xml下配置
<build>
<resources>
<resource>
<!-- 选择需要导出资源的路径 -->
<directory>src/main/resources</directory>
<includes>
<!-- 写入需要导出文件的类型 -->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<!-- 是否过滤这些文件 -->
<filtering>true</filtering>
</resource>
</resources>
</build>
1.6、总结
步骤:
- maven项目下使用mybatis需要在resources目录下创建一个mybatis的核心配置文件
- 创建数据库对应的实体类
- 编写接口
- 接口对应的mapper
- 配置文件中注册mapper
- 测试
注意点:
- 注意每一个接口对应一个mapper.xml文件,接口和接口中的方法,在mapper.xml文件中对应
- 在mybatis核心配置文件中注册对应的mapper使其生效
- mapper.xml不在resources目录下创建时,需要处理配置文件之外的载失败的问题
2、增删改查
在UserMapper接口下添加方法:
// 根据id查询用户
User getUserById(int id);
// 添加一个用户
int addUser(User user);
// 修改用户信息
int updateUser(User user);
// 根据id删除用户
int deleteUser(int id);
对应的mapper:
<!--根据id查询用户-->
<!--
parameterType:参数类型
-->
<select id="getUserById" resultType="com.yang.pojo.User" parameterType="int">
select * from user where id = #{id}
</select>
<!--增加用户-->
<!--
1 增删改操作返回类型都是int,可以省略不写
2 增删改操作必须提交事务,否者不成功
-->
<insert id="addUser" parameterType="com.yang.pojo.User">
insert into user values(#{id},#{name},#{pwd})
</insert>
<!--修改用户信息-->
<update id="updateUser" parameterType="com.yang.pojo.User">
update user set name=#{name},pwd=#{pwd} where id=#{id}
</update>
<!--删除用户-->
<delete id="deleteUser" parameterType="int">
delete from user where id=#{id}
</delete>
测试:
/**
* 删除用户
*/
@Test
public void test05(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.deleteUser(4);
sqlSession.commit();
sqlSession.close();
}
/**
* 修改用户信息
*/
@Test
public void test04(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.updateUser(new User(3,"smith","123"));
sqlSession.commit();
sqlSession.close();
}
/**
* 增加一个用户
*/
@Test
public void test03(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
userMapper.addUser(new User(4,"milan","123"));
sqlSession.commit();
sqlSession.close();
}
/**
* 查询单个用户
*/
@Test
public void test02(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.getUserById(2);
System.out.println(user);
sqlSession.commit();
sqlSession.close();
}
注意:
- 传递的参数类型是基本数据类型时,可以省略parameterType不写
- 增删改操作返回类型都是int,可以省略resultType不写
- 增删改操作必须提交事务,否者不成功
3、核心配置文件引入外部配置文件
resources目录下创建外部配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&charsetEncoding=UTF-8"
username=root
password=root
核心配置文件中引入外部配置文件:
<?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">
<!--可以添加属性-->
<!--因为外部配置文件中有属性password,则优先使用外部配置文件的配置-->
<property name="password" value="123"/>
</properties>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/yang/dao/UserMapper.xml" />
</mappers>
</configuration>
注意:
- 可以在核心配置文件中引入外部配置文件
- 可以在核心配置文件中增加一些属性
- 如果核心配置文件和外部配置文件中有共同属性字段,优先使用外部配置文件的
4、别名替代全类名
方式1指定别名(指定具体类):
<!--方式1使用别名-->
<typeAliases>
<!--
type:指定全类名
alias:别名
-->
<typeAlias type="com.yang.pojo.User" alias="User" />
</typeAliases>
方式2指定别名(扫描包):
<!--方式2使用别名-->
<typeAliases>
<!--为com.yang.pojo包下的实现类设置别名,默认为以小写字母开头的类名-->
<package name="com.yang.pojo"/>
</typeAliases>
使用方式2指定别名,不适用默认别名情况下,需要单独设置别名时使用注解@Alias(“别名”)的方式:
package com.yang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.ibatis.type.Alias;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Alias("testUser") // 设置别名为testUser
public class User {
private int id;
private String name;
private String pwd;
}
5、映射器
方式1:指定接口对应的mapper配置文件绑定
<mappers>
<mapper resource="com/yang/dao/UserMapper.xml" />
</mappers>
方式2:接口全类名绑定
<mappers>
<mapper class="com.yang.dao.UserMapper" />
</mappers>
方式3:扫描包绑定
<mappers>
<package name="com.yang.dao"/>
</mappers>
注意:使用时需要注意接口和mapper的存放位置
6、生命周期和作用域
6.1、SqlSessionFactoryBuilder
- 一旦创建了 SqlSessionFactory,就不再需要SqlSessionFactoryBuilder实例
- 因此 SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)
6.2、SqlSessionFactory
- SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在
- 使用 SqlSessionFactory 在应用运行期间尽量不要重复创建多次
- 因此 SqlSessionFactory 的最佳作用域是应用作用域
6.3、SqlSession
- 每个线程都应该有它自己的 SqlSession 实例
- SqlSession不能被共享,所以它的最佳的作用域是请求或方法作用域
- 每次收到 HTTP 请求,就可以打开一个 SqlSession,返回一个响应后,就关闭它
7、resultMap结果集映射
实体类属性名为password,数据库列名为pwd,使用resultMap解决:
<!--结果集映射resultMap-->
<resultMap id="userResultMap" type="user">
<!--只需处理属性名和查询结果集的列名不一致的关系映射即可-->
<!--column对应数据库列名,property对应实体类属性名-->
<result column="pwd" property="password" />
</resultMap>
<!--resultMap属性值与resultMap标签的id属性值对应-->
<select id="getUserById" resultMap="userResultMap">
select * from user where id = #{id}
</select>
8、日志
8.1、mybatis核心配置文件中设置标准的日志实现:
在核心配置文件中设置:
<!--日志功能-->
<settings>
<!--标准的日志实现-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
8.2、Log4j日志实现
- 通过Log4j日志可以输出日志到控制台,以及指定文件中
- 可以指定输出日志的格式
- 定义日志信息的级别可以精确控制日志的生成
- 通过配置文件配置,不需要修改程序原有代码
1、导入log4j依赖:
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
2、resources目录下新建log4j.properties配置文件:
### 设置
log4j.rootLogger = debug,stdout,D,E
### 输出信息到控制台
log4j.appender.stdout = org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n
### 输出DEBUG 级别以上的日志到=./log/debug.log
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = ./log/debug.log
log4j.appender.D.Append = true
log4j.appender.D.Threshold = DEBUG
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
### 输出ERROR 级别以上的日志到=./log/error.log
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
log4j.appender.E.File =./log/error.log
log4j.appender.E.Append = true
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n
3、编写测试类:
package com.yang.dao;
import org.apache.log4j.Logger;
import org.junit.Test;
public class Log4jTest {
private static final Logger logger = Logger.getLogger(Log4jTest.class);
@Test
public void testLog4j(){
// 记录debug级别的信息
logger.debug("This is debug message.");
// 记录info级别的信息
logger.info("This is info message.");
// 记录error级别的信息
logger.error("This is error message.");
}
}
4、查看控制台输出以及项目路径下生成目录和文件记录的内容
9、Mybatis实现分页
接口中添加方法:
/**
* 分页查询
*/
List<User> getUserByLimit(Map<String,Integer> map);
mapper中添加分页查询语句:
<!--
分页查询
1 parameterType:接收参数类型
2 resultMap:返回结果集映射
-->
<select id="getUserByLimit" parameterType="map" resultMap="userResultMap">
select * from user limit #{startIndex},#{pageSize}
</select>
测试代码:
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 使用map封装
Map<String, Integer> map = new HashMap<>();
map.put("startIndex",0);
map.put("pageSize",3);
List<User> userList = userMapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
补充:
- parameterType接收类型,对应的取值类型
- 普通类型 int,double …,取值为_int …
- 包装类型Integer,Double …,取值为 integer …
- 当parameterType接受的类型是Map,取值时需要和Map的key对应
9、Mybatis注解开发
Mybatis注解开发的底层逻辑是使用反射加载接口的结构,进而获取接口方法(返回类型,泛型,参数等)
- 使用注解来映射简单语句会使代码显得更加简洁
- 如果是一些很复杂的操作,最好用 XML 来映射语句
- 简单的sql语句可以使用注解的方式实现,遇到一些复杂的sql语句,尽量使用xml语句的映射方式
接口代码:
package com.yang.dao;
import com.yang.pojo.User;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper {
@Select("select * from user")
List<User> queryUsers();
}
核心配置文件中配置:
<!--绑定接口-->
<mappers>
<mapper class="com.yang.dao.UserMapper" />
</mappers>
测试:
package com.yang;
import com.yang.dao.UserMapper;
import com.yang.pojo.User;
import com.yang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class TestUser {
@Test
public void testQueryUsers(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = userMapper.queryUsers();
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
}
使用注解开发简单的CRUD操作:
// 根据id查询用户
@Select("select * from user where id = #{uid}")
User getUserById(@Param("uid") Integer id);
// 添加用户
@Insert("insert into user values (#{id},#{name},#{password})")
int addUser(User user);
// 修改用户信息
@Update("update user set name=#{name},pwd=#{password} where id=#{id}")
int updateUser(User user);
// 删除用户
@Delete("delete from user where id=#{uid}")
int deleteUser(@Param("uid") Integer id);
@Param注解的基本使用说明
- 传入单个基本数据类型时,可以不指定@Param注解,默认值为参数名
- 传入多个基本参数类型时,需要给每个基本类型的参数使用@Param注解
- 执行sql预编译的参数对应的是@Param注解的值,而不是参数名
- 包装类型不需要指定@Param注解
10、复杂结果集映射
添加数据库测试数据:
CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `teacher` VALUES(1,'李老师')
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO `student` VALUES ('1','小明','1');
INSERT INTO `student` VALUES ('2','小强','1');
INSERT INTO `student` VALUES ('3','小红','1');
INSERT INTO `student` VALUES ('4','小李','1');
INSERT INTO `student` VALUES ('5','小王','1');
teacher对应实体类:
package com.yang.pojo;
import lombok.Data;
@Data
public class Teacher {
private Integer id;
private String name;
}
student对应实体类:
package com.yang.pojo;
import lombok.Data;
@Data
public class Student {
private Integer id;
private String name;
}
10.1、对一关系
这里以一个学生对应一个老师的形式举例
Student实体中添加对象属性:
// 一个学生关联一个老师
private Teacher teacher;
StudentMapper.xml:
<!--使用联表查询的方式-->
<select id="studentList" resultMap="studentMap">
select s.id sid,s.name sname,t.id tid,t.name tname
from student s
join teacher t
on s.tid = t.id
</select>
<!--结果集映射-->
<resultMap id="studentMap" type="student">
<id property="id" column="sid" />
<result property="name" column="sname" />
<!--对象类型的属性映射关系使用association-->
<!--
property:Student实体类对应的属性名
javaType:实体类型,这里使用了别名的方式,可以使用全类名的方式
-->
<association property="teacher" javaType="teacher">
<!--这里映射的是Teacher实体类的对应关系-->
<id property="id" column="tid" />
<result property="name" column="tname" />
</association>
</resultMap>
注意:
- 对象类型属性关系映射使用association和javaType
- property属性对应的是实体类属性
- column属性对应的是查询结果返回的列名
- 因为查询结果时使用了别名的方式,所以属性column取值为别名的方式
10.2、对多关系
这里以一个老师对应多个学生的形式举例
Teacher实体类中添加集合类型属性:
// 一个老师对应多个学生
private List<Student> studentList;
TeacherMapper.xml:
<select id="queryById" resultMap="teacherMap">
SELECT t.id tid,t.name tname,s.id sid,s.name sname
FROM `teacher` t
JOIN `student` s
ON t.id = s.tid
where tid = #{tid}
</select>
<resultMap id="teacherMap" type="teacher">
<id property="id" column="tid" />
<result property="name" column="tname" />
<!--集合类型的属性映射关系使用collection-->
<!--使用ofType指定集合泛型的类型-->
<collection property="studentList" ofType="student">
<id property="id" column="sid" />
<result property="name" column="sname" />
</collection>
</resultMap>
测试:
@Test
public void testTeacher(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
TeacherMapper teacherMapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = teacherMapper.queryById(1);
System.out.println(teacher);
sqlSession.close();
}
注意:
- 集合类型的属性关系映射与对象类型属性关系映射不同
- 集合类型的属性关系映射是使用collection和ofType
- ofType指定的类型为集合的泛型类型
总结
- 当处理简单的普通类型的映射关系时,使用resultType
- 处理复杂类型(对象、集合)的映射关系时,需要使用结果集映射resultMap
- 处理结果集映射的关系时,需要注意属性名和列名的问题
11、动态SQL
- 在数据库层面增加一些逻辑,根据条件动态生成不同的sql语句
数据库准备:
CREATE TABLE `blog` (
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8
核心配置文件:
<!--引入外部配置文件-->
<properties resource="db.properties" />
<settings>
<!--mybatis默认日志打印-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--开启驼峰命名转换-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--扫描包使用别名-->
<typeAliases>
<package name="com.yang.pojo"/>
</typeAliases>
创建新的工具类:
package com.yang.utils;
import java.util.UUID;
public class IdUtils {
/**
* 返回一个随机的string类型的id
*/
public static String getId(){
return UUID.randomUUID().toString().replace("-","");
}
}
实体类:
package com.yang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private Integer views;
}
接口:
package com.yang.dao;
import com.yang.pojo.Blog;
public interface BlogMapper {
int addBlog(Blog blog);
}
接口对应mapper:
<insert id="addBlog">
insert into blog values (#{id},#{title},#{author},#{createTime},#{views})
</insert>
插入数据:
@Test
public void insertTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
blogMapper.addBlog(new Blog(IdUtils.getId(),"Mybatis如此简单","jack",new Date(),8888));
blogMapper.addBlog(new Blog(IdUtils.getId(),"Spring如此简单","tom",new Date(),7777));
blogMapper.addBlog(new Blog(IdUtils.getId(),"SpringMVC如此简单","smith",new Date(),4444));
blogMapper.addBlog(new Blog(IdUtils.getId(),"SpringBoot如此简单","milan",new Date(),5555));
sqlSession.commit();
sqlSession.close();
}
11.1、if
- 使用if动态拼接 SQL 最常见情景是根据条件包含 where 子句的一部分
接口:
List<Blog> queryBlogs(Map<String, Object> map);
mapper:
<select id="queryBlogs" parameterType="map" resultType="blog">
<!--使用if标签动态拼接符合条件的sql语句,这里使用 where 1 = 1 演示,实际开发不会这样使用,因为有风险-->
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 queryBlogTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put("author","tom");
List<Blog> blogList = blogMapper.queryBlogs(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}
通过传入Map,对指定内容进行筛选,使用if标签拼接sql实现不同的查询结果
11.2、where
- where只会在至少一个子元素返回SQL子句的情况下才插入 “WHERE” 子句。而且,若子句的开头为 “AND” 或 “OR”,where元素也会将它们去除,避免了sql语句拼接错误
去除mapper中的 where 1 = 1:
<select id="queryBlogs" parameterType="map" resultType="blog">
<!--使用if标签动态拼接符合条件的sql语句-->
select * from blog
<where>
<if test="title != null">
and title=#{title}
</if>
<if test="author != null">
and author=#{author}
</if>
</where>
</select>
11.3、choose、when、otherwise
- 当我们只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 java中的 switch 语句
mapper:
<select id="queryBlogs" parameterType="map" resultType="blog">
<!--使用choose、when、otherwise标签动态拼接符合条件的sql语句,拼接的结果只有0个或者1个-->
<!--使用形式与java中的 switch 语句类似-->
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
测试:
@Test
public void queryBlogTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
HashMap<String, Object> map = new HashMap<>();
map.put("title","SpringBoot如此简单");
map.put("author","tom");
map.put("views",8888);
List<Blog> blogList = blogMapper.queryBlogs(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}
当第一个条件满足时,下面的sql语句将不在拼接
11.4、set
- set会动态地在行首插入 SET 关键字,并会删掉额外的逗号(这些逗号是在使用条件语句给列赋值时引入的)
接口中添加方法 :
int updateBlog(Map<String,Object> map);
mapper:
<update id="updateBlog">
update blog
<set>
<if test="title != null">
title=#{title},
</if>
<if test="author != null">
author=#{author}
</if>
</set>
where id=#{id}
</update>
测试:
@Test
public void updateBlogTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("title","Mybatis如此简单");
map.put("author","jack");
map.put("id","751e59e0a6934e509ab40f49d1a6a117");
blogMapper.updateBlog(map);
sqlSession.commit();
sqlSession.close();
}
使用set时,当前面的条件满足,后面的条件不满足时,会自动去除多余的逗号,保证sql语句的正确
注意:当没有条件满足时,使用set,会导致sql语句拼接错误
11.5、sql片段
- 把sql语句中的公共部分提取,方便复用
<!--sql标签的id属性与include标签的refid对应-->
<sql id="if_title_author">
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</sql>
<select id="queryBlogs" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if_title_author"></include>
</where>
</select>
include标签相当于将sql标签的内容插入到where标签内,当下次有同样需求时,sql片段可以实现复用,建议使用时,sql片段内不包含where标签
11.6、foreach
- 可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值
接口:
List<Blog> queryBlogsForeach(Map<String,Object> map);
mapper:
<select id="queryBlogsForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="(" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>
- collection是需要遍历的集合
- item是集合中的每一个值
- open表示在开头拼接
- close表示在结尾拼接
- separator每一个值之间的分隔符,比如:where (item1 or item2 …)
测试:
@Test
public void queryBlogsForeachTest(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper blogMapper = sqlSession.getMapper(BlogMapper.class);
Map<String, Object> map = new HashMap<>();
ArrayList<String> ids = new ArrayList<>();
ids.add("751e59e0a6934e509ab40f49d1a6a117");
ids.add("b7e24d13123e445cbdb6ef9230496eff");
ids.add("5e6d4acc336342df9939033eb5c898c5");
// 将list集合放入map集合中
map.put("ids",ids);
List<Blog> blogList = blogMapper.queryBlogsForeach(map);
for (Blog blog : blogList) {
System.out.println(blog);
}
sqlSession.close();
}