Mybatis面试题

一、Mybatis面试题

1. MyBatis是什么?它与其他ORM框架的区别是什么?

  • MyBatis是一种基于Java语言的持久层框架,用于将Java对象与关系型数据库之间进行映射(ORM)。它的主要目的是简化Java开发人员与数据库之间的交互。

  • 与其他ORM框架相比,MyBatis具有以下几个区别:

  • 1.SQL控制: MyBatis不会强制开发人员使用任何特定的SQL查询语句,而是允许开发人员自由编写SQL语句,并且提供了一些工具和标签来辅助编写和管理SQL语句。

  • 2.映射控制: MyBatis提供了一种灵活的机制来将Java对象映射到数据库表中,开发人员可以通过XML或注解来定义对象与表之间的映射关系。

  • 3.调用存储过程: MyBatis允许开发人员调用存储过程来执行数据库操作。

  • 4.缓存控制: MyBatis提供了缓存机制,可以减少对数据库的访问次数,提高性能。

  • 5.易于集成: MyBatis可以轻松地与其他Java框架集成,例如Spring和Spring Boot等。

  • 总之,MyBatis在灵活性和可定制性方面具有优势,开发人员可以自由编写和管理SQL查询语句和对象映射关系,使其更加适合特定的项目需求。

2. MyBatis的工作原理(流程)是什么?

  • 1.创建SqlSessionFactory

    • 在使用MyBatis之前,我们需要创建一个SqlSessionFactory对象,用于管理数据库连接和SQL语句的执行。SqlSessionFactory是线程安全的,通常只需要创建一个实例。创建SqlSessionFactory的方式有多种,下面是其中一种基于XML配置文件的方式。

    • 首先,我们需要创建一个名为mybatis-config.xml的XML配置文件,用于配置SqlSessionFactory的相关参数,如数据库连接信息、插件、缓存等。

    • 接下来,我们可以使用SqlSessionFactoryBuilder类来创建SqlSessionFactory对象,并将上述配置文件作为参数传递给它的build()方法。     

  • 2.创建SqlSession

    • 在执行数据库操作时,我们需要创建一个SqlSession对象。SqlSession是非线程安全的,每个线程都应该创建自己的SqlSession实例。SqlSession包含了执行SQL语句所需的所有方法,如selectOne、selectList、insert、update、delete等。

    • 我们可以使用SqlSessionFactory的openSession()方法来创建SqlSession对象。

    • 这个方法返回一个新的SqlSession实例,它通过JDBC连接到数据库。我们可以通过SqlSession实例来执行任何数据库操作

  • 3.执行SQL语句

    • MyBatis中的SQL语句通常是以XML文件的形式存储的,每个XML文件都对应一个Mapper接口,这个接口中定义了对应的SQL语句。

    • 例如,我们有一个名为UserMapper的Mapper接口,其中定义了一个查询用户信息的方法getUserById。

    • 这个方法对应的SQL语句存储在一个名为UserMapper.xml的XML文件中。
    • 在这个XML文件中,我们定义了一个名为getUserById的select语句,它使用了一个参数id,并返回一个com.example.User类型的结果。

    • 现在,我们可以通过SqlSession实例来执行这个SQL语句。

    • 在这个示例中,我们首先使用getMapper()方法来获取UserMapper接口的一个代理对象,然后调用getUserById()方法来执行查询操作,并将结果存储在一个名为user的User对象中。最后,我们将这个对象打印出来。

  • 4.提交事务并关闭SqlSession

    • 在执行完所有数据库操作之后,我们需要提交事务并关闭SqlSession。

    • 我们首先调用commit()方法来提交事务,然后调用close()方法来关闭SqlSession。如果在操作过程中发生了异常,则可以调用rollback()方法来回滚事务。

3.Mybatis连接数据库的步骤

  • 加载数据库驱动

注意:驱动的加载在JDBC4之后可以无需显示声明(可以不写),因为在META-INF下services包中有个配置文件java.sql.Driver。在获取连接之前,DriverManager会自动寻找。

  • 获取数据库的连接

