Mybatis 常见知识点问题

1、resultType 和resultMap 的区别?
resultType 是<select>标签的一个属性,适合简单对象(POJO、JDK 自带类型:Integer、String、Map 等),只能自动映射,适合单表简单查询。

<select id="selectAuthor" parameterType="int"  resultType="com.demo.domain.Author">
    select author_id authorId, author_name authorName
    from author where author_id = #{authorId}
</select>

resultMap 是一个可以被引用的标签,适合复杂对象,可指定映射关系,适合关联复合查询。

<resultMap id="BlogWithAuthorResultMap" type="com.demo.domain.associate.BlogAndAuthor">
    <id column="bid" property="bid" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <!-- 联合查询,将author 的属性映射到ResultMap -->
    <association property="author" javaType="com.demo.domain.Author">
        <id column="author_id" property="authorId"/>
        <result column="author_name" property="authorName"/>
    </association>
</resultMap>

2、collection 和association 的区别?
association:一对一

<!-- 另一种联合查询(一对一)的实现,但是这种方式有“N+1”的问题-->
<resultMap id="BlogWithAuthorQueryMap"  type="com.demo.domain.associate.BlogAndAuthor">
    <id column="bid" property="bid" jdbcType="INTEGER"/>
    <result column="name" property="name" jdbcType="VARCHAR"/>
    <association property="author" javaType="com.demo.domain.Author" column="author_id" select="selectAuthor"/> <!-- selectAuthor 定义在下面 -->
</resultMap>

collection:一对多、多对多

<!-- 查询文章带评论的结果(一对多) -->
<resultMap id="BlogWithCommentMap"  type="com.demo.domain.associate.BlogAndComment" extends="BaseResultMap" >
    <collection property="comment" ofType="com.demo.domain.Comment">
        <id column="comment_id" property="commentId" />
        <result column="content" property="content" />
    </collection>
</resultMap>

<!-- 按作者查询文章评论的结果(多对多) -->
<resultMap id="AuthorWithBlogMap"  type="com.demo.domain.associate.AuthorAndBlog" >
    <id column="author_id" property="authorId" jdbcType="INTEGER"/>
    <result column="author_name" property="authorName" jdbcType="VARCHAR"/>
    <collection property="blog"  ofType="com.demo.domain.associate.BlogAndComment">
        <id column="bid" property="bid" />
        <result column="name" property="name" />
        <result column="author_id" property="authorId" />
        <collection property="comment" ofType="com.demo.domain.Comment">
            <id column="comment_id" property="commentId" />
            <result column="content" property="content" />
        </collection>
    </collection>
</resultMap>

3、PrepareStatement 和Statement 的区别?
1、两个都是接口,PrepareStatement 是继承自Statement 的;
2、Statement 处理静态SQL,PreparedStatement 主要用于执行带参数的语句;
3、PreparedStatement 的addBatch()方法一次性发送多个查询给数据库;
4、PS 相似SQL 只编译一次(对语句进行了缓存,相当于一个函数),减少编译次数;
5、PS 可以防止SQL 注入;
6、MyBatis 默认值:PREPARED

5、总结:MyBatis 里面用到了哪些设计模式?

设计模式
工厂SqlSessionFactory、ObjectFactory、MapperProxyFactory
建造者XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuidler
单例模式SqlSessionFactory、Configuration、ErrorContext
代理模式绑定:MapperProxy
延迟加载:ProxyFactory(CGLIB、JAVASSIT)
插件:Plugin
Spring集成 MyBaits:SqlSessionTemplate的内部类SqlSessionInterceptor MyBatis 自带连接池:PooledDataSource管理的 PooledConnection
日志打印:ConnectionLogger、StatementLogger
适配器模式logging模块,对于 Log4j、JDK logging 这些没有直接实现 slf4j 接口的日志组件,需要适配器
装饰模板方法模式BaseExecutor与子类 SimpleExecutor、BatchExecutor、ReuseExecutor
装饰器模式LoggingCache、LruCache 等对 PerpectualCache的装饰CachingExecutor对其他 Executor的装饰
责任链模式InterceptorChain

6、当我们传入RowBounds 做翻页查询的时候,使用limit 物理分页,代替原来的逻辑分页

