MyBatis面经
MyBatis常见面试题
!!本文主要是博主总结看着玩的,不具有很高的参考价值,慎重
1、MyBatis是什么?MyBatis工作原理?MyBatis的使用场景有哪些?
MyBatis是一款优秀的持久层框架,它是一个基于Java语言的ORM框架,通过XML或注解的方式将Java对象和数据库中的表进行映射,实现持久化操作。
mybatis工作原理:
大家可以看一下源码。推荐文章MyBatis底层原理小白版本
mybatis配置文件,包括Mybatis全局配置文件和Mybatis映射文件,其中全局配置文件配置了数据源、事务等信息;映射文件配置了SQL执行相关的信息。
mybatis通过读取配置文件信息(全局配置文件和映射文件),构造出SqlSessionFactory,即会话工厂。
通过SqlSessionFactory,可以创建SqlSession即会话。
Mybatis是通过SqlSession来操作数据库的。SqlSession本身不能直接操作数据库,它是通过底层的Executor执行器接口来操作数据库的。
Executor接口有两个实现类,一个是普通执行器,一个是缓存执行器(默认)。Executor执行器要处理的SQL信息是封装到一个底层对象MappedStatement中。
MyBatis在以下场景下都有着广泛的应用:
1、数据库访问操作:MyBatis提供了灵活的SQL语句编写和自定义的SQL映射,可以更加细粒度地控制SQL语句的执行,因此适用于需要对数据库进行复杂操作的场景。
2、大数据量操作:MyBatis的批量操作和分页查询功能能够很好地处理大量数据的访问和操作,因此适用于需要对大量数据进行操作的场景。
3、高并发访问:MyBatis的缓存机制可以有效地减少数据库访问的次数,提高系统的并发能力,因此适用于需要支持高并发访问的场景。
4、数据库事务处理:MyBatis支持事务处理机制,可以对多个操作进行事务管理,因此适用于需要进行数据库事务处理的场景。
5、多数据源操作:MyBatis可以支持多数据源的操作,可以同时连接多个数据库进行操作,因此适用于需要同时操作多个数据库的场景。
综上所述,MyBatis可以广泛应用于各种需要进行数据库访问和ORM操作的场景,特别是在需要高并发、大数据量和复杂操作的场景下更加适用。
2、MyBatis具有哪些优点?
MyBatis具有以下优点:
1、灵活性高:MyBatis提供了丰富的映射语句和灵活的配置,可以满足不同的需求。
2、易于掌握:MyBatis的学习曲线比较平稳,上手比较容易。
3、性能较好:MyBatis通过对SQL语句和结果集的缓存,可以提高系统的性能。
4、可以自由控制SQL:MyBatis支持使用动态SQL来构建复杂的SQL语句,可以自由控制SQL的执行。
5、易于集成:MyBatis可以与Spring等框架进行集成,方便与其他框架一起使用。
总之,MyBatis是一款功能强大、易于使用、性能出色的ORM框架,被广泛应用于各种Java项目中。
3、MyBatis的工作原理以及工作流程是什么?
依旧建议看底层原理MyBatis底层原理小白版本
MyBatis的工作原理可以简单地概括为以下三个步骤:
1、通过SqlSessionFactoryBuilder创建SqlSessionFactory对象;
2、通过SqlSessionFactory对象的openSession方法创建SqlSession对象;
3、通过SqlSession对象操作数据库,包括执行SQL语句、提交事务等。
MyBatis的工作流程如下:
1、加载MyBatis的配置文件,包括数据库连接信息、映射文件的位置等;
2、解析配置文件,创建Configuration对象,用于保存MyBatis的配置信息;
3、创建SqlSessionFactory(线程安全)对象,是用于创建SqlSession对象的工厂;
4、创建SqlSession对象,用于执行SQL语句的,一个SqlSession对象代表一次数据库连接;
5、通过SqlSession对象执行SQL语句,包括查询、插入、更新、删除等操作;
6、提交事务,如果需要的话;
7、关闭SqlSession对象,释放资源。
4、什么是MyBatis的接口绑定?有哪些实现方式?
接口绑定,就是在MyBatis中任意定义接口,然后把接口里面的方法和SQL语句绑定,我们直接调用接口方法就可以,这样比起原来了SqlSession提供的方法我们可以有更加灵活的选择和设置。
接口绑定有两种实现方式
- 通过注解绑定,就是在接口的方法上面加上 @Select、@Update等注解,里面包含Sql语句来绑定;
- 通过xml里面写SQL来绑定, 在这种情况下,要指定xml映射文件里面的namespace必须为接口的全路径名。当Sql语句比较简单时候,用注解绑定, 当SQL语句比较复杂时候,用xml绑定,一般用xml绑定的比较多。
5、当实体类中的属性名和表中的字段名不一样,怎么办?
-
查询sql的时候给查询出来的列起别名: 我们应尽量给列起别名而不是修改对应类的属性名,后者牵扯的太多
<!-- User{ int id; String pwd} --> <select id = "getUser" parameterType="int" resultType="user">select id, password pwd from user where id = #{id} </select>
-
通过来映射字段名和实体类属性名的一一对应的关系。
<select id = "getUser" parameterType="int" resultMap="userMap">select * from user where id = #{id} </select> <resultMap type="user" id="userMap"><!–用result属性来映射非主键字段,property为实体类属性名,column为数据库表中的属性–><result property ="id" column ="id"/><result property="pwd" column="password" /> </reslutMap>
6、在mapper中如何传递多个参数?
1. 顺序传参
public User selectUser(String name, int deptId);
<select id="selectUser" resultMap="UserResultMap">select * from userwhere user_name = #{0} and dept_id = #{1}
</select>
#{}里面的数字代表传入参数的顺序。
这种方法不建议使用,sql层表达不直观,且一旦顺序调整容易出错。
-
@Param注解传参法
public User selectUser(@Param("userName") String name, int @Param("deptId") deptId); <select id="selectUser" resultMap="UserResultMap">select * from userwhere user_name = #{userName} and dept_id = #{deptId} </select> #{}里面的名称对应的是注解@Param括号里面修饰的名称。 这种方法在参数不多的情况还是比较直观的,推荐使用。
-
Map传参法
public User selectUser(Map<String, Object> params); <select id="selectUser" parameterType="java.util.Map" resultMap="UserResultMap">select * from userwhere user_name = #{userName} and dept_id = #{deptId} </select> #{}里面的名称对应的是Map里面的key名称。 这种方法适合传递多个参数,且参数易变能灵活传递的情况。
-
Java Bean传参法
public User selectUser(User user); <select id="selectUser" parameterType="com.jourwon.pojo.User" resultMap="UserResultMap">select * from userwhere user_name = #{userName} and dept_id = #{deptId} </select> #{}里面的名称对应的是User类里面的成员属性。 这种方法直观,需要建一个实体类,扩展不容易,需要加属性,但代码可读性强,业务逻辑处理方便,推荐使用。
7、MyBatis中的#{}和${}有什么区别?
-
#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理。
-
Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?号,调用PreparedStatement的set方法来赋值。
-
Mybatis在处理 ${}时,是原值传入,就是把${}替换成变量的值,相当于JDBC中的Statement编译
-
变量替换后,#{} 对应的变量自动加上单引号 ‘ ’;变量替换后,${} 对应的变量不会加上单引号 ‘ ’
-
#{} 可以有效的防止SQL注入,提高系统安全性;${} 不能防止SQL 注入
-- 假如 有个 id = 5 or 1=1 delete from 表名 where id = #{id} delete from 表名 where id = ${id}-- 执行上面两条sql 第一个会变成这样-> delete from 表名 where id = '5 or 1=1';--执行肯定是失败的 第一个会变成这样-> delete from 表名 where id = 5 or 1=1;--这种情况就是sql注入,如果没有id为5的,那么就会判断 1=1, 这样结果是必然成立的,那么 delete 就会将整个表的数据全都删掉。对于任意一行 where 1=1 都是成立的
-
#{} 的变量替换是在DBMS 中;${} 的变量替换是在 DBMS 外
怎么理解第六点:
#{}
是mybaits 中的一种动态sql的用法,#{}
用于预编译,由DBMS进行处理。
${}
是一种在很多基于文本的配置文件(比如属性文件、XML配置文件等)中常用的变量替换语法。在这种情况下,
${}
用于将变量的值直接替换到SQL语句或者其他配置中。这种替换发生在应用程序加载配置文件的时候,而不是在DBMS中
8、模糊查询like语句该怎么写?
-
'%${question}%'
可能引起SQL注入,不推荐<select id="getStudent2" parameterType="String" resultMap="StudentTeacher">select * from student where name like '%${name}%' </select>
-
"%"#{question}"%"
注意:因为#{…}解析成sql语句时候,会在变量外侧自动加单引号 ’ ',所以这里 % 需要使用双引号" ",不能使用单引号 ’ ’ ,不然会查不到任何结果。<select id="getStudent2" parameterType="String" resultMap="StudentTeacher">select * from student where name like "%"#{name}"%" </select>
-
CONCAT(‘%’,#{question},‘%’) 使用CONCAT()函数,推荐
oracle的concat函数只支持两个参数,但是mysql的concat函数支持好几个,更换数据库就要重新sql
<select id="getStudent2" parameterType="String" resultMap="StudentTeacher">select * from student where name like concat('%',#{name},'%') </select>
-
使用bind标签
bind元素的作用是通过OGNL表达式去自定义一个上下文变量,这样更方便使用。在进行模糊查询时,如果是Mysql数据库,常常会用到的是一个concat,它用%和参数相连。然而在Oracle数据库则没有,Oracle数据库使用||进行连接。这样SQL就需要提供两种形式去实现。但是有了bind元素,就不必使用数据库的语言,而是使用MyBatis的动态SQL实现。
<select id="getStudent2" parameterType="String" resultMap="StudentTeacher"><bind name="pattern" value="'%'+name+'%'"/>select * from student where name like #{pattern} </select>
9、MyBatis的动态SQL有哪些?如何使用动态SQL?
1、IF
<select id="findUserById" parameterType="int" resultType="User">select * from user where 1 = 1<if test="id != null">and id = #{id}</if><if test="username != null">and username = #{username}</if>
</select>
2、Where元素: Where元素用于将多个条件拼接在一起,如果第一个条件为真,则拼接"WHERE"关键字,否则拼接"AND"关键字,二人且若子句的开头为 ‘and’ 或者 ‘or’ 则也会删掉
<select id="findUser" parameterType="User" resultType="User">select * from user<where><!--只有当下面的条件有任何一个返回值的时候才会拼接 where--><if test="id != null">and id = #{id}</if><if test="username != null">and username = #{username}</if></where>
</select>
3、choose (when, otherwise) :Choose元素类似于Java中的switch语句,用于选择一个分支执行。例如:
<select id="findUser" parameterType="User" resultType="User">select * from user<where><choose><when test="id != null">and id = #{id}</when><when test="username != null">and username = #{username}</when><otherwise>and 1 = 1</otherwise></choose></where>
</select>
4、Set: Set元素用于更新操作,通过Set元素可以动态地设置更新语句中的字段。例如:
<update id="updateUser" parameterType="User">update user<set><if test="username != null">username = #{username},</if><if test="password != null">password = #{password},</if></set>where id = #{id}
</update>
10、Mybatis如何执行批量操作
使用 <foreach> 标签
<!--
select * from blog where 1=1 and (id = 1 or id=2 or id=3)
我们现在传递一个万能的map,map中存在一个集合
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">select * from blog<where><foreach collection="ids" item="id" open="and (" separator="or" close=")">id = #{id}</foreach></where>
</select>
11、MyBatis实现一对一(多对一)有几种方式?具体怎么操作的?
第一种,按照结果嵌套查询
这种就简单的理解为 :
我们已经把需要的表并在一起了,我们只需要选择我们需要的属性进行映射就行了。
<select id="getStudent2" resultMap="StudentTeacher2">select s.id sid,s.name sname, t.name tnamefrom student s, teacher twhere s.tid = t.id
</select><resultMap id="StudentTeacher2" type="student"><result property="id" column="sid"/><result property="name" column="name"/><association property="teacher" javaType="teacher"><result property="name" column="tname"/></association>
</resultMap>
<!--
<association property="teacher" javaType="teacher"><result property="name" column="tname"/>
</association>
这种比较简单,<association>用来映射Student类的teacher属性 这个属性的类型也就是 javaType="teacher";<select id="getStudent2">中我们需要的是 teacher的name属性,那么我们只需要映射一下tname就行
<result property="name" column="tname"/>
-->
第二种:按查询进行嵌套处理
这中就简单的理解为子查询
我们先查学生表的所有信息,将查到的tid 给子查询,让子查询找到对应的数据,再把结果返回
<select id="getStudent" resultMap="StudentTeacher">select * from student
<!-- select id,name,tid from student -->
</select><resultMap id="StudentTeacher" type="student"><result property="id" column="id"/><result property="name" column="name"/><association property="teacher" javaType="teacher" select="getTeacher"column="tid"/>
</resultMap>
<!--
<association property="teacher" javaType="teacher" select="getTeacher"column="tid"/>
我们可以这样理解这句话:
我需要映射Student类的teacher属性,这个属性的java类型是Teacher,这个属性的数据从哪里来呢,我们需要调用 getTeacher 这个sql语句去查询,同时要传递给这个sql语句 参数进行查询。这个参数就是我们从 getStudent 查询语句中查出来的 tid
--><select id="getTeacher" resultType="teacher">select * from teacher where id = #{??};
</select>
<!--
我们发现 id = #{??} #{}里面的内容即使改变了,对查询语句的结果是没有任何影响的
我们可以将理解为这样 select * from teacher where id = ?;
我们知道sql中有预编译,也许本质就是下面这样呢
preparedStatement.setInt(1, resuleSet.getInt("tid"));
当然,具体流程是啥我不清楚。只是想让大家明白 #{??} 里面的内用没啥影响,但不能为空,大家可以自己试一下。
-->
12、MyBatis实现一对多有几种方式,怎么操作的?
第一种,按照结果嵌套查询
<select id="getTeacher" resultMap="TeacherStudent">select s.id sid, s.name sname, t.name tname, t.id tidfrom student s,teacher twhere s.tid = t.id and t.id = #{tid}
</select><resultMap id="TeacherStudent" type="Teacher2"><result property="id" column="tid"/><result property="name" column="tname"/><collection property="students" javaType="ArrayList" ofType="Student2"><result property="id" column="sid"/><result property="name" column="sname"/><result property="tid" column="tid"/></collection>
</resultMap>
<!--
只要理解了上面的association,这个也就很好理解了
我们使用<collection> 去映射teacher类的students属性。
students 的 java类型是个集合 , 集合里面存放的数据类型也就是泛型,是 ofType="Student2"
-->
第二种:按照查询进行嵌套
<select id="getTeacherById" resultMap="TeacherStudent">select id ddd, name from teacher where id = #{tid}
</select><resultMap id="TeacherStudent" type="Teacher2"><result property="id" column="ddd"/><result property="name" column="name"/><collection property="students" javaType="ArrayList" ofType="Student2"select="getStudentByTid" column="ddd"/>
</resultMap><select id="getStudentByTid" resultType="student2">select * from student where tid = #{hh}
</select>
<!--
同样, getStudentByTid 中的参数仍旧跟 #{}中的内容没有关系
而且,切记 ! column一定是跟我们从数据库中查出来的列名保持一致
-->
13、通常一个Xml映射文件,都会写一个Dao接口与之对应, 请问,这个Dao接口的工作原理是什么?Dao接口里的方法, 参数不同时,方法能重载吗?
依旧建议看一下源码
Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:
com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个、、、标签,都会被解析为一个MappedStatement对象。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
另一种有争议的答案:
mybatis层面可以实现有条件的重载,但xml配置文件中的id是唯一不可重复的,所以对于重载的多个(同名)方法,都将指向同一个MapperStatement,但有潜在的异常风险,一般不建议使用
public Data getOne()
public Data getOne(@Parme("id") long id)
<select id="getOne" resultType="xxx.xxx.Data">SELECT * FROM data_table<if test="id != null">WHERE id = #{id}</if>
</select>
<!--
同时满足以下条件可以实现重载
a. 只有一个无参方法和一个有参方法
b. 有多个有参方法时,参数的数量需要相同,且使用相同的@Param值
-->
14、Mybatis是如何进行分页的?
MyBatis的分页方式有五种:基于关键字的分页、基于MyBatis物理分页插件的分页、基于MyBatis逻辑分页插件的分页、基于数据库的分页、基于应用程序的分页。
1、基于limit语句的分页
<select id="getStudent" parameterType="map" resultMap="StudentTeacher">select * from student limit #{offset},#{count};
</select>
2、基于RowBounds:RowBounds是将所有符合条件的数据全都查询到内存中,然后在内存中对数据进行分页,若数据量大,千万别使用RowBounds
mappep.xml里面正常配置,不用对rowBounds任何操作。mybatis的拦截器自动操作rowBounds进行分页。
XML:
<select id="getUserByRowBounds" resultType="student2" >select * from student
</select>
接口:
List<Student2> getUserByRowBounds(RowBounds rowBounds);
使用:
RowBounds rowBounds = new RowBounds(0,2);
List<Student2> userList = mapper.getUserByRowBounds(rowBounds);
3、基于插件PageHelper(其实自定义插件也行)
导入相应依赖(注意版本匹配问题)
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.2.0</version>
</dependency>
配置文件(注意依赖的版本)
<plugins><plugin interceptor="com.github.pagehelper.PageInterceptor">
<!-- <property name="dialect" value="mysql"/>--></plugin>
</plugins>
XML:
<select id="getUserByPageHelper" resultType="student2" >select * from student
</select>
底层:
List<Student2> getUserByPageHelper();
使用:
int pageNo = 1;//第一页
int pageSize = 2;//每页两条数据
PageHelper.startPage(pageNo,pageSize);//注意,只会匹配最近的一条sql语句,每次使用,都要重新声明
List<Student2> userList = mapper.getUserByPageHelper();
15、MyBatis插件原理以及自定义插件
MyBatis的插件机制是一种扩展机制,可以在MyBatis执行SQL语句的各个阶段中插入自定义的逻辑,用于扩展或修改MyBatis的功能。
MyBatis的插件机制主要包括以下几个接口:
Interceptor:Interceptor是MyBatis插件的核心接口,所有的插件都要实现该接口,Interceptor中定义了四个方法,分别是intercept、plugin、setProperties和getProperties。
Executor:Executor是MyBatis的执行器,用于执行SQL语句。
MyBatis提供了三种执行器:SimpleExecutor、ReuseExecutor和BatchExecutor,Executor中定义了一些方法,如query、update等,可以被Interceptor拦截。
ParameterHandler:ParameterHandler用于处理JDBC ParameterStatement的参数,同样可以被Interceptor拦截。
ResultSetHandler:ResultSetHandler用于处理JDBC ResultSet的接口,同样可以被Interceptor拦截。
StatementHandler:StatementHandler是用于处理JDBC Statement的接口,同样可以被Interceptor拦截。
编写MyBatis插件的步骤如下:
1、实现Interceptor接口,并实现intercept方法,该方法中可以插入自定义的逻辑。
2、实现plugin方法,该方法用于返回一个代理对象,该代理对象包含了原始对象和Interceptor对象的逻辑,用于拦截原始对象的方法调用。
3、在mybatis-config.xml中配置插件,将Interceptor的实现类添加到plugins节点中。
下面是一个简单的插件实现示例:
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MyPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 在执行update方法前,输出日志System.out.println("Before executing update method.");Object result = invocation.proceed();// 在执行update方法后,输出日志System.out.println("After executing update method.");return result;}@Overridepublic Object plugin(Object target) {// 生成代理对象return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 设置插件属性}}
在上面的示例中,我们定义了一个MyPlugin类,实现了Interceptor接口,重写了intercept、plugin和setProperties方法。
注解@Intercepts用于标记拦截的对象和方法,@Signature用于标记拦截的方法参数类型。
intercept方法中,我们可以插入自定义的逻辑,例如在执行update方法前后输出日志。
plugin方法中,我们生成了一个代理对象,并将该代理对象返回。
setProperties方法中,我们可以设置插件的属性。
在完成插件的编写后,我们需要在mybatis-config.xml文件中配置插件,
例如:
<plugins><plugin interceptor="com.example.MyPlugin"><property name="property1" value="value1"/><property name="property2" value="value2"/></plugin>
</plugins>
在上面的配置中,我们将MyPlugin类作为插件的拦截器,并通过标签设置了插件的属性。
总之,MyBatis的插件机制是一种非常灵活的扩展机制,可以通过自定义的插件实现一些自己的功能,例如日志记录、缓存、分页等。
16、MyBatis中如何处理延迟加载?
MyBatis中的延迟加载可以通过两种方式来实现:基于动态代理的延迟加载和基于MyBatis自带的延迟加载机制。
基于动态代理的延迟加载
基于动态代理的延迟加载是MyBatis默认的延迟加载方式。
当查询主对象时,MyBatis只会查询主对象,而不会查询关联对象。
当需要使用关联对象时,MyBatis会通过动态代理的方式生成代理对象,再通过代理对象加载关联对象。
需要使用延迟加载功能时,只需要在Mapper.xml文件中使用或标签指定关联对象即可。
例如:
<!-- 延迟加载一对一关系的关联对象 -->
<association property="author" column="author_id" select="getAuthorById" fetchType="lazy"/><!-- 延迟加载一对多关系的关联对象 -->
<collection property="posts" column="id" select="getPostsByBlogId" fetchType="lazy"/>
基于MyBatis自带的延迟加载机制
基于MyBatis自带的延迟加载机制是指使用MyBatis提供的专门负责延迟加载的组件进行延迟加载。
该组件需要在MyBatis的配置文件中进行配置。
使用该组件时,需要在查询语句中使用ResultMap来指定关联对象,以便在查询时进行关联对象的加载。
例如:
<!-- 配置MyBatis自带的延迟加载机制 -->
<settings><setting name="lazyLoadingEnabled" value="true"/><setting name="aggressiveLazyLoading" value="false"/>
</settings>
<!-- 延迟加载一对一关系的关联对象 -->
<resultMap id="blogResult" type="Blog"><id property="id" column="id"/><result property="title" column="title"/><association property="author" column="author_id" select="getAuthorById" fetchType="lazy"/>
</resultMap><!-- 延迟加载一对多关系的关联对象 -->
<resultMap id="blogResult" type="Blog"><id property="id" column="id"/><result property="title" column="title"/><collection property="posts" column="id" select="getPostsByBlogId" fetchType="lazy"/>
</resultMap>
需要注意的是,基于动态代理的延迟加载方式只支持单个对象的延迟加载,即只能延迟加载一对一关系的关联对象;
而基于MyBatis自带的延迟加载机制则支持一对多关系的关联对象的延迟加载。因此,在使用延迟加载时需要根据具体的场景进行选择。
17、Mybatis都有哪些Executor执行器?它们之间的区别是什么?
Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
18、MyBatis缓存机制
MyBatis的缓存机制是指在执行SQL语句时,将查询结果缓存起来,下次执行相同的SQL语句时,直接从缓存中获取结果,从而提高查询效率。MyBatis的缓存机制分为一级缓存和二级缓存两种。查询顺序为:先查二级缓存,再查一级缓存,最后去数据库
1、一级缓存
一级缓存是指MyBatis的SqlSession级别的缓存,即在同一个SqlSession中执行相同的SQL语句,第二次查询时会直接从缓存中获取结果。
一级缓存的默认开启是通过SqlSessionFactory的默认值配置的,可以通过在mybatis-config.xml文件中的标签中配置开启或关闭,
一级缓存的缓存范围为SqlSession级别,即同一个SqlSession中的所有操作都共享同一个缓存。
一级缓存的缓存失效情况包括以下几种:
(1) SqlSession关闭;
(2) 执行了增删改操作;
(3) 执行了清空缓存操作;
(4) 在SqlSession中显式地调用了clearCache方法。
2、二级缓存
所有的数据都会先放在一级缓存中,只有当会话提交或关闭的时候,才会提交到二级缓存
二级缓存是指MyBatis的Mapper级别的缓存,即在多个SqlSession中执行相同的SQL语句,第二次查询时会直接从缓存中获取结果。
二级缓存的默认开启是通过Mapper的缓存配置实现的,可以通过在Mapper.xml文件中的标签中配置开启或关闭,
例如:
<setting name="cacheEnabled" value="true"/>
二级缓存的缓存范围为Mapper级别,即同一个Mapper的所有SqlSession共享同一个缓存。
二级缓存的缓存失效情况包括以下几种:
(1) 执行了增删改操作;
(2) 执行了清空缓存操作;
(3) 在Mapper.xml文件中的标签中配置了flushInterval属性,表示缓存刷新的时间间隔;
(4) 在Mapper.xml文件中的标签中配置了size属性,表示缓存的最大容量,当缓存的数量超过最大容量时,会触发缓存的清空操作;
(5) 在SqlSession中显式地调用了clearCache方法。
相关文章:

MyBatis面经
MyBatis常见面试题 !!本文主要是博主总结看着玩的,不具有很高的参考价值,慎重 1、MyBatis是什么?MyBatis工作原理?MyBatis的使用场景有哪些? MyBatis是一款优秀的持久层框架,它是…...

SpringBoot基础(六)-- 辅助功能之一 -- 内嵌tomcat
目录 1. 内嵌Tomcat定义位置 2. 内嵌Tomcat运行原理 3. 更换内嵌Tomcat 在前面,我们做的SpringBoot入门案例(SpringBoot基础(一)-- 使用idea(2022版)创建一个Springboot项目(联网开发))勾选了Spirng-web的功能&#...

K8s:部署 CNI 网络组件+k8s 多master集群部署+负载均衡及Dashboard k8s仪表盘图像化展示管理
目录 1 部署 CNI 网络组件 1.1 部署 flannel 1.2 部署 Calico 1.3 部署 CoreDNS 2 负载均衡部署 3 部署 Dashboard 1 部署 CNI 网络组件 1.1 部署 flannel K8S 中 Pod 网络通信: ●Pod 内容器与容器之间的通信 在同一个 Pod 内的容器(Pod 内的容…...

「直播回放」使用 PLC + OPC + TDengine,快速搭建烟草生产监测系统
在烟草工业场景里,多数设备的自动控制都是通过 PLC 可编程逻辑控制器来实现的,PLC 再将采集的数据汇聚至 OPC 服务器。传统的 PI System、实时数据库、组态软件等与 OPC 相连,提供分析、可视化、报警等功能,这类系统存在一些问题&…...

私域流量搭建与运营,技巧全攻略!
2023年是比拼运营深度和服务效率的一年,用户对于体验的期望值将持续增长,企业需提供无缝的客户体验,以推动增长、保障收入、确保客户忠诚度。在疫情新常态下,企业已构建起APP、小程序等一系列线上触点矩阵,而各个触点之…...

AWS SAP-C02教程0--课程概述
SAP是亚马逊云的解决方案架构师专业级认证,关于本课程,我会简述已下3点: 在本课程中按照自己的分类讲述考试相关的AWS产品,特别会注明每个产品在考试中可能出现的考点会对一些解决方案做对比,通过一些对比给出不同场景…...

RFC使用与WebService
RFC连接 CSDN RFC中引用类型组 http://t.csdnimg.cn/wQWAYhttp://t.csdnimg.cn/wQWAY 远程目标系统维护SM59 这里的类型指的是目标系统的系统类型(目标系统即rfc函数存在的系统). 类型2(R/2连接),只需给出主机名,所有通信信息…...

打造全球化电商平台,多语言商城系统助您开拓海外市场
全球化进程的加速,越来越多的企业开始将目光投向海外市场。然而,语言和文化差异成为了企业面临的一大挑战。为了帮助企业顺利拓展海外业务,多语言商城系统应运而生。作为一种功能强大的电子商务平台,多语言商城系统具备以下关键功…...

【滑动窗口】篮里到底能装 “几个水果” 呢?
Problem: 904. 水果成篮 文章目录 题目分析算法原理分析暴力枚举 哈希表滑动窗口优化数组再度优化 复杂度Code 题目分析 首先我们来分析一下本题的思路 首先我们通过题目的描述来理解一下其要表达的含义,题目给到我们一个fruit数组,里面存放的是每棵树上…...

newstarctf2022week2
Word-For-You(2 Gen) 和week1 的界面一样不过当时我写题的时候出了个小插曲 连接 MySQL 失败: Access denied for user rootlocalhost 这句话印在了背景,后来再进就没了,我猜测是报错注入 想办法传参 可以看到一个name2,试着传参 发现有回显三个字段…...

集群调度-01
目录 1、调度约束 2、Pod 是 Kubernetes 的基础单元,Pod 启动典型创建过程如下 2.1 工作机制 **** 2.2 调度过程 *** 2.3 Predicate 有一系列的常见的算法可以使用: ** 2.4 指定调度节点 1、调度约束 Kubernetes 是通过 List-Watch **…...

【软件工程】金管局计算机岗位——软件测试的分类(⭐⭐⭐⭐)
软件工程 软件测试的分类从是否关心软件内部结构和具体实现的角度划(⭐⭐⭐⭐)从是否执行代码角度划分(⭐⭐)从软件开发的过程按阶段划分(⭐⭐⭐⭐) 软件测试的分类 考点导读: 软件测试是软件工…...

Halcon WPF 开发学习笔记(1):Hello World小程序
文章目录 文章专栏视频链接Hello World训练图片训练目的 开始训练图像预处理导入图像三通道处理调用算子通道选取 滤波什么是好的滤波 增加对比度 区域选取阈值处理算子参数选择运行结果(红色为选择区域) 区域分割运行结果 特征筛选参数代码第二次,面积筛选 画选中十…...

pix2tex - LaTeX OCR 安装使用记录
系列文章目录 文章目录 系列文章目录前言一、安装二、使用三、少侠请留步,点赞、收藏、关注 前言 项目地址:这儿 一、安装 版本要求 Python: 3.7 PyTorch: >1.7.1 安装:pip install "pix2tex[gui]" 注意:Pyside6…...

前端框架Vue学习 ——(四)Axios
文章目录 Axios 介绍Axios 入门Vue项目中使用 Axios Axios 介绍 介绍: Axios 对原生的 Ajax 进行了封装,简化书写,快速开发。(异步请求) 官网: https://www.axios-http.cn/ 官网介绍:Axios 是一个基于 promise 网络请…...

将json数据导入到ES集群——解决方案对比填坑日记
需求 将写好的json数据。导入到es集群 数据说明 文件JSON数据,一行一个JSON。 {"id":"d2716ae8fba4e026c4bd9445c3f49e2c","lang":"zh","title":"吉美旅馆","content":"吉美..."}…...

C语言----------#pragma预处理分析
一、#pragma预处理分析 1、#pragma是编译器指示字,用于指示编译器完成一些特定的动作; 2、#pragma所定义的很多指示字是编译器和操作系统特有的; 3、#pragma在不同的编译器间是不可移植的: 预处理器将忽略它不认识的#pragma指…...

数据库中的时间django转换成None
原因 数据库中使用的是datetime[64] 的格式。精确的毫秒了。django默认的使用的是datetime.datetime.fromisoformat转换的。转换不了 使用原生查找 for raw in StockNominate.objects.raw("select id,code,strftime(%Y-%m-%d,date) as date from table_name; "):pr…...

八种流行的网络协议
1、HTTP(超文本传输协议),HTTP 是一种用于获取 HTML 文档等资源的协议。它是 Web 上任何数据交换的基础,是一种客户端 - 服务器协议。 2、HTTP/3,HTTP/3 是 HTTP 的下一个重大修订版。它运行在 QUIC 上,QU…...

Qwt QwtKnob绘制旋钮
1.简介 QwtKnob是Qwt库中的一个类,用于绘制一个旋钮样式的仪表盘。它继承QwtAbstractSlider类,提供了一些额外的功能和样式,用于旋转和选择值。 以下是类继承关系: 2.常用方法 旋钮(Knob)相关的属性和方法…...

docker部署elk
目录 前言 一、创建程序工作路径 二、创建私有网络 三、部署elasticsearch 1.先搜速后下载 2.创建一个基础的容器(此步骤是为了拷贝容器里的文件) 3.拷贝文件到宿主机 3.1进入容器 3.2拷贝并授权 3.3删除基础容器 4.创建容器 5.访问9200测试 …...

护网蓝队初级面试题摘录(下)
小王学习录 1.设备误报如何处理?2.讲一下TOP10都有哪些3.SQL注入的原理和漏洞产生的原因?4.SQL注入的类型盲注类型: 5.简单讲一下防范SQL注入的方法和原理6.SQL注入有哪些绕过姿势?7.SQL注入攻击有哪些危害?6.XSS&…...

通过51单片机控制SG90舵机按角度正反转转动
一、前言 本文介绍如何通过51单片机控制SG90舵机实现角度的正反转转动。SG90舵机是一种常用的微型舵机,具有体积小、重量轻、结构简单等特点,被广泛应用于机器人、遥控模型和各种自动控制系统中。 使用51单片机(STC89C52)作为控…...

uniapp写一个计算器用于记账(微信小程序,APP)
提要:自己用uniapp写了一个记账小程序(目前是小程序),写到计算器部分,在网上找了别人写的计算器,大多数逻辑都是最简单的,都不能满足一个记账计算器的基本逻辑。与其在网上找来找去,…...

前端的几种网络请求方式
网络请求 node编写接口 这里用到的几个包的作用 express:基于 Node.js 平台,快速、开放、极简的 Web 开发框架,官网:https://www.expressjs.com.cn/cors:用来解决跨域问题body-parser:可以通过 req.body…...

Kubernetes技术与架构-存储 4
如上所示,Kubernetes集群支持动态申请存储资源,即集群管理员可以按照实际的需求动态地申请存储资源,集群管理员需要事先定义一个或者多个StorageClass存储类型的资源,Pod中的容器实例直接引用事先定义的StorageClass存储类型的资源…...

jbase编译与部署的优化
上一篇的演示只是涉及自动编译业务脚本。演示时候工程编译是超级慢的。因为把静态资源放在了Web工程下,每次编译都要拷贝,运行起码是1分钟,不能忍受,为此思考工程结构改解决这个问题,顺带方便开发的发布。运行WebLoade…...

Filter 和 Listener
Filter 表示过滤器。是JavaWeb三大组件(Servlet、Filter、Listener)之一。 过滤器可以把对资源的请求 拦截 下来。浏览器可以访问服务器上所有的资源,而在访问到这些资源之前可以使用过滤器拦截下来,也就是说在访问资源之前会先经…...

【正则表达式】中的“\b“
正则表达式是一种用于匹配字符串的强大工具,它可以用于各种编程语言中,可以用来在文本中查找、替换或验证符合某种规则的内容。 正则表达式中有很多特殊的符号,称为元字符,它们有着特殊的含义和作用。其中,“\b” 是其…...

FPGA高端项目:图像采集+GTP+UDP架构,高速接口以太网视频传输,提供2套工程源码加QT上位机源码和技术支持
目录 1、前言免责声明本项目特点 2、相关方案推荐我这里已有的 GT 高速接口解决方案我这里已有的以太网方案 3、设计思路框架设计框图视频源选择OV5640摄像头配置及采集动态彩条视频数据组包GTP 全网最细解读GTP 基本结构GTP 发送和接收处理流程GTP 的参考时钟GTP 发送接口GTP …...