Appearance
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集成简化配置。
