当前位置: 首页 > article >正文

JAVA-Mybaits

1. Mybaits简介1.1 mybaits是什么mybaits 是一个半 ORM 对象关系映射框架它内部封装了 JDBC开发时只需要关注 SQL语句本身不需要花费精力去处理加载驱动、创建连接、创建 statement等繁杂的过程。程序员直接编写原生态SQL可以严格控制 SQL执行性能。灵活度高。mybaits 可以使用 XML 或注解来配置和映射原生信息将POJO 映射成数据库中的记录避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。1.2 Mybaits 优缺点优点与传统的数据库访问技术相比ORM有以下优点基于SQL语句编程相当灵活不会对应用程序或者数据库的现有设计造成任何影响SQL写在XML里解除sql与程序代码的耦合便于统一管理提供XML标签支持编写动态SQL语句并可重用与JDBC相比减少了50%以上的代码量消除了JDBC大量冗余的代码不需要手动开关连接很好的与各种数据库兼容因为Mybatis使用JDBC来连接数据库所以只要JDBC支持的数据库Mybatis都支持提供映射标签支持对象与数据库的ORM字段关系映射提供对象关系映射标签支持对象关系组件维护能够与Spring很好的集成缺点SQL语句的编写工作量较大尤其当字段多、关联表多时对开发人员编写SQL语句的功底有一定要求SQL语句依赖于数据库导致数据库移植性差不能随意更换数据库1.3 Hibernate 和 Mybatis 的区别相同点都是对jdbc的封装都是持久层的框架都用于dao层的开发。不同点映射关系Mybatis 是一个半自动映射的框架配置Java对象与sql语句执行结果的对应关系多表关联关系配置简单Hibernate 是一个全表映射的框架配置Java对象与数据库表的对应关系多表关联关系配置复杂SQL优化和移植性Hibernate 对SQL语句封装提供了日志、缓存、级联级联比 Mybatis 强大等特性此外还提供 HQLHibernate Query Language操作数据库数据库无关性支持好但会多消耗性能。如果项目需要支持多种数据库代码开发量少但SQL语句优化困难。Mybatis 需要手动编写 SQL支持动态 SQL、处理列表、动态生成表名、支持存储过程。开发工作量相对大些。直接使用SQL语句操作数据库不支持数据库无关性但sql语句优化容易。1.4 ORM是什么ORMObject Relational Mapping对象关系映射是一种为了解决关系型数据库数据与简单Java对象POJO的映射关系的技术。简单的说ORM是通过使用描述对象和数据库之间映射的元数据将程序中的对象自动持久化到关系型数据库中。1.5 为什么说Mybatis是半自动ORM映射工具它与全自动的区别在哪里Hibernate属于全自动ORM映射工具使用Hibernate查询关联对象或者关联集合对象时可以根据对象关系模型直接获取所以它是全自动的。而Mybatis在查询关联对象或关联集合对象时需要手动编写sql来完成所以称之为半自动ORM映射工具。1.6 传统JDBC开发存在什么问题频繁创建数据库连接对象、释放容易造成系统资源浪费影响系统性能。可以使用连接池解决这个问题。但是使用jdbc需要自己实现连接池。sql语句定义、参数设置、结果集处理存在硬编码。实际项目中sql语句变化的可能性较大一旦发生变化需要修改java代码系统需要重新编译重新发布。不好维护。使用preparedStatement向占有位符号传参数存在硬编码因为sql语句的where条件不一定可能多也可能少修改sql还要修改代码系统不易维护。结果集处理存在重复代码处理麻烦。如果可以映射成Java对象会比较方便。1.7 JDBC编程有哪些不足之处Mybatis是如何解决的1、数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能如果使用数据库连接池可解决此问题。解决在Mybatis-config.xml中配置数据链接池使用连接池管理数据库连接。2、Sql语句写在代码中造成代码不易维护实际应用sql变化的可能较大sql变动需要改变java代码。-解决将Sql语句配置在XXXXmapper.xml文件中与java代码分离。3、向sql语句传参数麻烦因为sql语句的where条件不一定可能多也可能少占位符需要和参数一一对应。解决 Mybatis自动将java对象映射至sql语句。4、对结果集解析麻烦sql变化导致解析代码变化且解析前需要遍历如果能将数据库记录封装成pojo对象解析比较方便。解决Mybatis自动将sql执行结果映射至java对象。1.8 Mybatis和Hibernate的适用场景?Mybatis专注于SQL本身是一个足够灵活的DAO层解决方案。对性能的要求很高或者需求变化较多的项目如互联网项目Mybatis将是不错的选择2 Mybatis的架构2.1 Mybatis编程步骤是什么样的1、 创建SqlSessionFactory2、 通过SqlSessionFactory创建SqlSession3、 通过sqlsession执行数据库操作4、 调用session.commit()提交事务5、 调用session.close()关闭会话2.2 Mybatis的工作原理Mybatis 的工作原理如下图读取 Mybatis 配置文件Mybatis-config.xml 为 Mybatis 的全局配置文件配置了 Mybatis 的运行环境等信息例如数据库连接信息。加载映射文件。映射文件即 SQL 映射文件该文件中配置了操作数据库的 SQL 语句需要在 Mybatis 配置文件 Mybatis-config.xml 中加载。Mybatis-config.xml 文件可以加载多个映射文件每个文件对应数据库中的一张表。构造会话工厂通过 Mybatis 的环境等配置信息构建会话工厂 SqlSessionFactory。创建会话对象由会话工厂创建 SqlSession 对象该对象中包含了执行 SQL 语句的所有方法。Executor 执行器Mybatis 底层定义了一个 Executor 接口来操作数据库它将根据 SqlSession 传递的参数动态地生成需要执行的 SQL 语句同时负责查询缓存的维护。MappedStatement 对象在 Executor 接口的执行方法中有一个 MappedStatement 类型的参数该参数是对映射信息的封装用于存储要映射的 SQL 语句的 id、参数等信息。输入参数映射输入参数类型可以是 Map、List 等集合类型也可以是基本数据类型和 POJO 类型。输入参数映射过程类似于 JDBC 对 preparedStatement 对象设置参数的过程。输出结果映射输出结果类型可以是 Map、 List 等集合类型也可以是基本数据类型和 POJO 类型。输出结果映射过程类似于 JDBC 对结果集的解析过程。2.3 Mybatis的功能架构我们把Mybatis的功能架构分为三层API接口层提供给外部使用的接口API开发人员通过这些本地API来操纵数据库。接口层一接收到调用请求就会调用数据处理层来完成具体的数据处理。数据处理层负责具体的SQL查找、SQL解析、SQL执行和执行结果映射处理等。它主要的目的是根据调用的请求完成一次数据库操作。基础支撑层负责最基础的功能支撑包括连接管理、事务管理、配置加载和缓存处理这些都是共用的东西将他们抽取出来作为最基础的组件。为上层的数据处理层提供最基础的支撑。2.4 Mybatis的框架架构设计是怎么样的这张图从上往下看。Mybatis的初始化会从Mybatis-config.xml配置文件解析构造成Configuration这个类就是图中的红框。加载配置配置来源于两个地方一处是配置文件一处是Java代码的注解将SQL的配置信息加载成为一个个MappedStatement对象包括了传入参数映射配置、执行的SQL语句、结果映射配置存储在内存中。SQL解析当API接口层接收到调用请求时会接收到传入SQL的ID和传入对象可以是Map、JavaBean或者基本数据类型Mybatis会根据SQL的ID找到对应的MappedStatement然后根据传入参数对象对MappedStatement进行解析解析后可以得到最终要执行的SQL语句和参数。SQL执行将最终得到的SQL和参数拿到数据库进行执行得到操作数据库的结果。结果映射将操作数据库的结果按照映射的配置进行转换可以转换成HashMap、JavaBean或者基本数据类型并将最终结果返回。2.5 什么是DBMSDBMS数据库管理系统(database management system)是一种操纵和管理数据库的大型软件用于建立、使用和维护数zd据库简称dbms。它对数据库进行统一的管理和控制以保证数据库的安全性和完整性。用户通过dbms访问数据库中的数据数据库管理员也通过dbms进行数据库的维护工作。它可使多个应用程序和用户用不同的方法在同时版或不同时刻去建立修改和询问数据库。DBMS提供数据定义语言DDLData Definition Language与数据操作语言DMLData Manipulation Language供用户定义数据库的模式结构与权限约束实现对数据的追加权、删除等操作。2.6 为什么需要预编译定义SQL 预编译指的是数据库驱动在发送 SQL 语句和参数给 DBMS 之前对 SQL 语句进行编译这样 DBMS 执行 SQL 时就不需要重新编译。为什么需要预编译JDBC 中使用对象 PreparedStatement 来抽象预编译语句使用预编译。预编译阶段可以优化 SQL 的执行。预编译之后的 SQL 多数情况下可以直接执行DBMS 不需要再次编译越复杂的SQL编译的复杂度将越大预编译阶段可以合并多次操作为一个操作。同时预编译语句对象可以重复利用。把一个 SQL 预编译后产生的 PreparedStatement 对象缓存下来下次对于同一个SQL可以直接使用这个缓存的 PreparedState 对象。Mybatis默认情况下将对所有的 SQL 进行预编译。还有一个重要的原因复制SQL注入2.7 Mybatis都有哪些Executor执行器它们之间的区别是什么Mybatis有三种基本的Executor执行器SimpleExecutor、ReuseExecutor、BatchExecutor。SimpleExecutor每执行一次update或select就开启一个Statement对象用完立刻关闭Statement对象。ReuseExecutor执行update或select以sql作为key查找Statement对象存在就使用不存在就创建用完后不关闭Statement对象而是放置于MapString, Statement内供下一次使用。简言之就是重复使用Statement对象。BatchExecutor执行update没有selectJDBC批处理不支持select将所有sql都添加到批处理中addBatch()等待统一执行executeBatch()它缓存了多个Statement对象每个Statement对象都是addBatch()完毕后等待逐一执行executeBatch()批处理。与JDBC批处理相同。作用范围Executor的这些特点都严格限制在SqlSession生命周期范围内。2.8 Mybatis中如何指定使用哪一种Executor执行器在Mybatis配置文件中在设置settings可以指定默认的ExecutorType执行器类型也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数如SqlSession openSession(ExecutorType execType)。配置默认的执行器。SIMPLE 就是普通的执行器REUSE 执行器会重用预处理语句prepared statements BATCH 执行器将重用语句并执行批量更新。2.9 Mybatis是否支持延迟加载如果支持它的实现原理是什么Mybatis仅支持association关联对象和collection关联集合对象的延迟加载association指的就是一对一collection指的就是一对多查询。在Mybatis配置文件中可以配置是否启用延迟加载lazyLoadingEnabledtrue|false。它的原理是使用CGLIB创建目标对象的代理对象当调用目标方法时进入拦截器方法比如调用a.getB().getName()拦截器invoke()方法发现a.getB()是null值那么就会单独发送事先保存好的查询关联B对象的sql把B查询上来然后调用a.setB(b)于是a的对象b属性就有值了接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。当然了不光是Mybatis几乎所有的包括Hibernate支持延迟加载的原理都是一样的。3 映射器3.1 #{} 和 ${}#{}是占位符预编译处理${}是拼接符字符串替换没有预编译处理。Mybatis在处理#{}时#{}传入参数是以字符串传入会将SQL中的#{}替换为?号调用PreparedStatement的set方法来赋值。#{} 可以有效的防止SQL注入提高系统安全性${} 不能防止SQL 注入#{} 的变量替换是在DBMS 中${} 的变量替换是在 DBMS 外3.2 模糊查询like语句该怎么写’%${question}%’ 可能引起SQL注入不推荐%#{question}% 注意因为#{…}解析成sql语句时候会在变量外侧自动加单引号’ 所以这里 % 需要使用双引号 不能使用单引号 ’ 不然会查不到任何结果。CONCAT(’%’,#{question},’%’) 使用CONCAT()函数推荐使用bind标签不推荐select idlistUserLikeUsername resultTypecom.jourwon.pojo.User bind namepattern value% username % / select id,sex,age,username,password from person where username LIKE #{pattern} /select3.3 再Mapper中如何传递多个参数方法1顺序传参法public User selectUser(String name, int deptId); ​ select idselectUser resultMapUserResultMap select * from user where user_name #{0} and dept_id #{1} /select#{}里面的数字代表传入参数的顺序。这种方法不建议使用sql层表达不直观且一旦顺序调整容易出错。方法2Param注解传参法public User selectUser(Param(userName) String name, int Param(deptId) deptId); ​ select idselectUser resultMapUserResultMap select * from user where user_name #{userName} and dept_id #{deptId} /select#{}里面的名称对应的是注解Param括号里面修饰的名称。这种方法在参数不多的情况还是比较直观的推荐使用。方法3Map传参法public User selectUser(MapString, Object params); ​ select idselectUser parameterTypejava.util.Map resultMapUserResultMap select * from user where user_name #{userName} and dept_id #{deptId} /select#{}里面的名称对应的是Map里面的key名称。这种方法适合传递多个参数且参数易变能灵活传递的情况。推荐使用。方法4Java Bean传参法public User selectUser(User user); ​ select idselectUser parameterTypecom.jourwon.pojo.User resultMapUserResultMap select * from user where user_name #{userName} and dept_id #{deptId} /select#{}里面的名称对应的是User类里面的成员属性。这种方法直观需要建一个实体类扩展不容易需要加属性但代码可读性强业务逻辑处理方便推荐使用。推荐使用。3.4 Mybatis如何执行批量操作使用foreach标签foreach的主要用在构建in条件中它可以在SQL语句中进行迭代一个集合。foreach标签的属性主要有itemindexcollectionopenseparatorclose。item 表示集合中每一个元素进行迭代时的别名随便起的变量名index 指定一个名字用于表示在迭代过程中每次迭代到的位置不常用open 表示该语句以什么开始常用“(”separator 表示在每次进行迭代之间以什么符号作为分隔符常用“,”close 表示以什么结束常用“)”。在使用foreach的时候最关键的也是最容易出错的就是collection属性该属性是必须指定的但是在不同情况下该属性的值是不一样的主要有一下3种情况如果传入的是单参数且参数类型是一个List的时候collection属性值为list如果传入的是单参数且参数类型是一个array数组的时候collection的属性值为array如果传入的参数是多个的时候我们就需要把它们封装成一个Map了当然单参数也可以封装成map实际上如果你在传入参数的时候在Mybatis里面也是会把它封装成一个Map的 map的key就是参数名所以这个时候collection属性值就是传入的List或array对象在自己封装的map里面的key具体用法!-- 批量保存(foreach插入多条数据两种方法) int addEmpsBatch(Param(emps) ListEmployee emps); -- !-- MySQL下批量保存可以foreach遍历 mysql支持values(),(),()语法 -- //推荐使用 insert idaddEmpsBatch INSERT INTO emp(ename,gender,email,did) VALUES foreach collectionemps itememp separator, (#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id}) /foreach /insert!-- 这种方式需要数据库连接属性allowMutiQueriestrue的支持 如jdbc.urljdbc:mysql://localhost:3306/Mybatis?allowMultiQueriestrue -- insert idaddEmpsBatch foreach collectionemps itememp separator; INSERT INTO emp(ename,gender,email,did) VALUES(#{emp.eName},#{emp.gender},#{emp.email},#{emp.dept.id}) /foreach /insert使用ExecutorType.BATCHMybatis内置的ExecutorType有3种默认为simple,该模式下它为每个语句的执行创建一个新的预处理语句单条提交sql而batch模式重复使用已经预处理的语句并且批量执行所有更新语句显然batch性能将更优 但batch模式也有自己的问题比如在Insert操作时在事务没有提交之前是没有办法获取到自增的id这在某型情形下是不符合业务要求的具体用法//批量保存方法测试 Test public void testBatch() throws IOException{ SqlSessionFactory sqlSessionFactory getSqlSessionFactory(); //可以执行批量操作的sqlSession SqlSession openSession sqlSessionFactory.openSession(ExecutorType.BATCH); //批量保存执行前时间 long start System.currentTimeMillis(); try { EmployeeMapper mapper openSession.getMapper(EmployeeMapper.class); for (int i 0; i 1000; i) { mapper.addEmp(new Employee(UUID.randomUUID().toString().substring(0, 5), b, 1)); } openSession.commit(); long end System.currentTimeMillis(); //批量保存执行后的时间 System.out.println(执行时长 (end - start)); //批量 预编译sql一次》设置参数》10000次》执行1次 677 //非批量 预编译设置参数执行 》10000次 1121 } finally { openSession.close(); } }public interface EmployeeMapper { //批量保存员工 Long addEmp(Employee employee); } mapper namespacecom.jourwon.mapper.EmployeeMapper !--批量保存员工 -- insert idaddEmp insert into employee(lastName,email,gender) values(#{lastName},#{email},#{gender}) /insert /mapper3.5 什么是Mybatis的接口绑定有哪些实现方式接口绑定就是在Mybatis中任意定义接口然后把接口里面的方法和SQL语句绑定我们直接调用接口方法就可以这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。接口绑定有两种实现方式通过注解绑定就是在接口的方法上面加上 Select、Update等注解里面包含Sql语句来绑定通过xml里面写SQL来绑定 在这种情况下要指定xml映射文件里面的namespace必须为接口的全路径名。当Sql语句比较简单时候用注解绑定 当SQL语句比较复杂时候用xml绑定一般用xml绑定的比较多。3.6 这个Dao接口的工作原理是什么Dao接口里的方法参数不同时方法能重载吗Dao接口的工作原理是JDK动态代理Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象代理对象proxy会拦截接口方法转而执行MappedStatement所代表的sql然后将sql执行结果返回。Dao接口里的方法是不能重载的因为是全限名方法名的保存和寻找策略。3.7 Mybatis的Xml映射文件中不同的Xml映射文件id是否可以重复不同的Xml映射文件如果配置了namespace那么id可以重复如果没有配置namespace那么id不能重复毕竟namespace不是必须的只是最佳实践而已。原因就是namespaceid是作为MapString, MappedStatement的key使用的如果没有namespace就剩下id那么id重复会导致数据互相覆盖。有了namespace自然id就可以重复namespace不同namespaceid自然也就不同。3.8 简述Mybatis的Xml映射文件和Mybatis内部数据结构之间的映射关系Mybatis将所有Xml配置信息都封装到All-In-One重量级对象Configuration内部。在Xml映射文件中parameterMap标签会被解析为ParameterMap对象其每个子元素会被解析为ParameterMapping对象。resultMap标签会被解析为ResultMap对象其每个子元素会被解析为ResultMapping对象。每一个select、insert、update、delete标签均会被解析为MappedStatement对象标签内的sql会被解析为BoundSql对象。3.9 Mybatis是如何将sql执行结果封装为目标对象并返回的都有哪些映射形式第一种是使用resultMap标签逐一定义列名和对象属性名之间的映射关系。第二种是使用sql列的别名功能将列别名书写为对象属性名比如T_NAME AS NAME对象属性名一般是name小写但是列名不区分大小写Mybatis会忽略列名大小写智能找到与之对应对象属性名你甚至可以写成T_NAME AS NaMeMybatis一样可以正常工作。有了列名与属性名的映射关系后Mybatis通过反射创建对象同时使用反射给对象的属性逐一赋值并返回那些找不到映射关系的属性是无法完成赋值的。3.10 Xml映射文件中除了常见的select|insert|updae|delete标签之外还有哪些标签还有很多其他的标签resultMap、parameterMap、sql、include、selectKey加上动态sql的9个标签trim|where|set|foreach|if|choose|when|otherwise|bind等其中sql为sql片段标签通过include标签引入sql片段selectKey为不支持自增的主键生成策略标签。3.11 Mybatis映射文件中如果A标签通过include引用了B标签的内容请问B标签能否定义在A标签的后面还是说必须定义在A标签的前面虽然Mybatis解析Xml映射文件是按照顺序解析的但是被引用的B标签依然可以定义在任何地方Mybatis都可以正确识别。原理是Mybatis解析A标签发现A标签引用了B标签但是B标签尚未解析到尚不存在此时Mybatis会将A标签标记为未解析状态然后继续解析余下的标签包含B标签待所有标签解析完毕Mybatis会重新解析那些被标记为未解析的标签此时再解析A标签时B标签已经存在A标签也就可以正常解析完成了。3.12 Mybatis能执行一对多一对一的联系查询吗有哪些实现方法能不止可以一对多一对一还可以多对多一对多实现方式单独发送一个SQL去查询关联对象赋给主对象然后返回主对象使用嵌套查询似JOIN查询一部分是A对象的属性值另一部分是关联对 象 B的属性值好处是只要发送一个属性值就可以把主对象和关联对象查出来子查询3.13 Mybatis是否可以映射Enum枚举类Mybatis可以映射枚举类不单可以映射枚举类Mybatis可以映射任何对象到表的一列上。映射方式为自定义一个TypeHandler实现TypeHandler的setParameter()和getResult()接口方法。TypeHandler有两个作用一是完成从javaType至jdbcType的转换二是完成jdbcType至javaType的转换体现为setParameter()和getResult()两个方法分别代表设置sql问号占位符参数和获取列查询结果。3.14 Mybatis动态sql是做什么的都有哪些动态sql能简述一下动态sql的执行原理吗Mybatis动态sql可以让我们在Xml映射文件内以标签的形式编写动态sql完成逻辑判断和动态拼接sql的功能Mybatis提供了9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind。其执行原理为使用OGNL从sql参数对象中计算表达式的值根据表达式的值动态拼接sql以此来完成动态sql的功能。3.15 Mybatis是如何进行分页的分页插件的原理是什么Mybatis使用RowBounds对象进行分页它是针对ResultSet结果集执行的内存分页而非物理分页可以在sql内直接书写带有物理分页的参数来完成物理分页功能也可以使用分页插件来完成物理分页。分页插件的基本原理是使用Mybatis提供的插件接口实现自定义插件在插件的拦截方法内拦截待执行的sql然后重写sql根据dialect方言添加对应的物理分页语句和物理分页参数。举例select * from student拦截sql后重写为select t.* from (select * from student) t limit 0, 103.16 简述Mybatis的插件运行原理以及如何编写一个插件Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件Mybatis使用JDK的动态代理为需要拦截的接口生成代理对象以实现接口方法拦截功能每当执行这4种接口对象的方法时就会进入拦截方法具体就是InvocationHandler的invoke()方法当然只会拦截那些你指定需要拦截的方法。实现Mybatis的Interceptor接口并复写intercept()方法然后在给插件编写注解指定要拦截哪一个接口的哪些方法即可记住别忘了在配置文件中配置你编写的插件。4. Mybatis延迟加载及其原理和延迟加载配置4.1 概念Mybatis中的延迟加载也称为懒加载是指再进行表的关联查询时按照设置延迟规则推迟对关联对象select 查询。例如 在进行一对多查询的时候只查询出一方当程序中需要多方的数据时Mybatis再发出sql语句进行查询。这样子延迟加载就可以减少数据库的压力。Mybatis的延迟加载只是对关联对象的查询有延迟设置对于主加载对象都是直接执行查询语句的。4.2 原理Mybatis实现延迟加载的方式是使用代理对象再访问未加载的数据时触发代理对象的方法从而进行数据的加载4.3 延迟加载支持对象Mybatis 仅支持 association 关联对象和collection 关联集合对象的延迟加载association 指的就是一对一collection 指的就是一堆多查询4.4 配置延迟加载配置全局延迟加载!-- 在Mybatis的核⼼配置⽂件中可以使⽤setting标签修改全局的加载策略-- settings !-- 打开延迟加载的开关 -- setting namelazyLoadingEnabled valuetrue/ !--不是必要的标签 false 深入式延迟加载 true 侵入式延迟加载 -- setting nameaggressiveLazyLoading valuefalse/ /settings侵入式延迟加载和深入式延迟加载的区别class 与 student 之间式一对多的关系 我们在加载时可以先加载class 数据当需要使用到 student 数据时我们再加载 student 的相关数据侵入式延迟加载侵入式延迟加载指的是只要主表的任一属性加载就会触发延迟加载。比如 class的name 被加载student 信息就会被触发加载深度延迟加载深度延迟加载指的是只有关联的从表信息被加载延迟加载才会被触发通常我们在实战中更倾向使用深度延迟加载配置局部延迟加载!--修改标签的fetchType属性 fetchTypelazy 延迟加载策略 fetchTypeeager ⽴即加载策略-- resultMap idkunkunMap typeuser id columnid propertyid/id result columnctrl propertyctrl/result !--开启⼀对多 延迟加载-- collection propertyuserList ofTypeorder columnid selectcom.lagou.dao.OrderMapper.findByUid fetchTypelazy /collection !--开启⼀对一 延迟加载-- association propertyorder columnid javaTypeorder selectcom.xinxin.dao.OrderMapper.findById fetchTypelazy /association /resultMap加载顺序局部的加载策略的优先级高于全局的加载策略4.5Mybatis支持延迟加载懒加载吗原理是什么支持的对象Mybatis仅支持 association 关联对象和collection关联集合对象的延迟加载association 指的就是一对一collection 指的就是一对多查询概念 延迟加载的原理是在查询时只加载部分数据当需要访问未加载的数据时在进行加载。这样可以减少查询所需的时间和资源提高系统性能原理 Mybatis 实现延迟加载的方式是使用代理对象在访问未加载的数据时触发代理对象的方法从而进行数据的加载。延迟加载可以通过配置文件或注解来实现4.6如何获取自动生成的主键值insert id”insertname” usegeneratedkeys”true” keyproperty”id” 新增sql /insert5 Mybaits的一级和二级缓存5.1 核心概念与区别先通过表格清晰区分两者的核心差异特性一级缓存本地缓存二级缓存全局缓存作用域SqlSession 级别会话级Mapper 级别全局级跨 SqlSession默认状态默认开启无法关闭默认关闭需手动开启存储位置内存SqlSession 内部内存 / 磁盘可配置默认 PerpetualCache共享范围仅当前会话可见同一个 Mapper 的所有会话共享失效时机SqlSession 关闭 / 提交 / 回滚、执行增删改操作Mapper 下执行增删改操作、缓存过期 / 清理5.2 一级缓存最常用重点掌握1. 工作原理当你通过一个SqlSession执行查询操作时MyBatis 会先将查询结果存入该SqlSession的一级缓存中同一个SqlSession内再次执行完全相同的查询SQL 语句 参数 环境等一致MyBatis 会直接从一级缓存取数据不再访问数据库一旦SqlSession执行close()、commit()、rollback()或执行增删改操作会自动清空当前 SqlSession 的一级缓存一级缓存就会失效。2. 代码示例直观理解import org.apache.ibatis.session.SqlSession; import org.junit.Test; import com.xxx.mapper.UserMapper; import com.xxx.pojo.User; import com.xxx.utils.MyBatisUtil; public class MyBatisCacheTest { Test public void testFirstLevelCache() { // 1. 获取第一个SqlSession try (SqlSession session1 MyBatisUtil.getSqlSession()) { UserMapper mapper1 session1.getMapper(UserMapper.class); // 第一次查询访问数据库结果存入一级缓存 User user1 mapper1.selectUserById(1); System.out.println(user1); // 第二次查询同一个SqlSession直接从一级缓存获取无数据库访问 User user2 mapper1.selectUserById(1); System.out.println(user1 user2); // 输出true是同一个对象 // 执行增删改操作一级缓存被清空 mapper1.updateUser(new User(1, test)); session1.commit(); // 提交后缓存失效 // 第三次查询重新访问数据库 User user3 mapper1.selectUserById(1); System.out.println(user1 user3); // 输出false } // 2. 新的SqlSession一级缓存独立重新查询 try (SqlSession session2 MyBatisUtil.getSqlSession()) { UserMapper mapper2 session2.getMapper(UserMapper.class); User user4 mapper2.selectUserById(1); System.out.println(user4); // 访问数据库 } } }3. 注意点一级缓存的 “相同查询” 要求SQL 语句、参数、分页、RowBounds、环境environment等完全一致如果手动调用session.clearCache()会主动清空当前 SqlSession 的一级缓存一级缓存是 MyBatis 内置的无需任何配置开箱即用。5.3 二级缓存全局缓存按需开启1. 工作原理二级缓存的作用域是Mapper 接口即同一个 namespace多个 SqlSession 共享同一个 Mapper 的二级缓存当 SqlSession 关闭close()时其一级缓存中的数据会被刷入二级缓存后续其他 SqlSession 查询该 Mapper 的相同数据时会优先从二级缓存获取再查一级缓存最后查数据库。2. 开启和使用步骤完整可执行步骤 1全局配置开启二级缓存mybatis-config.xmlconfiguration !-- 开启二级缓存默认是true可省略但显式配置更清晰 -- settings setting namecacheEnabled valuetrue/ /settings /configuration步骤 2在 Mapper.xml 中开启当前 Mapper 的二级缓存!-- UserMapper.xml -- mapper namespacecom.xxx.mapper.UserMapper !-- 开启当前Mapper的二级缓存 -- cache evictionLRU !-- 缓存淘汰策略LRU最近最少使用 -- flushInterval60000 !-- 缓存自动刷新时间毫秒 -- size1024 !-- 缓存最多存储的对象数量 -- readOnlytrue/ !-- 只读缓存性能更高避免序列化开销 -- !-- 查询语句默认开启缓存可通过useCachefalse关闭 -- select idselectUserById resultTypecom.xxx.pojo.User useCachetrue SELECT * FROM user WHERE id #{id} /select !-- 增删改操作默认清空当前Mapper的二级缓存可通过flushCachefalse关闭 -- update idupdateUser parameterTypecom.xxx.pojo.User flushCachetrue UPDATE user SET name #{name} WHERE id #{id} /update /mapper步骤 3实体类必须实现序列化接口Serializable因为二级缓存可能将数据序列化存储如分布式场景所以实体类需要序列化public class User implements Serializable { // 必须实现Serializable private Integer id; private String name; // 构造器、getter/setter、toString省略 }步骤 4代码测试二级缓存Test public void testSecondLevelCache() { // 第一个SqlSession try (SqlSession session1 MyBatisUtil.getSqlSession()) { UserMapper mapper1 session1.getMapper(UserMapper.class); User user1 mapper1.selectUserById(1); System.out.println(user1); // 关闭session1一级缓存数据刷入二级缓存 session1.close(); } // 第二个SqlSession跨会话共享二级缓存 try (SqlSession session2 MyBatisUtil.getSqlSession()) { UserMapper mapper2 session2.getMapper(UserMapper.class); User user2 mapper2.selectUserById(1); System.out.println(user2); // 从二级缓存获取无数据库访问 System.out.println(user1 user2); // 若readOnlytrue返回true否则false序列化反序列化 } }3. 关键配置说明eviction淘汰策略LRU最近最少使用移除最长时间未使用的对象默认FIFO先进先出按缓存加入顺序移除SOFT软引用基于 JVM 垃圾回收机制移除WEAK弱引用比软引用更易被回收。readOnlytrue缓存的对象是只读的直接返回引用性能高false则返回对象的拷贝序列化 / 反序列化更安全但性能稍低。可通过useCachefalse给单个查询禁用二级缓存如实时性要求高的查询增删改操作默认flushCachetrue会清空当前 Mapper 的二级缓存保证数据一致性。5.4 使用注意事项避坑重点数据一致性问题二级缓存是全局的若多个应用 / 服务共享同一个 MyBatis 二级缓存可能出现数据不一致建议分布式场景用 Redis 替代对频繁修改的表尽量关闭二级缓存避免缓存数据与数据库不一致。关联查询的缓存问题若 Mapper 中包含关联查询如association/collection需确保关联的实体类也序列化且缓存策略统一跨 Mapper 的关联查询二级缓存可能无法生效需谨慎使用。缓存失效场景执行增删改操作flushCachetrueSqlSession 未关闭一级缓存未刷入二级缓存查询参数不同、分页条件不同手动调用sqlSession.clearCache()仅清空一级缓存或mapper.clearCache()清空当前 Mapper 二级缓存。总结MyBatis 一级缓存是SqlSession 级的默认缓存同一个会话内重复查询自动生效会话关闭 / 增删改操作会失效二级缓存是Mapper 级的全局缓存需手动开启全局配置 Mapper 配置实体类需序列化跨会话共享数据使用核心原则对查询频繁、修改极少的数据开启二级缓存如字典表频繁修改的表禁用分布式场景优先用 Redis 等中间件替代 MyBatis 二级缓存。