getConnection()中的参数:url,user,password当然这个方法也有重载的其他方法,参数和这个相似。

  • 获取用于执行sql命令的执行对象

Statement一般用于执行静态sql语句。动态传入的参数时,使用Statement会有sql注入的风险,而PreparedStatement有预处理sql语句的功能可以避免sql注入的风险。

  • 执行具体操作

执行:Statement中有execute()的方法,返回值是boolean类型,true表示执行查询操作,false表示执行更新操作(增删改)

  • 处理结果

主要是对于结果集的处理,ResultSet 中有next()方法,它相当于一个游标,它的指向是下一条数据,返回值是boolean类型,能判断有没有一条数据,而ResultSet 中的getXxx是用来获取每一条数据中的具体内容比如:username、password等。

  • 回收资源

如果有结果集才能关闭结果集ResultSet,没有就不用写这一句。关闭资源类似递归和栈,就是开启顺序和关闭顺序相反。关闭资源时最好用try..finally...语句用try..catch....finally...语句。

4. MyBatis的核心组件有哪些?

  • 1.SqlSessionFactoryBuilder: 用于创建SqlSessionFactory的构建器。
  • 2.SqlSessionFactory: 用于创建SqlSession的工厂类。
  • 3.SqlSession: 用于执行数据库操作的会话对象。
  • 4.Executor: 用于执行SQL语句的接口,它有三个实现类:SimpleExecutor、ReuseExecutor和BatchExecutor。
  • 5.StatementHandler: 用于处理JDBC Statement的接口,它有两个实现类:PreparedStatementHandler和CallableStatementHandler。
  • 6.ParameterHandler: 用于处理SQL语句中的参数的接口,它有两个实现类:DefaultParameterHandler和MapParameterHandler。
  • 7.ResultSetHandler: 用于处理JDBC ResultSet的接口,它有多个实现类,如BeanListHandler、BeanHandler等。
  • 8.TypeHandler: 用于处理Java对象和JDBC类型之间的转换的接口,它有多个实现类,如StringTypeHandler、IntegerTypeHandler等。
  • 9.MappedStatement: 表示一个映射的SQL语句以及一些附加信息,比如输入参数和输出结果类型等。
  • 10.MapperRegistry: 用于管理所有Mapper接口的注册中心。
  • 11.Configuration: MyBatis的全局配置类,包括数据源、类型处理器、Mapper映射等。
  • 12.MapperProxyFactory: Mapper接口的代理工厂类,用于生成Mapper接口的代理对象。
  • 这些组件协同工作,完成了从读取XML配置文件到执行SQL语句的整个过程。其中,SqlSession是最常用的组件,它封装了一次数据库操作的所有步骤,并提供了一个简单的API供用户使用。其他组件则是MyBatis内部使用的,它们通过组合和委托的方式完成具体的功能。

5. MyBatis中的一级缓存和二级缓存是什么?有什么区别?

  • MyBatis中的一级缓存和二级缓存都是用于提高查询性能的缓存机制,但它们的作用范围、生命周期和缓存数据的方式有所不同。

  • 一级缓存(本地缓存) 是SqlSession级别的缓存,也就是说,使用同一个 sqlSession 查询同一 条sql 时,直接从缓存数据中取,不需要操作数据库。一级缓存默认是开启的,如果要关闭或清空一级缓存,可以在SqlSession执行相关操作时使用flushCache属性。

  • 一级缓存失效情况

    • 同一个 sqlSession 条件不同

    • 同一个 sqlSession 执行期间执行了增加、删除、修改操作

    • 手动清缓存

  • 二级缓存(全局缓存) 是Mapper级别的缓存,它的作用范围是多个SqlSession共享的,即同一个Mapper接口下的所有SqlSession都可以共享这个缓存。二级缓存默认是关闭的,需要手动在Mapper配置文件中进行开启。二级缓存可以在多个SqlSession之间共享缓存数据,但需要注意缓存数据的有效期,缓存数据在多个SqlSession之间共享,因此需要考虑缓存数据的一致性和并发性。

  • 二级缓存失效情况

    • 没有给类实现序列化接口(其实原理就是把对象信息写进一个序列化文件中,通过对象流)

    • 两次查询之间添加了任何的增删改操作

    • insert、update 和 delete 语句会刷新缓存

  • 一级缓存和二级缓存的区别:

    • 1.作用范围不同: 一级缓存作用于SqlSession级别,二级缓存作用于Mapper级别。

    • 2.生命周期不同: 一级缓存的生命周期与SqlSession相同,即在SqlSession关闭时失效;二级缓存的生命周期比较长,缓存数据会一直存在,直到Mapper的相关语句发生变化或手动清空缓存。

    • 3.缓存数据的方式不同: 一级缓存使用HashMap存储缓存数据,缓存的key是SQL语句和参数的组合,value是查询结果;二级缓存则是将缓存数据放在一个单独的缓存区域中,可以使用多种缓存方式,如Ehcache、Redis等。

    • 4.多线程并发访问时 ,二级缓存比一级缓存更安全,可以避免出现脏数据和并发冲突的情况。

  • 缓存查询顺序

    • 先查二级缓存,范围比较大,可能有其它会话缓存的信息

    • 再查一级缓存

    • 再查数据库

    • 如果sqlSession关闭会把一级缓存信息缓存到二级缓存

