MyBatis 源码分析系列文章导读 (6)

与 Hibernate 相反,MyBatis 需要手动维护 SQL,这会增加使用成本。但同时,使用者可灵活控制 SQL 的行为,这为改动和优化 SQL 提供了可能。所以 MyBatis 适合应用在一些需要快速迭代,需求变化大的项目中,这也就是为什么 MyBatis 在互联网公司中使用的比较广泛的原因。除此之外,MyBatis 还提供了插件机制,使用者可以按需定制插件。这也是 MyBatis 灵活性的一个体现。

分析到这里,大家应该清楚了两个框架之前的区别,以及适用场景。楼主目前在一家汽车相关的互联网公司,公司发展的比较快,项目迭代的也比较快,各种小需求也比较多。所以,相比之下,MyBatis 是一个比较合适的选择。

3.5 本章小结

本节用了大量的篇幅介绍常见持久层框架的用法,并进行了较为详细的分析和对比。看完这些,相信大家对这些框架应该也有了更多的了解。好了,其他的就不多说了,我们继续往下看吧。

4.如何使用 MyBatis

本章,我们一起来看一下 MyBatis 是如何使用的。在上一章,我简单演示了一下 MyBatis 的使用方法。不过,那个太简单了,本章我们来演示一个略为复杂的例子。不过,这个例子复杂度和真实的项目还是有差距,仅做演示使用。

本章包含两节内容,第一节演示单独使用 MyBatis 的过程,第二节演示 MyBatis 是如何和 Spring 进行整合的。那其他的就不多说了,下面开始演示。

4.1 单独使用

本节演示的场景是个人网站的作者和文章之间的关联场景。在一个网站中,一篇文章对应一名作者,一个作者对应多篇文章。下面我们来看一下作者和文章的定义,如下:

public class AuthorDO implements Serializable { private Integer id; private String name; private Integer age; private SexEnum sex; private String email; private List<ArticleDO> articles; // 省略 getter/setter 和 toString } public class ArticleDO implements Serializable { private Integer id; private String title; private ArticleTypeEnum type; private AuthorDO author; private String content; private Date createTime; // 省略 getter/setter 和 toString }

如上,AuthorDO 中包含了对一组 ArticleDO 的引用,这是一对多的关系。ArticleDO 中则包含了一个对 AuthorDO 的引用,这是一对一的关系。除此之外,这里使用了两个常量,一个用于表示性别,另一个用于表示文章类型,它们的定义如下:

public enum SexEnum { MAN, FEMALE, UNKNOWN; } public enum ArticleTypeEnum { JAVA(1), DUBBO(2), SPRING(4), MYBATIS(8); private int code; ArticleTypeEnum(int code) { this.code = code; } public int code() { return code; } public static ArticleTypeEnum find(int code) { for (ArticleTypeEnum at : ArticleTypeEnum.values()) { if (at.code == code) { return at; } } return null; } }

本篇文章使用了两张表,分别用于存储文章和作者信息。这两种表的内容如下:

MyBatis 源码分析系列文章导读

下面来看一下数据库访问层的接口定义,如下:

public interface ArticleDao { ArticleDO findOne(@Param("id") int id); } public interface AuthorDao { AuthorDO findOne(@Param("id") int id); }

与这两个接口对应的 SQL 被配置在了下面的两个映射文件中。我们先来看一下第一个映射文件 AuthorMapper.xml 的内容。

<!-- AuthorMapper.xml --> <mapper namespace="xyz.coolblog.dao.AuthorDao"> <resultMap type="Article"> <id property="id" column="article_id" /> <result property="title" column="title"/> <result property="type" column="type"/> <result property="content" column="content"/> <result property="createTime" column="create_time"/> </resultMap> <resultMap type="Author"> <id property="id" column="id"/> <result property="name" column="name"/> <result property="age" column="age"/> <result property="sex" column="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/> <result property="email" column="email"/> <collection property="articles" ofType="Article" resultMap="articleResult"/> </resultMap> <select resultMap="authorResult"> SELECT au.id, au.name, au.age, au.sex, au.email, ar.id as article_id, ar.title, ar.type, ar.content, ar.create_time FROM author au, article ar WHERE au.id = ar.author_id AND au.id = #{id} </select> </mapper>

注意看上面的<resultMap/>配置,这个标签中包含了一个一对多的配置<collection/>,这个配置引用了一个 id 为articleResult的 。除了要注意一对多的配置,这里还要下面这行配置:

<result property="sex" column="sex" typeHandler="org.apache.ibatis.type.EnumOrdinalTypeHandler"/>

前面说过 AuthorDO 的sex属性是一个枚举,但这个属性在数据表中是以整型值进行存储的。所以向数据表写入或者查询数据时,要进行类型转换。写入时,需要将SexEnum转成int。查询时,则需要把int转成SexEnum。由于这两个是完全不同的类型,不能通过强转进行转换,所以需要使用一个中间类进行转换,这个中间类就是 EnumOrdinalTypeHandler。这个类会按照枚举顺序进行转换,比如在SexEnum中,MAN的顺序是0。存储时,EnumOrdinalTypeHandler 会将MAN替换为0。查询时,又会将0转换为MAN。除了EnumOrdinalTypeHandler,MyBatis 还提供了另一个枚举类型处理器EnumTypeHandler。这个则是按照枚举的字面值进行转换,比如该处理器将枚举MAN和字符串 "MAN" 进行相互转换。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpsyfs.html