Skip to content

MyBatis面试题

1. MyBatis的基本概念

问题:什么是MyBatis?

答案

  • MyBatis:基于Java的持久层框架,支持定制化SQL、存储过程以及高级映射。
  • 特点
    • 简化SQL编写
    • 支持动态SQL
    • 支持缓存
    • 支持插件

2. MyBatis的核心组件

问题:MyBatis有哪些核心组件?

答案

  • SqlSessionFactory:创建SqlSession的工厂。
  • SqlSession:执行SQL的会话。
  • Mapper:映射SQL的接口。
  • Configuration:MyBatis的配置对象。
  • Executor:执行SQL的执行器。

3. MyBatis的配置文件

问题:MyBatis的配置文件有哪些?

答案

  • mybatis-config.xml:MyBatis的主配置文件。
  • mapper.xml:映射SQL的配置文件。

示例

xml
<!-- mybatis-config.xml -->
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

4. MyBatis的映射文件

问题:MyBatis的映射文件包含哪些元素?

答案

  • select:查询语句。
  • insert:插入语句。
  • update:更新语句。
  • delete:删除语句。
  • sql:可重用的SQL片段。
  • resultMap:结果映射。
  • parameterMap:参数映射。

示例

xml
<mapper namespace="com.example.mapper.UserMapper">
    <select id="findById" resultType="User">
        SELECT * FROM users WHERE id = #{id}
    </select>
    
    <insert id="insert" parameterType="User">
        INSERT INTO users (name, age) VALUES (#{name}, #{age})
    </insert>
    
    <update id="update" parameterType="User">
        UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}
    </update>
    
    <delete id="delete" parameterType="int">
        DELETE FROM users WHERE id = #{id}
    </delete>
</mapper>

5. MyBatis的动态SQL

问题:MyBatis支持哪些动态SQL?

答案

  • if:条件判断。
  • choose/when/otherwise:多条件选择。
  • trim/where/set:处理SQL拼接。
  • foreach:循环遍历。

示例

xml
<select id="findUsers" resultType="User">
    SELECT * FROM users
    <where>
        <if test="name != null">
            AND name = #{name}
        </if>
        <if test="age != null">
            AND age = #{age}
        </if>
    </where>
</select>

<select id="findUsersByChoose" resultType="User">
    SELECT * FROM users
    <choose>
        <when test="name != null">
            WHERE name = #{name}
        </when>
        <when test="age != null">
            WHERE age = #{age}
        </when>
        <otherwise>
            WHERE 1 = 1
        </otherwise>
    </choose>
</select>

<select id="findUsersByIds" resultType="User">
    SELECT * FROM users WHERE id IN
    <foreach item="id" collection="list" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

6. MyBatis的缓存

问题:MyBatis有哪些缓存?

答案

  • 一级缓存:SqlSession级别的缓存,默认开启。
  • 二级缓存:Mapper级别的缓存,需要配置开启。

示例

xml
<!-- 开启二级缓存 -->
<cache/>

<!-- 使用二级缓存 -->
<select id="findById" resultType="User" useCache="true">
    SELECT * FROM users WHERE id = #{id}
</select>

7. MyBatis的插件

问题:MyBatis的插件有什么作用?

答案

  • 作用
    • 拦截SQL执行。
    • 拦截参数设置。
    • 拦截结果映射。
    • 拦截事务管理。

示例

java
@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MyPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println("Before execute");
        Object result = invocation.proceed();
        System.out.println("After execute");
        return result;
    }
}

8. MyBatis的Mapper接口

问题:如何使用Mapper接口?

答案

java
public interface UserMapper {
    User findById(int id);
    List<User> findAll();
    void insert(User user);
    void update(User user);
    void delete(int id);
}

// 使用
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user = userMapper.findById(1);
sqlSession.close();

9. MyBatis的注解

问题:MyBatis支持哪些注解?

答案

  • @Select:查询语句。
  • @Insert:插入语句。
  • @Update:更新语句。
  • @Delete:删除语句。
  • @SelectProvider:动态查询。
  • @InsertProvider:动态插入。
  • @UpdateProvider:动态更新。
  • @DeleteProvider:动态删除。
  • @Results:结果映射。
  • @Result:结果映射。
  • @Param:参数映射。

示例

java
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(@Param("id") int id);
    
    @Insert("INSERT INTO users (name, age) VALUES (#{name}, #{age})")
    void insert(User user);
    
    @Update("UPDATE users SET name = #{name}, age = #{age} WHERE id = #{id}")
    void update(User user);
    
    @Delete("DELETE FROM users WHERE id = #{id}")
    void delete(int id);
}

10. MyBatis的关联查询

问题:如何实现关联查询?

答案

xml
<!-- 一对一 -->
<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="order" javaType="Order">
        <id property="id" column="order_id"/>
        <result property="orderNo" column="order_no"/>
    </association>
</resultMap>

<!-- 一对多 -->
<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <collection property="orders" ofType="Order">
        <id property="id" column="order_id"/>
        <result property="orderNo" column="order_no"/>
    </collection>
</resultMap>

11. MyBatis的延迟加载

问题:如何实现延迟加载?

答案

xml
<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="aggressiveLazyLoading" value="false"/>
</settings>

<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
    <association property="order" column="order_id" select="findOrderById" fetchType="lazy"/>
</resultMap>

12. MyBatis的类型处理器

