MyBatis 核心知识与实践
一、MyBatis 概述
1. 框架简介
MyBatis 是一款支持自定义 SQL、存储过程以及高级映射的持久层框架。它避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的操作,使开发人员能够更专注于 SQL 语句的编写和业务逻辑的处理。
2. 核心组件
- SqlSessionFactoryBuilder:用于创建 SqlSessionFactory 实例。
- SqlSessionFactory:是 MyBatis 的核心对象,负责创建 SqlSession 实例。
- SqlSession:提供了执行 SQL 语句、管理事务等功能。
3. 工作原理
MyBatis 通过读取配置文件和映射文件,将 SQL 语句与 Java 方法进行映射。在运行时,根据方法调用生成相应的 SQL 语句,并执行数据库操作,最后将结果映射为 Java 对象返回。
二、MyBatis 基础操作
1. 环境搭建
- 引入 MyBatis 依赖(以 Maven 项目为例):
<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>x.x.x</version>
</dependency>
- 配置
mybatis-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">
<configuration><environments default="development"><environment id="development"><transactionManager type="JDBC" /><dataSource type="POOLED"><property name="driver" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></dataSource></environment></environments><mappers><mapper resource="mapper/EmpMapper.xml" /><mapper resource="mapper/DeptMapper.xml" /></mappers>
</configuration>
2. 单表操作
- 实体类定义:
public class Emp {private Integer empid;private String empname;private String empjob;private BigDecimal empsalary;private Integer empdid;// 省略getter和setter方法
}
- Mapper 接口定义:
public interface EmpDao {List<Emp> findAll();Emp findById(Integer id);int insert(Emp emp);int update(Emp emp);int delete(Integer id);
}
- Mapper 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">
<mapper namespace="org.example.Dao.EmpDao"><resultMap id="BaseResultMap" type="Emp"><id property="empid" column="emp_id" jdbcType="INTEGER" /><result property="empname" column="emp_name" jdbcType="VARCHAR" /><result property="empjob" column="emp_job" jdbcType="VARCHAR" /><result property="empsalary" column="emp_salary" jdbcType="DECIMAL" /><result property="empdid" column="did" jdbcType="INTEGER" /></resultMap><select id="findAll" resultMap="BaseResultMap">select * from tbl_emp</select><select id="findById" resultMap="BaseResultMap">select * from tbl_emp where emp_id = #{id}</select><insert id="insert" keyProperty="empid" useGeneratedKeys="true">insert into tbl_emp(emp_name, emp_job, emp_salary, did)values (#{empname}, #{empjob}, #{empsalary}, #{empdid})</insert><update id="update">update tbl_empset emp_name = #{empname}, emp_job = #{empjob}, emp_salary = #{empsalary}, did = #{empdid}where emp_id = #{empid}</update><delete id="delete">delete from tbl_emp where emp_id = #{id}</delete>
</mapper>
3. 测试类编写
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.example.Entity.Emp;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class EmpDaoTest {@Testpublic void testFindAll() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);List<Emp> emps = empDao.findAll();for (Emp emp : emps) {System.out.println(emp);}sqlSession.close();}@Testpublic void testFindById() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);Emp emp = empDao.findById(1);System.out.println(emp);sqlSession.close();}@Testpublic void testInsert() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);Emp emp = new Emp();emp.setEmpname("张三");emp.setEmpjob("开发工程师");emp.setEmpsalary(new BigDecimal("8000"));emp.setEmpdid(1);int result = empDao.insert(emp);System.out.println("插入成功,影响行数:" + result);sqlSession.commit();sqlSession.close();}@Testpublic void testUpdate() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);Emp emp = new Emp();emp.setEmpid(1);emp.setEmpname("李四");emp.setEmpjob("高级开发工程师");emp.setEmpsalary(new BigDecimal("10000"));emp.setEmpdid(2);int result = empDao.update(emp);System.out.println("更新成功,影响行数:" + result);sqlSession.commit();sqlSession.close();}@Testpublic void testDelete() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);int result = empDao.delete(1);System.out.println("删除成功,影响行数:" + result);sqlSession.commit();sqlSession.close();}
}
三、MyBatis 高级特性
1. 分页查询
- 引入 PageHelper 依赖:
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>6.0.0</version>
</dependency>
- 在 MyBatis 配置文件中添加插件配置:
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor"><!-- 可配置参数 --><property name="param1" value="value1" /></plugin>
</plugins>
- 代码示例:
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
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.example.Dao.EmpDao;
import org.example.Entity.Emp;
import org.junit.Test;import java.io.IOException;
import java.io.InputStream;
import java.util.List;public class PaginationTest {@Testpublic void testPagination() throws IOException {InputStream resourceAsStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);SqlSession sqlSession = sqlSessionFactory.openSession();EmpDao empDao = sqlSession.getMapper(EmpDao.class);// 开启分页,查询第一页,每页显示3条数据PageHelper.startPage(1, 3);List<Emp> emps = empDao.findAll();// 将查询结果封装到PageInfo中PageInfo<Emp> pageInfo = new PageInfo<>(emps);// 输出相关信息System.out.println("总条数:" + pageInfo.getTotal());System.out.println("总页数:" + pageInfo.getPages());System.out.println("当前页记录:");List<Emp> list = pageInfo.getList();for (Emp emp : list) {System.out.println(emp);}sqlSession.close();}
}
2. 联表查询
- 多对一关系查询(以员工和部门为例):
- 使用
association标签:
<?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="org.example.Dao.EmpDao"><resultMap id="EmpWithDeptResultMap" type="Emp"><id property="empid" column="emp_id" jdbcType="INTEGER" /><result property="empname" column="emp_name" jdbcType="VARCHAR" /><result property="empjob" column="emp_job" jdbcType="VARCHAR" /><result property="empsalary" column="emp_salary" jdbcType="DECIMAL" /><result property="empdid" column="did" jdbcType="INTEGER" /><association property="dept" javaType="Dept"><id property="deptid" column="dept_id" jdbcType="INTEGER" /><result property="deptname" column="dept_name" jdbcType="VARCHAR" /><result property="deptloc" column="dept_loc" jdbcType="VARCHAR" /></association></resultMap><select id="findAllWithDept" resultMap="EmpWithDeptResultMap">select e.*, d.dept_id, d.dept_name, d.dept_locfrom tbl_emp ejoin tbl_dept d on e.did = d.dept_id</select>
</mapper>
- 一对多关系查询(以部门和员工为例):
- 使用
collection标签:
<?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="org.example.Dao.DeptDao"><resultMap id="DeptWithEmpsResultMap" type="Dept"><id property="deptid" column="dept_id" jdbcType="INTEGER" /><result property="deptname" column="dept_name" jdbcType="VARCHAR" /><result property="deptloc" column="dept_loc" jdbcType="VARCHAR" /><collection property="emps" ofType="Emp"><id property="empid" column="emp_id" jdbcType="INTEGER" /><result property="empname" column="emp_name" jdbcType="VARCHAR" /><result property="empjob" column="emp_job" jdbcType="VARCHAR" /><result property="empsalary" column="emp_salary" jdbcType="DECIMAL" /><result property="empdid" column="did" jdbcType="INTEGER" /></collection></resultMap><select id="findAllWithEmps" resultMap="DeptWithEmpsResultMap">select d.*, e.*from tbl_dept dleft join tbl_emp e on d.dept_id = e.did</select>
</mapper>
3. 动态 SQL
<trim>:通过修剪 SQL 语句的开头和结尾来动态生成 SQL 片段。它可以用于去除不必要的 SQL 关键字或条件语句,并提供了一些属性来定义修剪规则。
<where>:用于在生成的 SQL 语句中添加 WHERE 子句。它可以自动处理条件语句的前缀,并在有条件语句存在时添加 WHERE 关键字。而且会去除sql的第一个and标签。
<set>:用于在生成的 SQL 语句中添加 SET 子句。它主要用于更新操作,可以根据条件来动态生成需要更新的列。
<foreach>:用于在生成的 SQL 语句中进行循环操作。它可以遍历集合或数组,并根据指定的模板将集合元素或数组元素插入到 SQL 语句中。
<if>:用于在生成的 SQL 语句中添加条件判断。可以根据指定的条件决定是否包含某个 SQL 语句片段。
<choose>:类似于 Java 中的 switch 语句,根据条件选择执行不同的 SQL 语句片段。它可以包含多个 <when> 和一个可选的 <otherwise> 标签。
<when>:用于在 <choose> 标签中定义条件分支。可以根据指定的条件判断是否执行特定的 SQL 语句片段。
<otherwise>:在 <choose> 标签中可选的标签,用于定义当没有任何 <when> 条件匹配时执行的 SQL 语句片段。
if标签示例(根据条件查询员工):
<?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="org.example.Dao.EmpDao"><select id="selectByCondition" resultMap="BaseResultMap">select * from tbl_emp<where><if test="name!= null and name!= ''">and emp_name like concat('%', #{name}, '%')</if><if test="job!= null and job!= ''">and emp_job = #{job}</if><if test="salary!= null">and emp_salary = #{salary}</if></where></select>
</mapper>
choose、when、otherwise标签示例(根据条件查询员工):
<?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="org.example.Dao.EmpDao"><select id="selectByCondition2" resultMap="BaseResultMap">select * from tbl_emp<where><choose><when test="name!= null and name!= ''">and emp_name like concat('%', #{name}, '%')</when><when test="job!= null and job!= ''">and emp_job = #{job}</when><when test="salary!= null">and emp_salary = #{salary}</when><otherwise>and 1 = 1</otherwise></choose></where></select>
</mapper>
foreach标签示例(批量删除员工):
<?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="org.example.Dao.EmpDao"><delete id="batchDelete">delete from tbl_emp where emp_id in<foreach collection="ids" item="id" open="(" close=")" separator=",">#{id}</foreach></delete>
</mapper>
相关文章:
MyBatis 核心知识与实践
一、MyBatis 概述 1. 框架简介 MyBatis 是一款支持自定义 SQL、存储过程以及高级映射的持久层框架。它避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的操作,使开发人员能够更专注于 SQL 语句的编写和业务逻辑的处理。 2. 核心组件 SqlSessionFactoryB…...
机器学习期末速成
文章目录 一、机器学习分类二、逻辑回归三、决策树四、集成学习算法五、支持向量机六、聚类七、特征工程和指标 文章参考自B站机器学习期末速成课 本文仅作者个人复习使用 一、机器学习分类 聚类和分类的区别: 分类:一开始就知道有哪些类别 聚类&#…...
Linux中的线程
目录 线程的概念 进程与线程的关系 线程创建 线程终止 线程等待 线程分离 原生线程库 线程局部存储 自己实现线程封装 线程的优缺点 多线程共享与独占资源 线程互斥 互斥锁 自己实现锁的封装 加锁实现互斥的原理 死锁 线程同步 线程的概念 回顾进程相关概念 …...
AI大模型学习笔记|多目标算法梳理、举例
多目标算法学习内容推荐: 1.通俗易懂讲算法-多目标优化-NSGA-II(附代码讲解)_哔哩哔哩_bilibili 2.多目标优化 (python pyomo pareto 最优)_哔哩哔哩_bilibili 学习笔记: 通过网盘分享的文件:多目标算法学习笔记 链接: https://pan.baidu.com…...
蓝桥杯刷题——day3
蓝桥杯刷题——day3 题目一题干题目解析代码 题目二题干题目解析代码 题目一 题干 每张票据有唯一的 ID 号,全年所有票据的 ID 号是连续的,但 ID 的开始数码是随机选定的。因为工作人员疏忽,在录入 ID 号的时候发生了一处错误,造…...
企业级日志分析系统ELK之ELK概述
ELK 概述 ELK 介绍 什么是 ELK 早期IT架构中的系统和应用的日志分散在不同的主机和文件,如果应用出现问题,开发和运维人员想排 查原因,就要先找到相应的主机上的日志文件再进行查找和分析,所以非常不方便,而且还涉及…...
【开源项目】经典开源项目数字孪生体育馆—开源工程及源码
飞渡科技数字孪生体育馆管理平台,融合物联网IOT、BIM数据模型、三维GIS等技术,实现体育馆的全方位监控和实时全局掌握,同时,通过集成设备设施管理、人员管理等子系统,减少信息孤岛,让场馆“可视、可控、可管…...
C++多线程实战:掌握图像处理高级技巧
文章结尾有最新热度的文章,感兴趣的可以去看看。 本文是经过严格查阅相关权威文献和资料,形成的专业的可靠的内容。全文数据都有据可依,可回溯。特别申明:数据和资料已获得授权。本文内容,不涉及任何偏颇观点,用中立态度客观事实描述事情本身 导读 在当今的计算世界中,…...
解决MAC装win系统投屏失败问题(AMD显卡)
一、问题描述 电脑接上HDMI线后,电脑上能显示有外部显示器接入,但是外接显示器无投屏画面 二、已测试的方法 1 更改电脑分辨,结果无效 2 删除BootCamp,结果无效 3更新电脑系统,结果无效 4 在设备管理器中&#…...
网易游戏分享游戏场景中MongoDB运行和分析实践
在游戏行业中,数据库的稳定和性能直接影响了游戏质量和用户满意度。在竞争激烈的游戏市场中,一个优秀的数据库产品无疑能为游戏的开发和后期的运营奠定良好的基础。伴随着MongoDB在不同类型游戏场景中的应用越来越广泛,许多知名的游戏公司都在…...
Android14 AOSP 允许system分区和vendor分区应用进行AIDL通信
在Android14上,出于种种原因,system分区的应用无法和vendor分区的应用直接通过AIDL的方法进行通信,但是项目的某个功能又需要如此。 好在Binder底层其实是支持的,只是在上层进行了屏蔽。 修改 frameworks/native/libs/binder/Bp…...
R学习——因子
目录 1 定义因子(factor函数) 2因子的作用 一个数据集中的 只需要考虑可以用哪个数据来进行分类就可以了,可以用来分类就可以作为因子。 Cy1这个因子对应的水平level是4 6 8: 1 定义因子(factor函数) 要…...
pytest入门三:setup、teardown
https://zhuanlan.zhihu.com/p/623447031 function对应类外的函数,每个函数调用一次 import pytest def setup_module():print(开始 module)def teardown_module():print(结束 module)def setup_function():print(开始 function)def teardown_function():print(结…...
前端面试准备问题2
1.防抖和节流分别是什么,应用场景 防抖:在事件被触发后,只有在指定的延迟时间内没有再次触发,才执行事件处理函数。 在我的理解中,简单的说就是在一个指定的时间内,仅触发一次,如果有多次重复触…...
web前端sse封装
这是一个基于microsoft/fetch-event-source包封装的sse函数,包含开始、停止功能; 可传更多参数、使用非常简单。 使用前: 安装 microsoft/fetch-event-source 代码: // sse import { fetchEventSource } from microsoft/fetch-event-source import { …...
智能家居WTR096-16S录放音芯片方案,实现语音播报提示及录音留言功能
前言: 在当今社会的高速运转之下,夜幕低垂之时,许多辛勤工作的父母尚未归家。对于肩负家庭责任的他们而言,确保孩童按时用餐与居家安全成为心头大事。此时,家居留言录音提示功能应运而生,恰似家中的一位无形…...
【创建模式-蓝本模式(Prototype Pattern)】
目录 Overview应用场景代码演示JDK Prototype pattern 更优实践泛型克隆接口 https://doc.hutool.cn/pages/Cloneable/#%E6%B3%9B%E5%9E%8B%E5%85%8B%E9%9A%86%E7%B1%BB The prototype pattern is a creational design pattern in software development. It is used when the t…...
Spring Boot应用开发深度解析与实战案例
Spring Boot应用开发深度解析与实战案例 在当今快速发展的软件开发领域,Spring Boot凭借其“约定优于配置”的理念,极大地简化了Java应用的开发、配置和部署过程,成为了微服务架构下不可或缺的技术选型。本文将深入探讨Spring Boot的核心特性、最佳实践,并通过一个具体的…...
优化Go语言中的网络连接:设置代理超时参数
网络连接优化的重要性 在分布式系统和微服务架构中,网络请求的效率直接影响到整个系统的响应速度。合理的超时设置可以防止系统在等待网络响应时陷入无限期的阻塞,从而提高系统的吞吐量和用户体验。特别是在使用代理服务器时,由于增加了网络…...
《神经网络与深度学习》(邱锡鹏) 内容概要【不含数学推导】
第1章 绪论 基本概念:介绍了人工智能的发展历程及不同阶段的特点,如符号主义、连接主义、行为主义等。还阐述了深度学习在人工智能领域的重要地位和发展现状,以及其在图像、语音、自然语言处理等多个领域的成功应用。术语解释 人工智能&…...
通过Wrangler CLI在worker中创建数据库和表
官方使用文档:Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后,会在本地和远程创建数据库: npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库: 现在,您的Cloudfla…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
SQL Server 触发器调用存储过程实现发送 HTTP 请求
文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...