相关文章:

JAVA-Mybaits

1. Mybaits简介 1.1 mybaits是什么 mybaits 是一个半 ORM (对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement等繁杂的过程。程序员直接编…...

二分算法 cpp

7. 二分算法 基础算法中最难的原理与模板简单难点在细节处理边界问题解集中存在二段性 模板题 : [!leetcode] 34. 在排序数组中查找元素的第一个和最后一个位置 中等 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中…...

eclipse下载、安装、编写运行helloworld教程

1.官网下载 访问官网下载最新版安装包(绿色免安装压缩包) 官网安装包下载地址:https://www.eclipse.org/downloads/packages/,选择企业级版本“Eclipse IDE for Enterprise Java and Web Developers”,操作系统版本根…...

新160个CrackMe 008,009号:Afkayas.1,Boonz-KeygenMe#1逆向分析

008Die分析文件组成Win32,无壳,语言:VB动态调试双击程序运行,弹出窗口,输入用户名和序列号(例如abcd,123456)点击ok查找字符串,双击定位字符串,向上找函数入口下断点&…...

试过30多个副业后,我只推荐这2个靠谱项目!

一晃,已经整整十年了。这十年,在互联网圈子里摸爬滚打,没有捷径,没有躺赢,若用一个词形容,便是「热辣滚烫」—— 每一步都踩得扎实,每一份收获都拼得坦荡。常有人问我:你凭什么能带出…...

基于Flask的人脸识别OOD模型API服务开发

基于Flask的人脸识别OOD模型API服务开发 1. 引言 人脸识别技术在实际应用中经常面临一个挑战:如何处理那些低质量、噪声干扰或者分布外(Out-of Distribution,OOD)的输入数据。传统的人脸识别系统往往会对这些异常样本给出高置信…...

K64F平台FXOS8700传感器驱动与姿态融合实战

1. K64_FXOS8700 驱动库深度解析:面向工业级姿态感知的双轴传感器融合实现1.1 项目定位与工程价值K64_FXOS8700 是专为 NXP K64F 微控制器(基于 ARM Cortex-M4 内核,主频 120MHz,带 FPU)设计的 FXOS8700CQ 九轴传感器驱…...

挑中年大叔头像AI头像时,看着精致不代表后面能细修

在实际设计任务中,千图网的AI生成头像功能已成为许多门店和内容团队的首选工具。日前接到需求,需要为社群活动物料快速输出一批中年大叔形象的社交头像,要求风格沉稳、辨识度高,并能方便后续调整细节。首轮构思时决定,…...

Helsinki-NLP/opus-mt-en-zh模型实战:快速搭建英译中翻译工具

1. 5分钟快速上手:用Helsinki-NLP模型实现英译中 最近在做一个需要实时翻译英文文档的项目,试了几种方案后发现Hugging Face的Helsinki-NLP/opus-mt-en-zh模型特别适合快速集成。这个由赫尔辛基大学NLP团队开发的模型,在通用领域的英译中任务…...

工业相机选型基础:曝光时间、增益与信噪比的三角平衡关系

工业相机选型基础:曝光时间、增益与信噪比的三角平衡关系导读:在视觉项目选型现场,甲方常问:“我要拍清楚高速运动的零件,还要在昏暗环境下看清细微划痕,预算能不能少点?” 作为工程师&#xff…...

稳如磐石:STM32F4 与 DP83848 打造的以太网驱动工程

stm32f4 dp83848 以太网驱动程序稳定版工程 用的armfly例程里的tcpnet 改进加了网线断线重连 端口断开重连打包发送 可跑慢百兆速度 连续实测24小时以上无错误 dp83848 phy芯片是汽车级 工业场合要比dm9161 lan8720…更稳定可靠最近在搞一个基于 STM32F4 和 DP83848 的以太网驱…...

微信小程序电商实战:前后端分离架构,20章吃透全栈开发+上线部署

在私域电商爆发、小程序成为商家标配的当下,能独立开发全栈小程序电商的开发者,早已成为职场抢手人才。可市面上多数教程要么只讲前端皮毛、要么后端逻辑模糊,要么堆砌零散知识点,学完依旧做不出可落地、可商用的项目,…...

用Anaconda玩转D2L教材:手把手教你同步李沐AI课程实验环境(Python3.8.5版)

用Anaconda玩转D2L教材:手把手教你同步李沐AI课程实验环境(Python3.8.5版) 在深度学习的学习过程中,一个与教材完全匹配的实验环境往往能事半功倍。《动手学深度学习》(D2L)作为李沐老师的经典教材&#xf…...

RecyclerView Demo - Android列表组件详解

RecyclerView Demo - Android列表组件详解 📚 目录 项目介绍 环境要求 快速开始 项目结构 代码详解 运行效果 常见问题 扩展学习 项目介绍 这是一个专门为Android初学者设计的 RecyclerView 演示项目。 RecyclerView是什么? RecyclerView是Android Jetpack组件库中的一个…...

从二维地图到UE5数字孪生:GIS的‘升维’之路与未来应用场景漫谈

从二维地图到UE5数字孪生:GIS的‘升维’之路与未来应用场景漫谈 当我们打开手机导航,二维地图已经像空气一样自然地融入日常生活。但很少有人意识到,这些看似简单的线条背后,正经历着一场从平面到立体、从静态到动态、从观察到交互…...

WinForm实战:5分钟搞定Halcon12调用笔记本摄像头扫二维码(附完整C#代码)

5分钟极简实战:Halcon12C# WinForm调用笔记本摄像头扫码全指南 每次看到商场收银台"嘀"一声完成扫码支付时,有没有想过自己动手实现类似功能?作为C#开发者,你可能已经厌倦了复杂的摄像头调用和图像处理库集成。今天我将…...

终于解决了「选文字就自动 Ctrl+C」的玄学 Bug!

终于解决了「选文字就自动 CtrlC」的玄学 Bug! 最近用飞牛 NAS 的 FntermX 终端、甚至各种 SSH 工具时,只要用鼠标拖拽选文字,就会自动触发 CtrlC 中断,满屏都是^C,复制个配置文件都要疯了! 一开始以为是终…...

Fish-Speech-1.5情感语音合成:基于RLHF的语调控制

Fish-Speech-1.5情感语音合成:基于RLHF的语调控制 1. 听见情绪的温度:当语音不再只是“读出来” 你有没有听过一段语音,明明内容普通,却让你心头一紧?或者一句简单的“谢谢”,因为语气里带着真诚的暖意&a…...

nlp_structbert_sentence-similarity_chinese-large 在嵌入式设备部署的探索与优化

nlp_structbert_sentence-similarity_chinese-large 在嵌入式设备部署的探索与优化 最近在做一个智能家居中控的项目,需要让设备能“听懂”用户指令的意图,比如“打开客厅的灯”和“把客厅的灯调亮”是不是一个意思。这自然就用到了语义相似度模型。我们…...

测试1111

测试1111...

HNU2026-计算机系统-第一次作业

2026年春第一次作业: 教材第19页,第2题; 教材第47页,第5题; 教材第48页,第6题。第 2 题 一个字节可以用两个十六进制数来表示。填写下表中缺失的项,给出不同字节模式的十进制、二进制和十六进制…...

Qwen-Image-2512-Pixel-Art-LoRA 模型v1.0 企业级应用:SpringBoot微服务集成与API封装

Qwen-Image-2512-Pixel-Art-LoRA 模型v1.0 企业级应用:SpringBoot微服务集成与API封装 最近在帮一个游戏开发团队做内部工具升级,他们有个挺有意思的需求:想在自己的项目管理后台里,集成一个快速生成像素艺术素材的功能。美术同学…...

使用新版子开发的问题总结

目录 一、问题现象 二、根本原因 2.1 硬件差异(即使 CPU 相同) 2.2 软件差异 2.3 编译环境差异 三、为什么不能直接复制? 3.1 动态链接问题 3.2 设备树问题 3.3 路径问题 四、解决方案 4.1 方案对比 4.2 方案1:针对板子…...

怎么想到用双指针法?怎么时候用?(算法)(数组)

一、先观察题目特点 二、有那种”要从数组两端左右向中间逼近取数的感觉的时候用 三、例题(977. 有序数组的平方 - 力扣(LeetCode)) 【代码随想录】(题目讲解)视频链接:双指针法经典题目 | Lee…...

从ConnectionReset到StateHashMismatch:MCP客户端同步失败的6类错误码速查表与自动恢复策略

第一章:从ConnectionReset到StateHashMismatch:MCP客户端同步失败的6类错误码速查表与自动恢复策略MCP(Model Control Protocol)客户端在分布式状态同步过程中,常因网络抖动、服务端状态漂移、时钟偏斜或序列化不一致等…...

GLM-OCR多场景落地:图书馆数字化项目中百万页文献批量OCR流水线设计

GLM-OCR多场景落地:图书馆数字化项目中百万页文献批量OCR流水线设计 1. 项目背景与需求分析 图书馆数字化项目面临着一个核心挑战:如何高效地将海量纸质文献转化为可搜索、可编辑的数字文本。传统OCR技术在处理复杂版式、多语言混合、历史文献退化等问…...

基于SpringBoot+Vue2的AI流式对话实现:从后端处理到前端展示

1. 为什么需要流式对话交互 在传统的前后端交互中,用户发送请求后需要等待后端完全处理完毕才能看到结果。当处理AI对话这类耗时操作时,这种模式会让用户面对长时间的白屏等待。我去年开发客服系统时就遇到过这个问题——当用户提问复杂问题时&#xff0…...

架构演进与性能压榨:在金融 RAG 中引入条款森林 (FoC)

业务痛点:在金融/医疗等强层级长文档场景中,传统向量检索(含混合检索)面对“跨章节逻辑对比”问题时,存在结构性召回缺失。架构破局:设计了 FoC (Forest of Clauses) 条款森林 架构,将文档目录树…...

【Agents】Claude Code 多 Agent 入门:从一问一答到并行协作

​ 你和 Claude Code 的日常是不是这样,敲一句提示、等它回答、再敲一句?这种"你来我往"的 QA 乒乓模式,处理简单任务绰绰有余。但一旦任务变复杂,比如"搜索项目里所有 deprecated API,同时检查 README…...

关于类和对象的基本区别

我将以我如今的知识来归纳一二一、定义1.类的定义类(class)就是某类事物,其中包含着它这个类的共同特征(属性)和行为(方法)。例如:学生类的属性(名字,年龄等&…...