6.二级缓存清除策略

  • LRU – (Least Recently Used)最近最少使用:移除最长时间不被使用的对象。默认使用方式
  • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
  • SOFT – 软引用:基于垃圾回收器状态和软引用规则移除对象。
  • WEAK – 弱引用:更积极地基于垃圾收集器状态和弱引用规则移除对象。

7.  MyBatis中如何处理动态SQL?

  • MyBatis中处理动态SQL的方式是使用OGNL表达式和标签来动态生成SQL语句,其中OGNL表达式用于判断条件是否成立,标签用于生成对应的SQL片段。

  • 以下是MyBatis中常用的动态SQL标签:

  • 1.if标签: 用于条件判断,如果条件成立则生成对应的SQL片段,否则忽略该标签内的内容。示例代码如下:


    
  • 2.choose、when、otherwise标签: 用于类似于switch-case语句的条件判断,可以选择匹配的分支进行生成SQL片段。示例代码如下: 

    
  • 3.foreach标签: 用于遍历一个集合,并生成对应的SQL片段。示例代码如下:
    
      update user
      
        
          name=#{user.name},age=#{user.age}
        
      
      where id in
      
        #{user.id}
      
    

上述代码中,foreach标签中的list属性指定了要遍历的集合,item属性指定了遍历时的集合元素名,separator属性指定了生成SQL片段时元素之间的分隔符。

总之,MyBatis提供了多种动态SQL标签和OGNL表达式,可以方便地处理复杂的动态SQL,提高了SQL语句的灵活性和可重用性。

8.MyBatis中如何处理懒加载?

  • MyBatis提供了懒加载(Lazy Loading)功能,可以在需要使用相关数据时才去加载,而不是一次性将所有数据都加载到内存中。这样可以节省内存,并且在数据量较大的情况下能够提高查询效率。

  • 在MyBatis中,懒加载是通过两种方式实现的:一是使用延迟加载(Lazy Loading)技术,二是使用嵌套查询(Nested Query)技术。

  • 1.延迟加载
    延迟加载是指在访问对象的某个属性时,才去加载该属性所对应的数据,而不是在查询主对象时一次性将所有关联对象的数据都加载到内存中。MyBatis中实现延迟加载的方式是使用代理对象,在访问属性时,通过代理对象去加载数据,示例代码如下:

 


    
    public interface UserMapper {
      User getUser(int id);

      // 延迟加载关联的订单信息
      List getOrdersLazy(int userId);
    }

    
    

    

在上述代码中,getUser方法查询User对象时并不会查询该对象关联的订单信息,而是返回一个代理对象。当访问代理对象的getOrders方法时,才会去执行getOrdersLazy方法查询对应的订单信息。

  • 2.嵌套查询

嵌套查询是指在查询主对象时,不仅查询主对象本身的数据,还通过嵌套查询方式查询与主对象关联的数据。示例代码如下:


    
    public interface UserMapper {
      // 查询用户及其关联的订单信息
      User getUserWithOrders(int id);
    }

    
    

    
      
      
      
      
        
        
        
      
    