问题:如何自定义类型处理器?

答案

java
public class MyTypeHandler implements TypeHandler<String> {
    @Override
    public void setParameter(PreparedStatement ps, int i, String parameter, JdbcType jdbcType) throws SQLException {
        ps.setString(i, parameter);
    }
    
    @Override
    public String getResult(ResultSet rs, String columnName) throws SQLException {
        return rs.getString(columnName);
    }
    
    @Override
    public String getResult(ResultSet rs, int columnIndex) throws SQLException {
        return rs.getString(columnIndex);
    }
    
    @Override
    public String getResult(CallableStatement cs, int columnIndex) throws SQLException {
        return cs.getString(columnIndex);
    }
}

// 配置
<typeHandlers>
    <typeHandler handler="com.example.handler.MyTypeHandler"/>
</typeHandlers>

13. MyBatis的分页

问题:如何实现分页?

答案

xml
<select id="findUsers" resultType="User">
    SELECT * FROM users LIMIT #{offset}, #{limit}
</select>

// 使用
List<User> users = userMapper.findUsers(0, 10);

14. MyBatis的批量操作

问题:如何实现批量操作?

答案

java
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    for (User user : users) {
        userMapper.insert(user);
    }
    sqlSession.commit();
} finally {
    sqlSession.close();
}

15. MyBatis的事务

问题:MyBatis如何管理事务?

答案

java
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    userMapper.insert(user);
    sqlSession.commit();
} catch (Exception e) {
    sqlSession.rollback();
} finally {
    sqlSession.close();
}

16. MyBatis的Spring集成

问题:如何集成Spring?

答案

xml
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.example.mapper"/>
</bean>

17. MyBatis的PageHelper

问题:如何使用PageHelper?

答案

java
// 使用PageHelper
PageHelper.startPage(1, 10);
List<User> users = userMapper.findAll();
PageInfo<User> pageInfo = new PageInfo<>(users);

// 配置
<plugin interceptor="com.github.pagehelper.PageInterceptor">
    <property name="helperDialect" value="mysql"/>
</plugin>

18. MyBatis的逆向工程

问题:如何使用逆向工程?

答案

xml
<generatorConfiguration>
    <context id="context1">
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mydb"
                        userId="root"
                        password="123456"/>
        <javaModelGenerator targetPackage="com.example.model" targetProject="src/main/java"/>
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources"/>
        <javaClientGenerator targetPackage="com.example.mapper" targetProject="src/main/java"/>
        <table tableName="users"/>
    </context>
</generatorConfiguration>

19. MyBatis的#和$的区别

问题:#和$有什么区别?

答案

  • #:预编译,防止SQL注入。
  • $:字符串拼接,不防止SQL注入。

示例

xml
<!-- # -->
<select id="findById" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>

<!-- $ -->
<select id="findByColumn" resultType="User">
    SELECT * FROM users ORDER BY ${column}
</select>

20. MyBatis的resultType和resultMap

问题:resultType和resultMap有什么区别?

答案

  • resultType:自动映射,字段名和属性名一致。
  • resultMap:自定义映射,可以指定字段和属性的对应关系。

示例

xml
<!-- resultType -->
<select id="findById" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>

<!-- resultMap -->
<resultMap id="userResultMap" type="User">
    <id property="id" column="id"/>
    <result property="name" column="name"/>
</resultMap>

<select id="findById" resultMap="userResultMap">
    SELECT * FROM users WHERE id = #{id}
</select>

21. MyBatis的parameterType

问题:parameterType有什么作用?

答案

  • parameterType:指定参数类型。
  • 作用
    • 基本类型:int、String等。
    • 对象类型:User等。
    • Map类型:HashMap等。

示例

xml
<select id="findById" parameterType="int" resultType="User">
    SELECT * FROM users WHERE id = #{id}
</select>

<select id="findByNameAndAge" parameterType="User" resultType="User">
    SELECT * FROM users WHERE name = #{name} AND age = #{age}
</select>

<select id="findByMap" parameterType="map" resultType="User">
    SELECT * FROM users WHERE name = #{name} AND age = #{age}
</select>

22. MyBatis的foreach

问题:foreach有哪些属性?

答案

  • item:集合中的元素。
  • collection:集合的名称。
  • open:开始字符串。
  • close:结束字符串。
  • separator:分隔符。
  • index:索引。

示例

xml
<select id="findUsersByIds" resultType="User">
    SELECT * FROM users WHERE id IN
    <foreach item="id" collection="list" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

23. MyBatis的include

问题:如何使用include?

答案

xml
<sql id="userColumns">
    id, name, age
</sql>

<select id="findById" resultType="User">
    SELECT <include refid="userColumns"/> FROM users WHERE id = #{id}
</select>

24. MyBatis的日志

问题:如何配置日志?

答案

xml
<settings>
    <setting name="logImpl" value="SLF4J"/>
</settings>

25. MyBatis的最佳实践

问题:使用MyBatis的最佳实践有哪些?

答案

  • 使用Mapper接口而不是XML配置。
  • 使用动态SQL简化SQL编写。
  • 使用缓存提高性能。
  • 使用分页提高查询效率。
  • 使用批量操作提高性能。
  • 使用插件扩展功能。
  • 使用类型处理器处理特殊类型。
  • 使用关联查询处理复杂查询。
  • 使用延迟加载提高性能。
  • 使用Spring集成简化配置。