MyBatis入门教程:从零开始学习持久层框架

发布时间:2026/7/31 13:55:08
MyBatis入门教程:从零开始学习持久层框架 1. 项目背景与核心价值旋转机械作为工业领域的核心设备如汽轮机、压缩机、发电机等其故障诊断一直是设备运维的关键课题。传统振动信号分析方法常面临频段选择依赖专家经验、诊断效率低下的痛点。我们团队提出的这种基于分类的频段选择新方法通过算法自动识别对故障敏感的频段显著提升了诊断准确率。实测数据表明在轴承故障诊断场景中与传统固定频段方法相比新方法将诊断准确率从78%提升至93%同时减少了70%以上的无效频段分析计算量。2. 方法原理与技术路线2.1 频段选择的数学建模设原始振动信号为x(t)经过傅里叶变换得到频谱X(f)。定义频段选择函数function [selected_bands] band_selection(X, f, N_bands) % X: 频谱数据 % f: 频率向量 % N_bands: 目标频段数 energy abs(X).^2; % 计算各频率点能量 [~, idx] sort(energy, descend); % 按能量排序 % 动态划分能量集中区域 selected_bands adaptive_partition(f(idx), N_bands); end该方法的核心创新在于能量梯度分析通过计算ΔE/Δf识别能量突变点类间可分性评估使用Fisher准则量化各频段对故障类别的区分度自适应聚类基于谱聚类算法自动合并相似频段2.2 特征提取与分类架构graph TD A[原始振动信号] -- B[频段选择模块] B -- C[多尺度熵特征] B -- D[小波包能量] C D -- E[随机森林分类] E -- F[故障类型输出]注实际实现时需用Matlab代码替代该流程图3. Matlab实现详解1. 概述1.1 什么是MyBatisMyBatis 是一款优秀的持久层框架它支持自定义 SQL、存储过程以及高级映射MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJOPlain Old Java Objects普通老式 Java 对象为数据库中的记录1.2 持久化数据持久化持久化就是将程序的数据在持久状态和瞬时状态转化的过程内存断电即失数据库jdbcio文件持久化为什么需要持久化有一些对象不能让他丢掉内存太贵1.3 持久层Dao层、Service层、Controller层完成持久化工作的代码块层界限十分明显1.4 为什么需要MyBatis帮助程序员将数据存入到数据库中方便传统的JDBC代码太复杂了简化框架自动化不用MyBatis也可以更容易上手优点简单易学灵活sql和代码的分离提高了可维护性提供映射标签支持对象与数据库的orm字段关系映射提供对象关系映射标签支持对象关系组建维护提供xml标签支持编写动态sql2. 第一个MyBatis程序思路搭建环境 -- 导入MyBatis -- 编写代码 -- 测试2.1 搭建环境搭建数据库CREATE DATABASE mybatis; USE mybatis; CREATE TABLE user( id INT(20) NOT NULL PRIMARY KEY, name VARCHAR(30) DEFAULT NULL, pwd VARCHAR(30) DEFAULT NULL )ENGINEINNODB DEFAULT CHARSETutf8; INSERT INTO user(id,name,pwd) VALUES (1,狂神,123456), (2,张三,123456), (3,李四,123456)新建项目新建一个普通的maven项目删除src目录导入maven依赖!--导入依赖-- dependencies !--mysql驱动-- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.47/version /dependency !--mybatis-- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.2/version /dependency !--junit-- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.12/version /dependency /dependencies2.2 创建一个模块编写mybatis的核心配置文件?xml version1.0 encodingUTF-8 ? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd !--configuration核心配置文件-- configuration environments defaultdevelopment environment iddevelopment transactionManager typeJDBC/ dataSource typePOOLED property namedriver valuecom.mysql.jdbc.Driver/ property nameurl valuejdbc:mysql://localhost:3306/mybatis?useSSLtrueamp;useUnicodetrueamp;characterEncodingUTF-8/ property nameusername valueroot/ property namepassword value123456/ /dataSource /environment /environments mappers mapper resourcecom/kuang/dao/UserMapper.xml/ /mappers /configuration编写mybatis工具类//sqlSessionFactory -- sqlSession public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { //使用Mybatis第一步获取sqlSessionFactory对象 String resource org/mybatis/example/mybatis-config.xml; 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(); } }2.3 编写代码实体类//实体类 public class User { private int id; private String name; private String pwd; public User() { } public User(int id, String name, String pwd) { this.id id; this.name name; this.pwd pwd; } public int getId() { return id; } public void setId(int id) { this.id id; } public String getName() { return name; } public void setName(String name) { this.name name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd pwd; } Override public String toString() { return User{ id id , name name \ , pwd pwd \ }; } }Dao接口public interface UserDao { ListUser getUserList(); }接口实现类由原来的UserDaoImpl转变为一个Mapper配置文件?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd !--namespace绑定一个对应的Dao/Mapper接口-- mapper namespacecom.kuang.dao.UserDao !--select查询语句-- select idgetUserList resultTypecom.kuang.pojo.User select * from mybatis.user /select /mapper2.4 测试注意点org.apache.ibatis.binding.BindingException: Type interface com.kuang.dao.UserDao is not known to the MapperRegistry.MapperRegistry是什么核心配置文件中注册mappersjunit测试public class UserDaoTest { Test public void test(){ //第一步获得SqlSession对象 SqlSession sqlSession MybatisUtils.getSqlSession(); //方式一getMapper UserDao userDao sqlSession.getMapper(UserDao.class); ListUser userList userDao.getUserList(); for (User user : userList) { System.out.println(user); } //关闭SqlSession sqlSession.close(); } }可能会遇到的问题配置文件没有注册绑定接口错误方法名不对返回类型不对Maven导出资源问题3. CRUD1. namespacenamespace中的包名要和Dao/mapper接口的包名一致2. select选择查询语句id就是对应的namespace中的方法名resultTypeSql语句执行的返回值parameterType参数类型编写接口//根据ID查询用户 User getUserById(int id);编写对应的mapper中的sql语句select idgetUserById parameterTypeint resultTypecom.kuang.pojo.User select * from mybatis.user where id #{id} /select测试Test public void getUserById() { SqlSession sqlSession MybatisUtils.getSqlSession(); UserMapper mapper sqlSession.getMapper(UserMapper.class); User user mapper.getUserById(1); System.out.println(user); sqlSession.close(); }3. Insert!--对象中的属性可以直接取出来-- insert idaddUser parameterTypecom.kuang.pojo.User insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd}); /insert4. Updateupdate idupdateUser parameterTypecom.kuang.pojo.User update mybatis.user set name#{name},pwd#{pwd} where id #{id} ; /update5. Deletedelete iddeleteUser parameterTypeint delete from mybatis.user where id #{id}; /delete注意点增删改需要提交事务6. 分析错误标签不要匹配错resource绑定mapper需要使用路径程序配置文件必须符合规范NullPointerException没有注册到资源输出的xml文件中存在中文乱码问题maven资源没有导出问题7. 万能Map假设我们的实体类或者数据库中的表字段或者参数过多我们应当考虑使用Map//万能的Map int addUser2(MapString,Object map);!--对象中的属性可以直接取出来 传递map的key-- insert idaddUser2 parameterTypemap insert into mybatis.user (id, pwd) values (#{userid},#{passWord}); /insertTest public void addUser2(){ SqlSession sqlSession MybatisUtils.getSqlSession(); UserMapper mapper sqlSession.getMapper(UserMapper.class); MapString, Object map new HashMapString, Object(); map.put(userid,5); map.put(passWord,2222333); mapper.addUser2(map); sqlSession.commit(); sqlSession.close(); }Map传递参数直接在sql中取出key即可【parameterTypemap】对象传递参数直接在sql中取对象的属性即可【parameterTypeObject】只有一个基本类型参数的情况下可以直接在sql中取到多个参数用Map或者注解8. 思考题模糊查询怎么写Java代码执行的时候传递通配符% %ListUser userList mapper.getUserLike(%李%);在sql拼接中使用通配符select * from mybatis.user where name like %#{value}%4. 配置解析1. 核心配置文件mybatis-config.xmlMyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。configuration配置 properties属性 settings设置 typeAliases类型别名 typeHandlers类型处理器 objectFactory对象工厂 plugins插件 environments环境配置 environment环境变量 transactionManager事务管理器 dataSource数据源 databaseIdProvider数据库厂商标识 mappers映射器2. 环境配置environmentsMyBatis 可以配置成适应多种环境不过要记住尽管可以配置多个环境但每个 SqlSessionFactory 实例只能选择一种环境。学会使用配置多套运行环境MyBatis默认的事务管理器就是JDBC连接池POOLED3. 属性properties我们可以通过properties属性来实现引用配置文件这些属性可以在外部进行配置并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性也可以在 properties 元素的子元素中设置。【db.properties】编写一个配置文件db.propertiesdrivercom.mysql.jdbc.Driver urljdbc:mysql://localhost:3306/mybatis?useSSLtrueuseUnicodetruecharacterEncodingUTF-8 usernameroot password123456在核心配置文件中引入!--引入外部配置文件-- properties resourcedb.properties property nameusername valueroot/ property namepwd value11111/ /properties可以直接引入外部文件可以在其中增加一些属性配置如果两个文件有同一个字段优先使用外部配置文件的4. 类型别名typeAliases类型别名可为 Java 类型设置一个缩写名字。它仅用于 XML 配置意在降低冗余的全限定类名书写。!--可以给实体类起别名-- typeAliases typeAlias typecom.kuang.pojo.User aliasUser/ /typeAliases也可以指定一个包名MyBatis 会在包名下面搜索需要的 Java Bean比如扫描实体类的包它的默认别名就为这个类的类名首字母小写!--可以给实体类起别名-- typeAliases package namecom.kuang.pojo/ /typeAliases在实体类比较少的时候使用第一种方式。如果实体类十分多建议使用第二种。第一种可以DIY别名第二种则不行如果非要改需要在实体上增加注解Alias(user) public class User {}5. 设置settings这是 MyBatis 中极为重要的调整设置它们会改变 MyBatis 的运行时行为。6. 其他配置typeHandlers类型处理器objectFactory对象工厂plugins插件mybatis-generator-coremybatis-plus通用mapper7. 映射器mappersMapperRegistry注册绑定我们的Mapper文件方式一【推荐使用】!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-- mappers mapper resourcecom/kuang/dao/UserMapper.xml/ /mappers方式二使用class文件绑定注册!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-- mappers mapper classcom.kuang.dao.UserMapper/ /mappers注意点接口和他的Mapper配置文件必须同名接口和他的Mapper配置文件必须在同一个包下方式三使用扫描包进行注入绑定!--每一个Mapper.xml都需要在MyBatis核心配置文件中注册-- mappers package namecom.kuang.dao/ /mappers8. 生命周期和作用域生命周期和作用域是至关重要的因为错误的使用会导致非常严重的并发问题。SqlSessionFactoryBuilder一旦创建了 SqlSessionFactory就不再需要它了局部变量SqlSessionFactory说白了就是可以想象为数据库连接池SqlSessionFactory 一旦被创建就应该在应用的运行期间一直存在没有任何理由丢弃它或重新创建另一个实例因此 SqlSessionFactory 的最佳作用域是应用作用域最简单的就是使用单例模式或者静态单例模式SqlSession连接到连接池的一个请求SqlSession 的实例不是线程安全的因此是不能被共享的所以它的最佳的作用域是请求或方法作用域用完之后需要赶紧关闭否则资源被占用这里的每一个Mapper就代表一个具体的业务5. 解决属性名和字段名不一致的问题1. 问题数据库中的字段新建一个项目拷贝之前的测试实体类字段不一致的情况public class User { private int id; private String name; private String password; }测试出现问题// select * from mybatis.user where id #{id} //类型处理器 // select id,name,pwd from mybatis.user where id #{id}解决方法起别名select idgetUserById resultTypecom.kuang.pojo.User select id,name,pwd as password from mybatis.user where id #{id} /select2. resultMap结果集映射id name pwd id name password!--结果集映射-- resultMap idUserMap typeUser !--column数据库中的字段property实体类中的属性-- result columnid propertyid/ result columnname propertyname/ result columnpwd propertypassword/ /resultMap select idgetUserById resultMapUserMap select * from mybatis.user where id #{id} /selectresultMap元素是 MyBatis 中最重要最强大的元素ResultMap 的设计思想是对简单的语句做到零配置对于复杂一点的语句只需要描述语句之间的关系就行了ResultMap的优秀之处在于你完全可以不用显式地配置它们如果这个世界总是这么简单就好了6. 日志6.1 日志工厂如果一个数据库操作出现了异常我们需要排错。日志就是最好的助手曾经sout、debug现在日志工厂SLF4JLOG4J【掌握】LOG4J2JDK_LOGGINGCOMMONS_LOGGINGSTDOUT_LOGGING【掌握】NO_LOGGING在MyBatis中具体使用哪一个日志实现在设置中设定STDOUT_LOGGING标准日志输出在mybatis核心配置文件中配置我们的日志settings setting namelogImpl valueSTDOUT_LOGGING/ /settings6.2 Log4j什么是Log4jLog4j是Apache的一个开源项目通过使用Log4j我们可以控制日志信息输送的目的地是控制台、文件、GUI组件我们也可以控制每一条日志的输出格式通过定义每一条日志信息的级别我们能够更加细致地控制日志的生成过程通过一个配置文件来灵活地进行配置而不需要修改应用的代码先导入log4j的包!-- https://mvnrepository.com/artifact/log4j/log4j -- dependency groupIdlog4j/groupId artifactIdlog4j/artifactId version1.2.17/version /dependencylog4j.properties#将等级为DEBUG的日志信息输出到console和file这两个目的地console和file的定义在下面的代码 log4j.rootLoggerDEBUG,console,file #控制台输出的相关设置 log4j.appender.console org.apache.log4j.ConsoleAppender log4j.appender.console.Target System.out log4j.appender.console.Threshold DEBUG log4j.appender.console.layout org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern [%c]-%m%n #文件输出的相关设置 log4j.appender.file org.apache.log4j.RollingFileAppender log4j.appender.file.File ./log/kuang.log log4j.appender.file.MaxFileSize 10mb log4j.appender.file.Threshold DEBUG log4j.appender.file.layout org.apache.log4j.PatternLayout log4j.appender.file.layout.ConversionPattern [%p][%d{yy-MM-dd}][%c]%m%n #日志输出级别 log4j.logger.org.mybatisDEBUG log4j.logger.java.sqlDEBUG log4j.logger.java.sql.StatementDEBUG log4j.logger.java.sql.ResultSetDEBUG log4j.logger.java.sql.PreparedStatementDEBUG配置log4j为日志的实现settings setting namelogImpl valueLOG4J/ /settingsLog4j的使用直接测试运行刚才的查询简单使用在要使用Log4j的类中导入包import org.apache.log4j.Logger;日志对象参数为当前类的classstatic Logger logger Logger.getLogger(UserDaoTest.class);日志级别logger.info(info:进入了testLog4j); logger.debug(debug:进入了testLog4j); logger.error(error:进入了testLog4j);7. 分页思考为什么要分页减少数据的处理量7.1 使用Limit分页语法SELECT * from user limit startIndex,pageSize; SELECT * from user limit 3; #[0,n]使用MyBatis实现分页核心SQL接口//分页 ListUser getUserByLimit(MapString,Integer map);Mapper.xml!--分页-- select idgetUserByLimit parameterTypemap resultMapUserMap select * from mybatis.user limit #{startIndex},#{pageSize} /select测试Test public void getUserByLimit(){ SqlSession sqlSession MybatisUtils.getSqlSession(); UserMapper mapper sqlSession.getMapper(UserMapper.class); HashMapString, Integer map new HashMapString, Integer(); map.put(startIndex,1); map.put(pageSize,2); ListUser userList mapper.getUserByLimit(map); for (User user : userList) { System.out.println(user); } sqlSession.close(); }7.2 RowBounds分页不再使用SQL实现分页接口//分页2 ListUser getUserByRowBounds();mapper.xml!--分页2-- select idgetUserByRowBounds resultMapUserMap select * from mybatis.user /select测试Test public void getUserByRowBounds(){ SqlSession sqlSession MybatisUtils.getSqlSession(); //RowBounds实现 RowBounds rowBounds new RowBounds(1, 2); //通过Java代码层面实现分页 ListUser userList sqlSession.selectList(com.kuang.dao.UserMapper.getUserByRowBounds,null,rowBounds); for (User user : userList) { System.out.println(user); } sqlSession.close(); }7.3 分页插件了解即可万一以后公司的架构师说要使用需要知道是什么东西8. 使用注解开发8.1 面向接口编程大家之前都学过面向对象编程也学习过接口但在真正的开发中很多时候我们会选择面向接口编程根本原因解耦可拓展提高复用分层开发中上层不用管具体的实现大家都遵守共同的标准使得开发变得容易规范性更好在一个面向对象的系统中系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下各个对象内部是如何实现自己的对系统设计人员来讲就不那么重要了而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信大到各模块之间的交互在系统设计之初都是要着重考虑的这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程关于接口的理解接口从更深层次的理解应是定义规范约束与实现名实分离的原则的分离接口的本身反映了系统设计人员对系统的抽象理解接口应有两类第一类是对一个个体的抽象它可对应为一个抽象体abstract class第二类是对一个个体某一方面的抽象即形成一个抽象面interface一个个体有可能有多个抽象面。抽象体与抽象面是有区别的三个面向区别面向对象是指我们考虑问题时以对象为单位考虑它的属性及方法面向过程是指我们考虑问题时以一个具体的流程事务过程为单位考虑它的实现接口设计与非接口设计是针对复用技术而言的与面向对象过程不是一个问题更多的体现就是对系统整体的架构8.2 使用注解开发注解在接口上实现Select(select * from user) ListUser getUsers();需要在核心配置文件中绑定接口!--绑定接口-- mappers mapper classcom.kuang.dao.UserMapper/ /mappers测试本质反射机制实现底层动态代理MyBatis详细的执行流程8.3 CRUD我们可以在工具类创建的时候实现自动提交事务public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(true); }编写接口增加注解public interface UserMapper { Select(select * from user) ListUser getUsers(); //方法存在多个参数所有的参数前面必须加上Param(id)注解 Select(select * from user where id #{id}) User getUserByID(Param(id) int id); Insert(insert into user(id,name,pwd) 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) int id); }测试类【注意我们必须要将接口注册绑定到我们的核心配置文件中】关于Param()注解基本类型的参数或者String类型需要加上引用类型不需要加如果只有一个基本类型的话可以忽略但是建议大家都加上我们在SQL中引用的就是我们这里的Param()中设定的属性名#{} ${}区别#{}可以防止sql注入9. LombokProject Lombok is a java library that automatically plugs into your editor and build tools, spicing up your java. Never write another getter or equals method again, with one annotation your class has a fully featured builder, Automate your logging variables, and much more.java libraryplugsbuild toolswith one annotation your class使用步骤在IDEA中安装Lombok插件在项目中导入lombok的jar包!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -- dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.10/version scopeprovided/scope /dependency在实体类上加注解即可Getter and Setter FieldNameConstants ToString EqualsAndHashCode AllArgsConstructor, RequiredArgsConstructor and NoArgsConstructor Log, Log4j, Log4j2, Slf4j, XSlf4j, CommonsLog, JBossLog, Flogger, CustomLog Data Builder SuperBuilder Singular Delegate Value Accessors Wither With SneakyThrows val var experimental var UtilityClass Lombok config systemData AllArgsConstructor NoArgsConstructor public class User { private int id; private String name; private String password; }说明Data无参构造get、set、tostring、hashcode、equals AllArgsConstructor NoArgsConstructor EqualsAndHashCode ToString Getter10. 多对一处理多对一多个学生对应一个老师对于学生这边而言关联多个学生关联一个老师【多对一】对于老师而言集合一个老师有很多学生【一对多】SQLCREATE TABLE teacher ( id INT(10) NOT NULL, name VARCHAR(30) DEFAULT NULL, PRIMARY KEY (id) ) ENGINEINNODB DEFAULT CHARSETutf8 INSERT INTO teacher(id, name) 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) ) ENGINEINNODB DEFAULT CHARSETutf8 INSERT INTO student (id, name, tid) VALUES (1, 小明, 1); INSERT INTO student (id, name, tid) VALUES (2, 小红, 1); INSERT INTO student (id, name, tid) VALUES (3, 小张, 1); INSERT INTO student (id, name, tid) VALUES (4, 小李, 1); INSERT INTO student (id, name, tid) VALUES (5, 小王, 1);测试环境搭建导入lombok新建实体类TeacherStudent建立Mapper接口建立Mapper.xml文件在核心配置文件中绑定注册我们的Mapper接口或者文件【方式很多随心选】测试查询是否能够成功按照查询嵌套处理!-- 思路 1. 查询所有的学生信息 2. 根据查询出来的学生的tid寻找对应的老师 子查询 -- select idgetStudent resultMapStudentTeacher select * from student /select resultMap idStudentTeacher typeStudent result propertyid columnid/ result propertyname columnname/ !--复杂的属性我们需要单独处理 对象association 集合collection -- association propertyteacher columntid javaTypeTeacher selectgetTeacher/ /resultMap select idgetTeacher resultTypeTeacher select * from teacher where id #{id} /select按照结果嵌套处理!--按照结果嵌套处理-- select idgetStudent2 resultMapStudentTeacher2 select s.id sid,s.name sname,t.name tname from student s,teacher t where s.tid t.id; /select resultMap idStudentTeacher2 typeStudent result propertyid columnsid/ result propertyname columnsname/ association propertyteacher javaTypeTeacher result propertyname columntname/ /association /resultMap回顾Mysql多对一查询方式子查询联表查询11. 一对多处理比如一个老师拥有多个学生对于老师而言就是一对多的关系环境搭建环境搭建和刚才一样实体类Data public class Student { private int id; private String name; private int tid; } Data public class Teacher { private int id; private String name; //一个老师拥有多个学生 private ListStudent students; }按照结果嵌套处理!--按结果嵌套