在上述代码中,getUserWithOrders方法查询User对象时通过嵌套查询方式一次性查询出与该用户关联的所有订单信息,并封装到User对象中的orders属性中。

总之,MyBatis提供了延迟加载和嵌套查询两种方式实现懒加载功能,开发中可以根据业务需求选择合适的方式来优化查询效率。

9. MyBatis中的插件是什么?如何编写插件?

  • MyBatis插件是MyBatis提供的一种机制,可以在MyBatis执行核心流程的过程中,通过拦截器机制对其进行扩展或改进。插件可以拦截MyBatis执行的SQL语句、参数、结果集等信息,对其进行修改或增强。这样,我们就可以通过编写插件来扩展MyBatis的功能,实现自定义的需求。
  • 编写一个MyBatis插件需要实现Interceptor接口,Interceptor接口中定义了三个方法:
public Object intercept(Invocation invocation) throws Throwable; 

public Object plugin(Object target);

public void setProperties(Properties properties);
  • 其中,intercept方法是最为重要的,用于拦截MyBatis的执行过程。它接收一个Invocation对象,代表了MyBatis执行过程中的一个调用点。我们可以在这个调用点之前或之后对执行过程进行修改或增强,也可以在调用点内部进行处理。

  • plugin方法用于包装目标对象,返回一个代理对象。这个代理对象会拦截目标对象的方法调用,并在方法调用前后执行自定义的逻辑。

  • setProperties方法用于在配置插件时,从配置文件中读取插件所需的参数。这些参数可以通过Properties对象传递到插件中,供插件使用。

  • 下面是一个简单的插件实现示例,它可以在执行查询语句前打印出SQL语句及其参数:


    @Intercepts({@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})})
    public class SqlInterceptor implements Interceptor {

        private static final Logger logger = LoggerFactory.getLogger(SqlInterceptor.class);

        @Override
        public Object intercept(Invocation invocation) throws Throwable {
            StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
            BoundSql boundSql = statementHandler.getBoundSql();
            Object[] args = invocation.getArgs();
            logger.info("SQL: " + boundSql.getSql());
            logger.info("Parameters: " + Arrays.toString(args));
            return invocation.proceed();
        }

        @Override
        public Object plugin(Object target) {
            return Plugin.wrap(target, this);
        }

        @Override
        public void setProperties(Properties properties) {
            // do nothing
        }
    }
  • 这个插件可以在MyBatis执行SQL语句前打印出SQL语句及其参数,并返回原始的执行结果。我们可以在MyBatis的配置文件中配置这个插件:

    

  • 通过这个插件,我们就可以在开发和调试过程中方便地查看MyBatis执行的SQL语句及其参数,帮助我们快速定位问题。

10. MyBatis中的事务是如何管理的?

  • 在 MyBatis 中,事务的管理是通过 SqlSession 来完成的。SqlSession 提供了多种方法来管理事务,包括:

    • 1.SqlSession.commit(): 提交事务,将未提交的 SQL 语句一次性提交到数据库中。

    • 2.SqlSession.rollback(): 回滚事务,将未提交的 SQL 语句全部回滚。

    • 3.SqlSession.close(): 关闭 SqlSession,释放资源。

  • MyBatis 支持两种事务管理方式:JDBC 事务和 Spring 事务。

  • JDBC 事务管理

    • JDBC 事务管理是 MyBatis 的默认事务管理方式。在使用 JDBC 事务时,MyBatis 会将事务管理的工作委托给 JDBC,即通过调用 java.sql.Connection 接口的 commit() 和 rollback() 方法来实现事务的提交和回滚。开发者可以使用 SqlSession.getConnection() 方法获取 java.sql.Connection 对象,然后通过该对象来管理事务。

  • Spring 事务管理

    • 除了使用 JDBC 事务,MyBatis 还可以与 Spring 集成,使用 Spring 事务管理。在使用 Spring 事务时,MyBatis 会将事务管理的工作委托给 Spring 的事务管理器,即通过调用 Spring 的 PlatformTransactionManager 接口来实现事务的提交和回滚。