@Intercepts({@Signature(type = Executor.class,method = “query”,
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
public class MyPageInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println(“将逻辑分页改为物理分页”);
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0]; // MappedStatement
BoundSql boundSql = ms.getBoundSql(args[1]); // Object parameter
RowBounds rb = (RowBounds) args[2]; // RowBounds
// RowBounds为空,无需分页
if (rb == RowBounds.DEFAULT) {
return invocation.proceed();
}

    // 将原 RowBounds 参数设为 RowBounds.DEFAULT,关闭 MyBatis 内置的分页机制
    //args[2] = RowBounds.DEFAULT;


    // 在SQL后加上limit语句
    String sql = boundSql.getSql();
    String limit = String.format("LIMIT %d,%d", rb.getOffset(), rb.getLimit());
    sql = sql + " " + limit;


    // 自定义sqlSource
    SqlSource sqlSource = new StaticSqlSource(ms.getConfiguration(), sql, boundSql.getParameterMappings());


    // 修改原来的sqlSource
    Field field = MappedStatement.class.getDeclaredField("sqlSource");
    field.setAccessible(true);
    field.set(ms, sqlSource);


    // 执行被拦截方法
    return invocation.proceed();
}


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


@Override
public void setProperties(Properties properties) {
}

}

7、在未启用日志组件的情况下,输出执行的SQL,并且统计SQL 的执行时间(先实现查询的拦截)

@Intercepts({ @Signature(type = StatementHandler.class, method = "query", args = { Statement.class, ResultHandler.class}) })
public class SQLInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        long startTime = System.currentTimeMillis();
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        String sql = boundSql.getSql();
        System.out.println("获取到SQL语句:"+sql);


        try {
            return invocation.proceed();
        }finally {
            long endTime = System.currentTimeMillis();
            System.out.println("SQL执行耗时:" + (endTime-startTime) +"ms");
        }


    }


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


    @Override
    public void setProperties(Properties properties) {
        String name = properties.getProperty("name");
        // System.out.println("获取到的参数:"+ name);
    }
}

8、用注解还是用xml 配置?
常用注解:@Insert、@Select、@Update、@Delete、@Param、@Results、@Result
在MyBatis 的工程中,我们有两种配置SQL 的方式。一种是在Mapper.xml 中集中管理,一种是在Mapper 接口上,用注解方式配置SQL。很多同学在工作中可能两种方式都用过。那到底什么时候用XML 的方式,什么时候用注解的方式呢?
注解的缺点是SQL 无法集中管理,复杂的SQL 很难配置。所以建议在业务复杂的项目中只使用XML 配置的形式,业务简单的项目中可以使用注解和XML 混用的形式。

9、Mapper 接口无法注入或Invalid bound statement (not found)
我们在使用MyBatis 的时候可能会遇到Mapper 接口无法注入,或者mapper statement id 跟Mapper 接口方法无法绑定的情况。基于绑定的要求或者说规范,我们
可以从这些地方去检查一下:
1、扫描配置,xml 文件和Mapper 接口有没有被扫描到
2、namespace 的值是否和接口全类名一致
3、检查对应的sql 语句ID 是否存在

10、怎么获取插入的最新自动生成的ID
在MySQL 的插入数据使用自增ID 这种场景,有的时候我们需要获得最新的自增ID,比如获取最新的用户ID。常见的做法是执行一次查询,max 或者order by 倒序获取最大的ID(低效、存在并发问题)。在MyBatis 里面还有一种更简单的方式:insert 成功之后,mybatis 会将插入的值自动绑定到插入的对象的Id 属性中,我们用getId 就能取到最新的ID。

<insert id="insert" parameterType="com.demo.domain.Blog">
    insert into blog (bid, name, author_id)
    values (#{bid,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR},  #{author,jdbcType=CHAR})
</insert>
blogService.addBlog(blog);
System.out.println(blog.getBid());

11、XML 中怎么使用特殊符号,比如小于&
1、转义< &lt;(大于可以直接写)
2、使用<![CDATA[ ]]>——当XML 遇到这种格式就会把[]里面的内容原样输出,不进行解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值