概述
Mybatis中文官网:https://mybatis.net.cn/
Mybatis是一个优秀的持久层框架,通过XML将SQL与程序解耦,便于维护;并且可以自定义SQL、存储过程以及高级映射
开发流程
- 引入Mybatis依赖
- 创建核心配置文件
- 创建实体类
- 创建Mapper映射文件
- 初始化SessionFactory(会话工厂) 作用是读取配置文件,加载mapper映射
- 利用SqlSession对象操作数据
基础入门
环境配置
Mybatis使用XML格式配置数据库环境信息,默认名称为mybatis-config.xml
Mybatis环境配置标签为<environment>
environment中包含数据库驱动、URL、用户名、密码
环境配置示例
<!--配置环境,不同的环境不同的id名字-->
<environment id="dev">
<!--采用JDBC方式对数据库事物进行commit/rollback-->
<transcationManager type = "JDBC"></transcationManager>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/school"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
搭建Mybatis环境
① 创建一个空白的Maven项目
② 配置pom.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.spark</groupId>
<artifactId>mybatis-study</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!--配置阿里云镜像-->
<repositories>
<repository>
<id>aliyun</id>
<name>aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</repository>
</repositories>
<!--配置依赖-->
<dependencies>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
</project>
③ 在resource中创建Mybatis核心配置文件mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--配置环境-->
<environments default="dev">
<environment id="dev">
<!--采用JDBC的方式对数据库事务进行commit/rollback-->
<transactionManager type="JDBC"></transactionManager>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
</configuration>
SqlSessionFactory
SqlSessionFactory是Mybatis的核心对象,用于初始化Mybatis创建SqlSession对象,需要保证SqlSessionFactory在应用全局唯一。
SqlSession对象是Mybatis操作数据库的核心对象,使用JDBC方式与数据库进行交互,并提供了数据表CRUD对应方法
引入单元测试依赖JUnit
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
在test目录下新建测试类进行测试
package com.spark.test;
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 org.junit.Test;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
/**
* MybatisTester class
* description: 测试环境是否配置成功
*
* @author Administrator
* @date 2022/12/31
*/
public class MybatisTester {
@Test
public void testConnection() throws IOException {
// 读取resource目录下的mybatis-config.xml文件
Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
// 加载mybatis核心配置文件并创建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
// 创建SqlSession对象
SqlSession sqlSession = null;
try {
sqlSession = sqlSessionFactory.openSession();
// 创建数据库连接,查看是否连接成功
Connection connection = sqlSession.getConnection();
System.out.println(connection);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null){
// 如果是POOLED连接池方式,close是将连接回收到连接池中
// 如果是UNPOOLED直连方式,close是调用Connection.close()方法关闭连接
sqlSession.close();
}
}
}
}
初始化工具类MybatisUtils
编写工具类使得初始化SqlSessionFactory对象全局唯一
在Java目录下创建MybatisUtils类
package com.spark.mybatis.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.Reader;
/**
* MybatisUtils class
* description: 初始化工具类用于创建SqlSessionFactory对象并保证全局唯一
*
* @author Administrator
* @date 2022/12/31
*/
public class MybatisUtils {
// 使用static关键字修饰,使得sqlSessionFactory对象属于类,并保证全局唯一
private static SqlSessionFactory sqlSessionFactory = null;
// 使用static代码块初始化时创建sqlSessionFactory对象
static{
Reader reader = null;
try {
reader = Resources.getResourceAsReader("mybatis-config.xml");
sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
// 在初始化时报错,抛出ExceptionInInitializerError通知调用者
throw new ExceptionInInitializerError(e);
}
}
// 获取SqlSession对象用于操作数据库
public static SqlSession getSqlSession(){
return sqlSessionFactory.openSession();
}
// 关闭SqlSession连接
public static void closeSqlSession(SqlSession sqlSession){
if(sqlSession!=null){
sqlSession.close();
}
}
}
在测试类中编写测试方法
@Test
public void testInitialization(){
SqlSession sqlSession =null;
try {
// 通过工具类获取SqlSession对象
sqlSession = MybatisUtils.getSqlSession();
// 创建连接,测试是否连接成功
Connection connection = sqlSession.getConnection();
System.out.println(connection);
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接
MybatisUtils.closeSqlSession(sqlSession);
}
}
Mybatis数据查询
数据查询实现步骤
- 创建实体类
- 创建Mapper XML
- 编写<select> SQL标签
- 开启驼峰命名映射
- 新增<mapper>
- SqlSession执行语句
创建实体类
package com.spark.mybatis.entity;
/**
* Student class
* description: 实体类
*
* @author Administrator
* @date 2022/12/31
*/
public class Student {
private Integer id; // id
private String name; // 姓名
private String stuno; // 学号
private Integer age; // 年龄
private String sex; // 性别
private Integer cId; // 班级id
public Student() {
}
public Student(Integer id, String name, String stuno, Integer age, String sex, Integer cId) {
this.id = id;
this.name = name;
this.stuno = stuno;
this.age = age;
this.sex = sex;
this.cId = cId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStuno() {
return stuno;
}
public void setStuno(String stuno) {
this.stuno = stuno;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getcId() {
return cId;
}
public void setcId(Integer cId) {
this.cId = cId;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", stuno='" + stuno + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", cId=" + cId +
'}';
}
}
② 在resources目录下新建mapper目录,并创建StudentMapper.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">
<mapper namespace="student">
<select id="selectAll" resultType="com.spark.mybatis.entity.Student">
select * from student;
</select>
</mapper>
③ 在mybatis-config.xml中开启驼峰命名,并添加mapper映射
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!--开启驼峰命名-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--配置环境-->
<environments default="dev">
<environment id="dev">
<!--采用JDBC的方式对数据库事务进行commit/rollback-->
<transactionManager type="JDBC"></transactionManager>
<!--采用连接池方式管理数据库连接-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</dataSource>
</environment>
</environments>
<!--设置mappers映射-->
<mappers>
<!--添加resources目录下的mapper映射-->
<mapper resource="mappers/StudentMapper.xml"></mapper>
</mappers>
</configuration>
使用SqlSession对象执行SQL语句
@Test
public void testSelectAll(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
// 执行SQL
// student.selectAll student表示mapper的namespace命名空间 selectAll表示select标签的id
List<Student> list = sqlSession.selectList("student.selectAll");
for (Student student : list) {
System.out.println(student);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
SQL传参
当执行select语句时,可能会通过传递参数作为查询条件去查询数据
Mybatis如何处理动态传参问题?
在select标签中新增parameterType属性去指定参数类型,之后在sql语句中对查询条件进行赋值
<select id="selectById" parameterType="Integer" resultType="com.spark.mybatis.entity.Student">
select * from student where id = #{value};
</select>
单参数传递
编写select标签
<!--单参数传递-->
<select id="selectById" parameterType="Integer" resultType="com.spark.mybatis.entity.Student">
select * from student where id = #{value};
</select>
编写测试方法
@Test
public void testSelectById(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Student student = sqlSession.selectOne("student.selectById", 1);
System.out.println(student);
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
多参数传递
编写select标签
<!--多参数传递-->
<select id="selectStudents" parameterType="java.util.Map" resultType="com.spark.mybatis.entity.Student">
select * from student where sex = #{sex} and c_id = #{cId};
</select>
编写测试方法
@Test
public void selectStudents(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Map<String,Object> map = new HashMap<>();
map.put("sex","女");
map.put("cId",2);
List<Student> list = sqlSession.selectList("student.selectStudents",map);
for (Student student : list) {
System.out.println(student);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
多表关联查询
获取查询结果
SQL查询操作大多数为多表关联查询。
现在有两张表student和classroom,通过Mybatis获取多表查询结果
编写select查询标签
<!--多表查询-->
<select id="selectStudentsAndClass" resultType="java.util.LinkedHashMap">
select s.*,c.c_name,c.c_number
from student s , classroom c
where s.c_id = c.id;
</select>
编写测试代码
@Test
public void testSelectStudentsAndClass(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
List<Map> list = sqlSession.selectList("student.selectStudentsAndClass");
for (Map map : list) {
System.out.println(map);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
ResultMap结果映射
虽然使用Map可以保存多表查询结果,但是Map太过灵活不便于维护
如何使用对象去保存多表查询的结果?
- ResultMap可以将查询结果映射为复杂类型的Java对象
- ResultMap适用于Java对象保存多表关联结果
- ResultMap支持对象关联查询等高级特性
创建复杂类型Java对象接收多表查询结果
DTO对象为数据传输对象,用于对原生对象进行拓展
package com.spark.mybatis.dto;
import com.spark.mybatis.entity.Student;
/**
* StudentDTO class
* description: student类的数据传输对象
*
* @author Administrator
* @date 2022/12/31
*/
public class StudentDTO {
private Student student = new Student();
private String cName;
private Integer cNumber;
public StudentDTO() {
}
public StudentDTO(Student student, String cName, Integer cNumber) {
this.student = student;
this.cName = cName;
this.cNumber = cNumber;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public String getcName() {
return cName;
}
public void setcName(String cName) {
this.cName = cName;
}
public Integer getcNumber() {
return cNumber;
}
public void setcNumber(Integer cNumber) {
this.cNumber = cNumber;
}
@Override
public String toString() {
return "StudentDTO{" +
"student=" + student +
", cName='" + cName + '\'' +
", cNumber=" + cNumber +
'}';
}
}
编写select查询标签
<!--ResultMap结果映射-->
<resultMap id="BaseResultMap" type="com.spark.mybatis.dto.StudentDTO">
<id column="id" property="student.id"></id>
<result column="name" property="student.name"></result>
<result column="age" property="student.age"></result>
<result column="sex" property="student.sex"></result>
<result column="stuno" property="student.stuno"></result>
<result column="c_id" property="student.cId"></result>
<result column="c_name" property="cName"></result>
<result column="c_number" property="cNumber"></result>
</resultMap>
<select id="selectStudentDTO" resultMap="BaseResultMap">
select s.*,c.c_name,c.c_number
from student s , classroom c
where s.c_id = c.id;
</select>
编写测试方法
@Test
public void testSelectStudentDTO(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
List<StudentDTO> list = sqlSession.selectList("student.selectStudentDTO");
for (StudentDTO studentDTO : list) {
System.out.println(studentDTO);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
数据操作
数据插入
插入数据使用insert标签
编写insert插入标签
<!--数据插入-->
<insert id="insertStudent" parameterType="com.spark.mybatis.entity.Student">
insert into `student` (`name`, `stuno`, `age`, `sex`, `c_id`)
values (#{name},#{stuno},#{age},#{sex},#{cId});
<!--
查询主键自增结果
学生表id字段为自增主键
selectKey标签的作用是查询insert语句执行后主键最后添加的值并赋值给学生类的id
-->
<selectKey resultType="Integer" keyColumn="id" order="AFTER">
select last_insert_id();
</selectKey>
</insert>
测试方法
@Test
public void testInsertStudent(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Student student = new Student();
student.setName("小花");
student.setAge(18);
student.setSex("女");
student.setStuno("2022005");
student.setcId(1);
int num = sqlSession.insert("student.insertStudent", student);
System.out.println(num);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
// 如果插入出现异常,回滚事务
if(sqlSession!=null){
sqlSession.rollback();
}
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
selectKey和useGeneratedKeys的区别
selectKey示例
<!--数据插入-->
<insert id="insertStudent" parameterType="com.spark.mybatis.entity.Student">
insert into `student` (`name`, `stuno`, `age`, `sex`, `c_id`)
values (#{name},#{stuno},#{age},#{sex},#{cId});
<!--
查询主键自增结果
学生表id字段为自增主键
selectKey标签的作用是查询insert语句执行后主键最后添加的值并赋值给学生类的id
-->
<selectKey resultType="Integer" keyColumn="id" order="AFTER">
select last_insert_id();
</selectKey>
</insert>
useGeneratedKeys示例
<!--数据插入-->
<insert id="insertStudent2"
parameterType="com.spark.mybatis.entity.Student"
useGeneratedKeys="true"
keyColumn="id"
keyProperty="id"
>
insert into `student` (`name`, `stuno`, `age`, `sex`, `c_id`)
values (#{name},#{stuno},#{age},#{sex},#{cId});
</insert>
二者区别:
① 显示与隐式
- selectKey标签需要明确编写获取最新主键的SQL语句
- useGeneratedKeys属性会自动根据驱动生成对应的SQL语句
② 应用场景
- selectKey支持所有的关系型数据库
- useGeneratedKeys只支持“自增主键”数据库
更新与删除
更新使用update标签
<!--数据更新-->
<update id="updateStudent" parameterType="com.spark.mybatis.entity.Student">
update student
set
name = #{name},
sex = #{sex},
age = #{age},
c_id = #{cId}
where
stuno = #{stuno};
</update>
编写测试方法
@Test
public void testUpdateStudent(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Student student = sqlSession.selectOne("student.selectById",1);
student.setName("张小飞");
sqlSession.update("student.updateStudent",student);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
// 如果插入出现异常,回滚事务
if(sqlSession!=null){
sqlSession.rollback();
}
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
删除使用delete标签
<!--删除数据-->
<delete id="deleteStudent" parameterType="String">
delete from student where stuno = #{stuno};
</delete>
编写测试方法
@Test
public void testDeleteStudent(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Student student = sqlSession.selectOne("student.selectById",1);
sqlSession.delete("student.deleteStudent",student.getStuno());
// 提交事务
sqlSession.commit();
} catch (Exception e) {
// 如果插入出现异常,回滚事务
if(sqlSession!=null){
sqlSession.rollback();
}
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
预防SQL注入攻击
SQL注入是指攻击者利用SQL漏洞,绕过系统约束,越权获取数据的方式

Mybatis预防SQL注入
两种传值方式:
${} 文本替换,未经任何处理对SQL文本替换
#{} 预编译传值,使用预编译传值可以预防SQL注入
Mybatis工作流程

- Java应用程序首先会根据Mybatis核心配置文件加载全局设置项,其中包含了数据库连接、mapper映射等等
- 初始化阶段通过SqlSessionFactoryBuilder创建SqlSessionFactory对象,SqlSessionFactory对象会调用openSession()方法去获取SqlSession对象,从而可以操作数据库对数据表进行增删改查
- 对于数据表的写操作,SqlSession对象会根据SQL的执行情况进行事务的提交和回滚,最后SQL执行完毕,SqlSession对象会执行close()方法
- 如果mybatis-config.xml文件中数据库连接是POOLED连接池方式,执行close方法,会将连接回收到连接池中如果是UNPOOLED直连方式,执行close方法,会执行Connection.close()方法关闭连接
Mybatis高级特性
日志管理
当使用Mybatis执行Java程序时,例如执行SQL语句,无法得知SQL的执行情况,这时可以通过配置日志在控制台显示执行情况,以便于对程序进行调试维护
日志的门面通常是Slf4j和Apache Commons-Loggings,日志的具体实现有log4j、logback等等

开启日志的步骤
在pom.xml中引入依赖
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.9</version>
</dependency>
在resources目录下新建logback.xml文件对日志进行配置
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<!--向控制台输出日志-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<!--定义日志输出格式-->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!--
定义日志打印的级别(从高到低)
error: 错误 - 系统故障日志
warn: 警告 - 存在风险或使用不当的日志
info: 一般性消息
debug: 程序内部用于调式信息
trace: 程序运行的跟踪信息
-->
<root level="debug">
<appender-ref ref="console"/>
</root>
</configuration>
动态SQL
概述
动态SQL可以根据不同条件生成不同SQL,允许在映射文件中编写灵活的SQL语句,以便于根据参数的不同情况来动态生成SQL语句
动态SQL的作用
- 条件灵活:使用动态SQL可以根据不同的条件生成不同的SQL语句,使得查询、更新或删除数据时能够根据具体情况进行灵活的处理
- 查询优化:动态SQL可以根据运行时的条件动态调整查询语句,从而更好的适应实际情况,提供查询性能
- 动态表名和字段名:当需要根据不同的场景来操作不同的表或字段,可以通过动态SQL来动态构建表名和字段名,实现灵活性和扩展性
- 防止SQL注入:通过使用参数化查询或者绑定变量的方式来构建动态SQL,可以有效防止SQL注入攻击,提升系统的安全性
常用的动态SQL标签
| 标签 | 作用 |
| if | 根据指定的条件判断是否包含某部分SQL代码,使得SQL语句在运行时更具灵活性 |
| where | 生成动态的WHERE子句,只有满足条件时才包含WHERE子句,避免不必要的WHERE关键字 |
| choose | 根据不同的条件选择执行不同的SQL片段,实现类似于switch-case语句的功能 |
| foreach | 对集合进行循环,并在SQL语句中使用循环的结果,可以用于动态构建IN或VALUES子句 |
| set | 生成动态的SET子句,只有满足条件时才包含SET子句,用于动态更新表中的字段 |
| trim | 对SQL语句进行修剪和重组,去掉多余的AND或OR等,以便根据不同的条件动态生成合适的SQL语句 |
where和if标签
使用where标签和if标签编写动态SQL
<!--动态SQL-->
<select id="dynamicSQL" resultType="com.spark.mybatis.entity.Student">
select * from student
<where>
<if test="sex != null">
and sex = #{sex}
</if>
<if test="cId != null">
and c_id = #{cId}
</if>
</where>
</select>
编写测试方法
@Test
public void testDynamicSQL(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Map<String,Object> map = new HashMap<>();
map.put("sex","女");
map.put("cId",2);
List<Student> list = sqlSession.selectList("student.selectStudents",map);
for (Student student : list) {
System.out.println(student);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
注意:使用where标签会动态的去掉第一个条件前的and条件,如果所有的参数没有值则不加where关键字;但是单使用if标签的话,建议 where 关键字后跟1=1,即:
select 列名 from 表名 where 1=1 and 条件 = 条件值;
否则,当参数值不为空时,生成的SQL会报错,即:
select 列名 from 表名 where and 条件 = 条件值;
choose标签
<choose>标签中有两部分,<when>和<otherwise>
when用于定义条件成立时执行的代码块,其中的test属性用于指定该条件分支的判断条件
otherwise用于定义默认的代码块,当所有的when条件都不成立时,将执行<otherwise>中定义的代码块
<select id="getSuppliersAll" resultType="pojo.Supplier">
select supCode,supName,supContact,supPhone,supFax,createdTime from t_supplier
<where>
<choose> <!--相当于Switch-->
<when test="supCode!=null and supCode!=''"> <!--相当于case-->
and supCode like #{supCode}
</when>
<when test="supName!=null and supName!=''"> <!--相当于case-->
and supName like #{supName}
</when>
</choose>
</where>
</select>
set标签
set标签可以根据传入的字段值动态的去更新需要更新的字段,忽略不需要更新的字段
<!--动态修改-->
<update id="UpdateManySupplier">
update t_supplier
<set>
<if test="supCode!=null and supCode!=''">
supCode=#{supCode},
</if>
<if test="supName!=null and supName!=''">
supName=#{supName},
</if>
<if test="supPhone!=null and supPhone!=''">
supPhone=#{supPhone},
</if>
</set>
where id=#{id}
</update>
trim标签
trim标签允许你在模版引擎或XML处理器中对字符串进行修剪操作,包括去除空白字符,去除指定的前缀和后缀,以及根据条件进行修剪。提供了一种方便和灵活的方式来处理和清理字符串数据
| 属性 | 作用 |
| prefix | 指定一个字符串前缀,它将被添加到修剪后的字符串的开头。通常用于添加特定的字符或标记 |
| suffix | 指定一个字符串后缀,它将被添加到修剪后的字符串的结尾。常用于添加特定的字符或标记 |
| prefixOverrides | 指定一个字符串前缀,当修剪后的字符串以该前缀开头时,该前缀将被移除 |
| suffixOverrides | 指定一个字符串后缀,在修剪后的字符串以该后缀结尾时,该后缀将被移除 |
动态查询
<!--动态查询-->
<select id="getSuppliersAll" resultType="pojo.Supplier">
select supCode,supName,supContact,supPhone,supFax,createdTime from t_supplier
<trim prefix="where" prefixOverrides="and|or" suffix=" LIMIT #{index},#{pageSize}">
<if test="supCode!=null and supCode!=''">
and supCode like #{supCode}
</if>
<if test="supName!=null and supName!=''">
and supName like #{supName}
</if>
<if test="supPhone!=null and supPhone!=''">
and supPhone like #{supPhone}
</if>
</trim>
</select>
动态修改
<update id="UpdateManySupplier">
update t_supplier
<trim prefix="set" suffixOverrides="," suffix="where id=#{id}">
<if test="supCode!=null and supCode!=''">
supCode=#{supCode},
</if>
<if test="supName!=null and supName!=''">
supName=#{supName},
</if>
<if test="supPhone!=null and supPhone!=''">
supPhone=#{supPhone},
</if>
</trim>
</update>
二级缓存
一级缓存默认开启,缓存范围 SqlSession会话
二级缓存需要手动开启,缓存范围 Mapper namespace
二级缓存运行规则
- 二级缓存开启后默认所有查询操作均使用缓存
- 写操作commit提交时对该namespace缓存强制清空(保证数据一致性)
- 在select标签中配置useCache = false 可以不用缓存
- 在SQL标签中配置flushCache = true 代表SQL执行完毕后强制清空缓存
开启二级缓存
在mapper文件中开启二级缓存
<!--开启二级缓存-->
<cache eviction="LRU" flushInterval="600000" size="512" readOnly="true"></cache>
eviction:缓存的清除策略,当缓存对象数量达到上限后,自动触发对应算法对缓存对象清除
- LRU 移除最长时间不被使用的对象
- LFU 移除使用次数最少的对象
- FIFO 按对象进入缓存的顺序来移除
- SOFT 移除基于垃圾收集器状态和软引用规则的对象
- WEAK 更积极地移除基于垃圾收集器状态和弱引用规则的对象
flushInterval:代表间隔多长时间自动清空缓存,单位毫秒
size:缓存存储上限,用于报错对象或集合(1个集合算1个对象)的数量上限
readOnly:设置为true时,返回只读缓存,每次从缓存取出的是缓存对象的本身,执行效率较高;
设置为false时,每次取出的是缓存对象的“副本”,每一次取出的对象都是不同的,安全性较高
分页插件
Mybatis提供了PageHelper分页插件
- Maven引入PageHelper与jsqlparser
- mybatis-config.xml增加Plugin配置
- 代码中使用PageHelper.startPage()自动分页
引入依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.0</version>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.3</version>
</dependency>
配置Plugin
<!--开启分页插件-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<!--数据库类型-->
<property name="helperDialect" value="mysql"/>
<!--分页合理化-->
<property name="reasonable" value="true"/>
</plugin>
</plugins>
测试
@Test
public void testSelectPage(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
// 查询第几页,每页几条数据
PageHelper.startPage(1,2);
Page<Student> page = (Page) sqlSession.selectList("student.selectAll");
// 获取当前页记录
List<Student> list = page.getResult();
// 获取总页数
System.out.println(page.getPages());
// 获取总记录数
System.out.println(page.getTotal());
for (Student student : list) {
System.out.println(student);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
整合C3P0连接池
引入依赖
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.4</version>
</dependency>
创建数据源工厂
package com.spark.mybatis.datasource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory;
/**
* C3P0DataSourceFactory class
* description: C3P0连接池工厂
*
* @author Administrator
* @date 2023/1/2
*/
/**
* C3P0与mybatis兼容使用的数据源工厂类
*/
public class C3P0DataSourceFactory extends UnpooledDataSourceFactory {
public C3P0DataSourceFactory(){
this.dataSource = new ComboPooledDataSource();
}
}
更改mybatis-config.xml文件中数据源配置
<dataSource type="com.spark.mybatis.datasource.C3P0DataSourceFactory">
<property name="driverClass" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8"/>
<property name="user" value="root"/>
<property name="password" value="root"/>
<property name="initialPoolSize" value="5"/>
<property name="maxPoolSize" value="20"/>
<property name="minPoolSize" value="5"/>
</dataSource>
批处理
向标签中插入批处理
<!--批量添加-->
<insert id="batchInsert"
parameterType="java.util.List"
>
insert into `student` (`name`, `stuno`, `age`, `sex`, `c_id`)
values
<foreach collection="list" index="index" item="item" separator=",">
(#{item.name},#{item.stuno},#{item.age},#{item.sex},#{item.cId})
</foreach>
</insert>
<!--批量删除-->
<delete id="batchDelete" parameterType="java.util.List">
delete from `student` where id in
<foreach collection="list" index="index" item="item" open="(" close=")" separator=",">
#{item}
</foreach>
</delete>
编写测试方法
@Test
public void testBatchInsert(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
Student student;
List<Student> list = new ArrayList<Student>();
for(int i=0;i<100;i++){
student = new Student();
student.setName("测试用户"+(i+1));
student.setAge(18);
student.setSex("男");
student.setStuno("202300"+(i+1));
student.setcId(1);
list.add(student);
}
sqlSession.insert("student.batchInsert", list);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
// 如果插入出现异常,回滚事务
if(sqlSession!=null){
sqlSession.rollback();
}
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
@Test
public void testBatchDelete(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
List<Integer> list = new ArrayList<>();
for(int i=1;i<=100;i++){
list.add(i);
}
sqlSession.delete("student.batchDelete",list);
// 提交事务
sqlSession.commit();
} catch (Exception e) {
// 如果插入出现异常,回滚事务
if(sqlSession!=null){
sqlSession.rollback();
}
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}
注解开发
Mybatis通过注解开发可以简化配置过程
创建Dao接口
package com.spark.mybatis.dao;
import com.spark.mybatis.entity.Student;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface StudentDAO {
@Select("select * from Student where c_id = #{cId}")
public List<Student> getStudentsByClassNo(@Param("cId") Integer cId);
}
在配置类中加载Dao
<mappers>
<!--
加载DAO类两种写法
-->
<!--<mapper class="com.spark.mybatis.dao.StudentDAO"></mapper>-->
<package name="com.spark.mybatis.dao"/>
</mappers>
测试
@Test
public void testDao(){
SqlSession sqlSession =null;
try {
sqlSession = MybatisUtils.getSqlSession();
StudentDAO dao = sqlSession.getMapper(StudentDAO.class);
List<Student> list = dao.getStudentsByClassNo(2);
System.out.println(list);
} catch (Exception e) {
e.printStackTrace();
} finally {
MybatisUtils.closeSqlSession(sqlSession);
}
}

1242

被折叠的 条评论
为什么被折叠?