11. MyBatis中的Mapper接口和Mapper映射文件是如何关联的?

  • 在MyBatis中,Mapper接口和Mapper映射文件是通过命名空间(namespace)来关联的。命名空间是Mapper映射文件的唯一标识,Mapper接口与之对应。

  • 举个例子,如果有一个UserMapper接口和一个user.xml映射文件,那么可以在user.xml文件中指定命名空间为UserMapper:



   

  • 这样,MyBatis就知道将UserMapper接口与user.xml映射文件关联起来了。接下来,可以在UserMapper接口中定义与user.xml文件中的语句相对应的方法。例如,如果user.xml中定义了一个查询用户信息的语句:

 


    
    
  • 那么可以在UserMapper接口中定义一个与之对应的方法:

    public interface UserMapper {
      User getUserById(int id);
    }
  • MyBatis会根据UserMapper接口中方法的签名,自动查找user.xml文件中与之相对应的语句,并执行该语句。

  • 需要注意的是,命名空间的名称应该与Mapper接口的全限定名一致,这样MyBatis才能正确地将Mapper接口和Mapper映射文件关联起来。

12. MyBatis中如何处理分页查询?

MyBatis提供了两种方式来处理分页查询:基于数据库的分页和基于应用程序的分页。

12.1基于数据库的分页

  • 基于数据库的分页是通过数据库提供的分页查询语句实现的,通常使用的是类似于MySQL的LIMIT和OFFSET关键字或者Oracle的ROWNUM机制。使用这种方式,需要在SQL语句中添加特定的分页关键字,并通过参数来指定要查询的页数和每页显示的记录数。

  • 例如,使用MySQL的LIMIT和OFFSET关键字,可以在SQL语句中添加如下的分页查询语句:

  SELECT id, username, email FROM users LIMIT #{offset}, #{pageSize}
  • 其中,#{offset}表示偏移量,即从哪一条记录开始查询,#{pageSize}表示每页显示的记录数。这里的偏移量和每页显示的记录数可以通过参数传递进来,例如:
    public interface UserMapper {
      List getUsers(@Param("offset") int offset, @Param("pageSize") int pageSize);
    }
  • 在使用时,可以通过调用selectList方法来查询指定页数的数据:
 List users = sqlSession.selectList("com.example.UserMapper.getUsers", 10, 5);
  • 这里查询第2页数据,每页显示5条记录,偏移量为10。

12.2基于应用程序的分页

  • 基于应用程序的分页是通过查询所有记录,然后在应用程序中根据指定的页数和每页显示的记录数进行分页处理的。使用这种方式,需要查询所有的记录,并将结果集传递给应用程序进行分页处理。

  • 例如,在MyBatis中,可以使用RowBounds对象来实现基于应用程序的分页。RowBounds对象表示结果集中的一段连续记录,通过传递RowBounds对象,可以指定要查询的起始记录和总记录数。

  • 使用RowBounds对象进行分页查询时,需要在Mapper接口方法中添加一个RowBounds类型的参数,例如:

    public interface UserMapper {
      List getUsers(RowBounds rowBounds);
    }
  • 在使用时,可以通过调用selectList方法来查询指定页数的数据:
    RowBounds rowBounds = new RowBounds(10, 5);
    List users = 
      sqlSession.selectList("com.example.UserMapper.getUsers", rowBounds);
  • 这里查询第2页数据,每页显示5条记录,起始记录为第11条。

  • 需要注意的是,基于应用程序的分页在处理大量数据时可能会影响性能,而基于数据库的分页则可以利用数据库的优化机制,提高查询效率。因此,在实际应用中,应根据具体情况选择合适的分页方式。

11. MyBatis中如何处理乐观锁和悲观锁?

11.1乐观锁

  • 乐观锁是一种基于数据版本号的机制。在更新数据时,先查询出数据的版本号,然后更新时将版本号加1。如果版本号没有被其他线程修改,则更新成功,否则更新失败,需要重试。

  • 在 MyBatis 中,可以通过在对应的 Mapper 映射文件中使用 update 标签实现乐观锁的更新。在 SQL 语句中需要使用版本号字段,并且需要使用 set 标签更新版本号字段。

11.2乐观锁实现方式:

  • 取出记录时,获取当前 version
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败

11.3悲观锁

  • 悲观锁是一种基于数据库锁机制的实现方式,当对数据进行操作时先获取锁,确保其他线程不能对数据进行修改。悲观锁一般需要数据库的支持,常见的实现方式有行级锁和表级锁。

  • 在 MyBatis 中,可以使用 for update 语句来实现行级悲观锁的机制。例如,在对应的 Mapper 映射文件中可以使用 select 标签进行查询,然后在 SQL 语句中使用 for update 对查询结果进行加锁。

14. MyBatis中如何执行批量操作?

  • 在 MyBatis 中执行批量操作可以使用 SqlSession 对象提供的批处理方法 batch(),支持批量插入、更新、删除操作。下面介绍具体的实现方式。

  • 首先,定义一个包含多个参数的方法,参数可以是对象、Map 或基本类型。在方法中,调用 SqlSession 对象的 batch() 方法,该方法接受一个 Statement 对象和一个 List 集合作为参数。其中,Statement 对象代表要执行的 SQL 语句,List 集合存储了所有参数,每个元素代表一组参数,它是一个数组或集合类型。

  • 然后,在映射文件中编写 SQL 语句,并使用 foreach 标签循环遍历参数集合,生成多条 SQL 语句,用于执行批量操作。具体步骤如下:

    • 1.定义批量插入方法,该方法接受一个包含多个对象的集合作为参数:
    • 2.在映射文件中编写插入语句,并使用 foreach 标签遍历参数集合:
    • 3.在代码中调用批量插入方法,并将对象集合传入:
  • 需要注意的是,在进行批量操作时,需要保证所有操作语句都是相同的类型(如插入语句、更新语句等),且参数类型一致。另外,批量操作可以有效减少与数据库的交互次数,提高系统性能。

15. MyBatis中如何处理多表查询?

  • MyBatis中处理多表查询需要使用SQL语句进行关联查询,可以使用JOIN、INNER JOIN、LEFT JOIN等关键字实现表的关联。

  • 在Mapper映射文件中,我们可以定义多个ResultMap和多个Select语句,用于处理多表查询结果的映射和查询。

  • 使用MyBatis进行多表查询的步骤:

    • 首先,定义多个实体类,代表不同的表
    • 然后,在Mapper映射文件中,定义多个ResultMap,用于将查询结果映射到对应的实体类上
    • 接着,在Mapper映射文件中,定义多个Select语句,用于进行多表查询操作
    • 在Java代码中,我们可以通过SqlSession对象执行上述SQL语句,实现多表查询操作
  • 注意,如果查询结果涉及多个表的字段,需要使用别名进行区分,以避免字段名冲突。另外,在处理多表查询时,需要注意性能问题,尽量减少不必要的关联查询操作。

16. MyBatis中如何处理枚举类型?

  • MyBatis中处理枚举类型的方式与处理其他Java数据类型类似。通常情况下,MyBatis会将Java枚举类型映射到数据库中的字符串类型。在查询结果中,MyBatis会自动将数据库中的字符串类型转换为Java枚举类型。

17. MyBatis中如何处理日期类型?

  • MyBatis中处理日期类型需要使用Java中的java.util.Date或java.time包下的日期类型,例如LocalDate、LocalDateTime等。在映射文件中,可以使用JDBC的标准类型来映射日期类型,例如使用DATE、TIMESTAMP、TIME等类型。同时,MyBatis也提供了类型处理器(TypeHandler)来处理Java中的日期类型和JDBC的日期类型之间的转换。

18. MyBatis中的TypeHandler是什么?如何自定义TypeHandler?

  • MyBatis的TypeHandler是用来将Java类型与JDBC类型相互转换的组件。当我们向数据库中插入或读取某种Java类型时,MyBatis会自动使用TypeHandler将其转换成对应的JDBC类型,或者在从数据库中读取数据时将JDBC类型转换成对应的Java类型。

  • MyBatis提供了许多内置的TypeHandler,用于处理常见的Java类型,如字符串、日期、枚举等。如果需要处理自定义的Java类型,我们可以通过实现TypeHandler接口来自定义TypeHandler。TypeHandler接口中包含了两个方法:

    • setParameter: 将Java类型转换成对应的JDBC类型,用于向数据库中插入数据时的转换。
    • getResult: 将JDBC类型转换成对应的Java类型,用于从数据库中读取数据时的转换。

 

19. MyBatis中的动态SQL中的标签如何使用?

  • 在 MyBatis 中, 标签是动态 SQL 中非常有用的标签之一,它可以用来迭代集合或数组,并将迭代出来的元素动态地拼接到 SQL 语句中。

  • 标签有以下属性:

    • collection: 指定要遍历的集合或数组的属性名或者表达式,例如:collection=“list”,其中 list 是一个包含多个元素的集合对象。
    • item: 指定迭代变量的名称,例如:item=“item”,表示每次遍历时,当前元素将被赋值给名为 item 的变量。
    • index: 指定迭代索引的名称,例如:index=“index”,表示每次遍历时,当前元素的索引值将被赋值给名为 index 的变量。
    • open: 指定 SQL 语句的前缀,例如:open="("
    • close: 指定 SQL 语句的后缀,例如:close=")"
    • separator: 指定每个元素之间的分隔符,例如:separator=","

20. MyBatis中的延迟加载是如何实现的?

  • MyBatis中的延迟加载是通过代理模式和动态代理技术来实现的。当一个实体对象的某个属性被标记为延迟加载时,MyBatis会在查询该实体对象时,只查询该实体对象的基本信息,而不会查询该属性相关的信息,直到第一次使用该属性时才会触发查询该属性相关的信息。
  • 具体实现过程如下:
    • 1.在MyBatis配置文件中,将延迟加载设置为true:
    • 2.在实体对象的属性中添加@Lob注解来标识该属性为延迟加载属性:
    • 3.当查询该实体对象时,MyBatis会使用动态代理生成一个代理对象,该代理对象只包含基本信息,不包含延迟加载属性的信息。
    • 4.当第一次访问延迟加载属性时,代理对象会触发查询延迟加载属性的信息,并将查询结果缓存起来,以供后续访问使用。
    • 5.当再次访问延迟加载属性时,代理对象会直接从缓存中获取查询结果,避免再次查询数据库。
  • 需要注意的是,如果一个实体对象同时包含多个延迟加载属性,MyBatis会为每个延迟加载属性生成一个代理对象,每个代理对象只包含一个延迟加载属性的信息。同时,延迟加载只对关联表查询有效,对于非关联表查询,MyBatis仍然会查询所有的属性信息。

21. MyBatis中的拦截器机制是如何实现的?

  • MyBatis中的拦截器机制是基于JDK动态代理和责任链模式实现的,可以通过自定义拦截器来拦截SQL语句的执行,以实现自定义功能,例如打印SQL语句、统计SQL执行时间、实现分表等功能。

  • MyBatis中的拦截器机制主要涉及以下两个接口:

    • Interceptor: 拦截器接口,定义了拦截器的基本方法,包括拦截方法、插件方法、设置属性方法等。
    • Plugin: 插件接口,实现MyBatis拦截器功能的核心接口,主要用于创建动态代理对象,并实现对应的拦截器逻辑。
  • 拦截器的实现主要包括以下几个步骤:

    • 1.实现Interceptor接口,实现拦截方法、插件方法和设置属性方法等。

    • 2.在MyBatis配置文件中配置拦截器,并指定需要拦截的方法和拦截器的顺序。
  • 在配置文件中可以配置多个拦截器,多个拦截器的执行顺序按照在配置文件中的顺序执行。

  • 需要注意的是,拦截器只能拦截在MyBatis中定义的接口方法,无法拦截在Mapper XML文件中定义的SQL语句。如果需要拦截XML中的SQL语句,可以使用XML解析器来解析XML文件,找到需要拦截的SQL语句并进行拦截。

 

你可能感兴趣的:(数据库面试题,mybatis,java,数据库)