前言

之前一段时间写了【Spring源码分析】系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章【MyBatis源码分析】,在【MyBatis源码分析】文章的基础之上,可以继续分析数据库连接池、Spring整合MyBatis源码、Spring事物管理tx等等。

【MyBatis源码分析】整个文章结构相较【Spring源码分析】稍微改一改,后者会在每一部分源码分析的开头列出要分析的源码的实例,比如:

  • 分析Bean流程加载,就会先写Bean的代码示例及xml中配置Bean的示例

  • 分析AOP流程,就会先写AOP的代码及xml中配置AOP的示例

【MyBatis源码分析】系列文章,在本文中会一次性地将所有的代码示例写完,之后就针对这些代码一部分一部分进行分析,探究MyBatis原理。

其实MyBatis代码示例,我在之前的文章里面记得至少写了两遍,完全可以拿之前的文章作为例子,但是这里要再写一遍,就希望分享给网友朋友们一点态度:作为一个程序员,还是应当多去写代码,多去实践,不要认为之前写过的东西就没必要再写一遍,之前懂的内容就没必要再学习一遍,温故知新,写得越多用得越熟练,思考得越多成长越快。

SQL准备

首先还是建表,这里准备一段SQL:

drop table if exists mail;

create table mail (

id               int             auto_increment not null comment '主键id',

create_time datetime      not null  comment '创建时间',

modify_time timestamp   not null  comment '修改时间',

web_id        int             not null  comment '站点id,1表示新浪,2表示QQ,3表示搜狐,4表示火狐',

mail            varchar(50) not null  comment '邮箱名',

use_for       varchar(30)             comment '邮箱用途',

primary key(id),

index use_for(use_for),

unique index web_id_mail(web_id, mail)

)charset=utf8 engine=innodb comment='邮箱表';

很多人可能有不止一个邮箱,新浪的、腾讯的、搜狐的,每个邮箱可能又有不一样的用途,这里就拿邮箱做一个例子。

建立每张表的时候应当注意唯一约束,像这里,一个网站下的邮箱一定是唯一的,不可能在新浪下同时存在两个名为”123@sina.com”的邮箱名,因此对web_id+mail做唯一索引。

建立实体类

建立完毕SQL之后,第二步一定是为表建立在Java层面的实体类,在SQL层面不同的词语使用”_”分割,在Java层面不同的词语则使用驼峰命名法:

对于类名/接口名/枚举类,使用首字母大写的驼峰命名法

对于字段,使用首字母小写的驼峰命名法

现在为mail表建立实体类:

public class Mail {

/**

* 主键id

*/

private long id;

/**

* 创建时间

*/

private Date createTime;

/**

* 修改时间

*/

private Date modifyTime;

/**

* 网站id,1表示新浪,2表示QQ,3表示搜狐,4表示火狐

*/

private int webId;

/**

* 邮箱

*/

private String mail;

/**

* 用途

*/

private String useFor;

public Mail() {}

public Mail(int webId, String mail, String useFor) {

this.webId = webId;

this.mail = mail;

this.useFor = useFor;

}

public long getId() {

return id;

}

public void setId(long id) {

this.id = id;

}

public Date getCreateTime() {

return createTime;

}

public void setCreateTime(Date createTime) {

this.createTime = createTime;

}

public Date getModifyTime() {

return modifyTime;

}

public void setModifyTime(Date modifyTime) {

this.modifyTime = modifyTime;

}

public int getWebId() {

return webId;

}

public void setWebId(int webId) {

this.webId = webId;

}

public String getMail() {

return mail;

}

public void setMail(String mail) {

this.mail = mail;

}

public String getUseFor() {

return useFor;

}

public void setUseFor(String useFor) {

this.useFor = useFor;

}

@Override

public String toString() {

return "MailDO [id=" + id + ", createTime=" + createTime + ", modifyTime=" + modifyTime + ", webId=" + webId + ", mail=" + mail + ", useFor="

+ useFor + "]";

}

}

注意实体类一定要重写toStirng()方法,便于定位问题。

建立数据访问层

下一步,个人喜好是建立数据访问层,对于数据访问层通常有如下约定:

  • 数据访问层使用Dao命名,它定义了对表的基本增删改查操作

  • 数据访问层之上使用Service命名,它的作用是对于数据库的多操作进行组合,比如先查再删、先删再增、先改再查再删等等,这些操作不会放在Dao层面去操作,而会放在Service层面去进行组合

那么,首先定义一个MailDao,我定义增删改查五个方法,其中查询两个方法,一个查单个,一个查列表:

public interface MailDao {

/**

* 插入一条邮箱信息

*/

public long insertMail(Mail mail);

/**

* 删除一条邮箱信息

*/

public int deleteMail(long id);

/**

* 更新一条邮箱信息

*/

public int updateMail(Mail mail);

/**

* 查询邮箱列表

*/

public List<Mail> selectMailList();

/**

* 根据主键id查询一条邮箱信息

*/

public Mail selectMailById(long id);

}

接着是Dao的实现类,通常以”Impl”结尾,”Impl”是关键字”Implements”的缩写,表示接口实现类的意思。MailDao的实现类就命名为MailDaoImpl了,代码为:

public class MailDaoImpl implements MailDao {

private static final String NAME_SPACE = "MailMapper.";

private static SqlSessionFactory ssf;

private static Reader reader;

static {

try {

reader = Resources.getResourceAsReader("mybatis/config.xml");

ssf = new SqlSessionFactoryBuilder().build(reader);

}

catch (IOException e) {

e.printStackTrace();

}

}

@Override

public long insertMail(Mail mail) {

SqlSession ss = ssf.openSession();

try {

int rows = ss.insert(NAME_SPACE + "insertMail", mail);

ss.commit();

if (rows > 0) {

return mail.getId();

}

return 0;

} catch (Exception e) {

ss.rollback();

return 0;

} finally {

ss.close();

}

}

@Override

public int deleteMail(long id) {

SqlSession ss = ssf.openSession();

try {

int rows = ss.delete(NAME_SPACE + "deleteMail",  id);

ss.commit();

return rows;

} catch (Exception e) {

ss.rollback();

return 0;

} finally {

ss.close();

}

}

@Override

public int updateMail(Mail mail) {

SqlSession ss = ssf.openSession();

try {

int rows = ss.update(NAME_SPACE + "updateMail", mail);

ss.commit();

return rows;

} catch (Exception e) {

ss.rollback();

return 0;

} finally {

ss.close();

}

}

@Override

public List<Mail> selectMailList() {

SqlSession ss = ssf.openSession();

try {

return ss.selectList(NAME_SPACE + "selectMailList");

} finally {

ss.close();

}

}

@Override

public Mail selectMailById(long id) {

SqlSession ss = ssf.openSession();

try {

return ss.selectOne(NAME_SPACE + "selectMailById", id);

} finally {

ss.close();

}

}

}

具体代码就不看了,会在第二篇文章开始分析。

建立MyBatis配置文件

接着就是建立MyBatis的配置文件了,MyBatis的配置文件有两个,一个是环境的配置config.xml,一个是具体SQL的编写mail.xml。首先看一下config.xml:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

<properties resource="properties/db.properties" />

<settings>

<setting name="cacheEnabled" value="true" />

<setting name="lazyLoadingEnabled" value="true"/>

<setting name="useGeneratedKeys" value="true"/>

</settings>

<typeAliases>

<typeAlias alias="Mail" type="org.xrq.mybatis.pojo.Mail"/>

</typeAliases>

<environments default="development">

<environment id="development">

<transactionManager type="JDBC"/>

<dataSource type="POOLED">

<property name="driver" value="${driveClass}"/>

<property name="url" value="${url}"/>

<property name="username" value="${userName}"/>

<property name="password" value="${password}"/>

</dataSource>

</environment>

</environments>

<mappers>

<mapper resource="mybatis/mail.xml"/>

</mappers>

</configuration>

接着是编写SQL语句的mail.xml:

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="MailMapper">

<resultMap type="Mail" id="MailResultMap">

<result column="id" property="id" />

<result column="create_time" property="createTime" />

<result column="modify_time" property="modifyTime" />

<result column="web_id" property="webId" />

<result column="mail" property="mail" />

<result column="use_for" property="useFor" />

</resultMap>

<sql id="fields">

id, create_time, modify_time, web_id, mail, use_for

</sql>

<sql id="fields_value">

null, now(), now(), #{webId}, #{mail}, #{useFor}

</sql>

<insert id="insertMail" parameterType="Mail" useGeneratedKeys="true" keyProperty="id">

insert into mail(

<include refid="fields" />

) values(

<include refid="fields_value" />

);

</insert>

<delete id="deleteMail" parameterType="java.lang.Long">

delete from mail where id = #{id};

</delete>

<update id="updateMail" parameterType="Mail">

update mail

<set>

<if test="web_id != 0">

web_id = #{webId}

</if>

<if test="mail != null">

mail = #{mail}

</if>

<if test="use_for != null">

use_for = #{useFor}

</if>

</set>

where id = #{id};

</update>

<select id="selectMailList" resultMap="MailResultMap">

select <include refid="fields" /> from mail;

</select>

<select id="selectMailById" resultMap="MailResultMap" parameterType="java.lang.Long">

select <include refid="fields" /> from mail where id = #{id};

</select>

</mapper>

这个mail.xml我尽量写得全一点,这样后面分析的时候都会有代码示例,mail.xml中包括:

  • resultMap

  • <sql>标签

  • 插入主键返回主键id

  • 动态sql

建立单元测试代码

软件的正确性离不开良好的测试,通常测试有两种方式:

  • 写main函数,这种方式我基本不使用,除非是测试一个很小的功能点比如Math.round这种,这种代码写完我也会直接删除的,不会留着提交到代码库上

  • 使用单元测试工具比如junit,这是我常用的方式

其实很多公司的JD上面也有写着”能编写良好的单元测试代码”,跑main函数的方式我个人真的是不太推荐。

接着看一下单元测试代码:

public class TestMyBatis {

private static MailDao mailDao;

static {

mailDao = new MailDaoImpl();

}

@Test

public void testInsert() {

Mail mail1 = new Mail(1, "123@sina.com", "个人使用");

Mail mail2 = new Mail(2, "123@qq.com", "企业使用");

Mail mail3 = new Mail(3, "123@sohu.com", "注册账号使用");

System.out.println(mailDao.insertMail(mail1));

System.out.println(mailDao.insertMail(mail2));

System.out.println(mailDao.insertMail(mail3));

}

@Test

public void testDelete() {

System.out.println(mailDao.deleteMail(1));

}

@Test

public void testUpdate() {

Mail mail = new Mail(2, "123@qq.com", "个人使用");

mail.setId(2);

System.out.println(mailDao.updateMail(mail));

System.out.println(mailDao.selectMailById(2));

}

@Test

public void testSelectOne() {

System.out.println(mailDao.selectMailById(2));

}

@Test

public void testSelectList() {

List<Mail> mailList = mailDao.selectMailList();

if (mailList != null && mailList.size() != 0) {

for (Mail mail : mailList) {

System.out.println(mail);

}

}

}

}

正确的情况下,应当五个方法跑出来全部是绿色的进度条。

MyBatis源码分析之环境准备篇的更多相关文章

  1. 【MyBatis源码分析】环境准备

    前言 之前一段时间写了[Spring源码分析]系列的文章,感觉对Spring的原理及使用各方面都掌握了不少,趁热打铁,开始下一个系列的文章[MyBatis源码分析],在[MyBatis源码分析]文章的 ...

  2. 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙看这篇或许真的够了 | 百篇博客分析OpenHarmony源码 | v50.06

    百篇博客系列篇.本篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉坑指南 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉 ...

  3. MyBatis 源码分析系列文章导读

    1.本文速览 本篇文章是我为接下来的 MyBatis 源码分析系列文章写的一个导读文章.本篇文章从 MyBatis 是什么(what),为什么要使用(why),以及如何使用(how)等三个角度进行了说 ...

  4. 精尽MyBatis源码分析 - Spring-Boot-Starter 源码分析

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  5. MyBatis源码分析-SQL语句执行的完整流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

  6. Mybatis源码分析--关联表查询及延迟加载原理(二)

    在上一篇博客Mybatis源码分析--关联表查询及延迟加载(一)中我们简单介绍了Mybatis的延迟加载的编程,接下来我们通过分析源码来分析一下Mybatis延迟加载的实现原理. 其实简单来说Myba ...

  7. MyBatis 源码分析系列文章合集

    1.简介 我从七月份开始阅读MyBatis源码,并在随后的40天内陆续更新了7篇文章.起初,我只是打算通过博客的形式进行分享.但在写作的过程中,发现要分析的代码太多,以至于文章篇幅特别大.在这7篇文章 ...

  8. MyBatis 源码分析 - 插件机制

    1.简介 一般情况下,开源框架都会提供插件或其他形式的拓展点,供开发者自行拓展.这样的好处是显而易见的,一是增加了框架的灵活性.二是开发者可以结合实际需求,对框架进行拓展,使其能够更好的工作.以 My ...

  9. MyBatis 源码分析 - 缓存原理

    1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...

随机推荐

  1. HashMap负载因子

    下面是HashMap的一个构造函数,两个参数initialCapacity,loadFactor 这关系HashMap的迭代性能. /** * Constructs an empty <tt&g ...

  2. CentOS下安装JDK的三种方法

    方法一:手动解压JDK的压缩包,然后设置环境变量 1.在/usr/目录下创建java目录 [root@localhost ~]# mkdir/usr/java[root@localhost ~]# c ...

  3. 2017-4-26 winform tab和无边框窗体制作

    TabIndex-----------------------------------确定此控件将占用的Tab键顺序索引 Tabstop-------------------------------指 ...

  4. (转载)Linux查看文件编码格式及文件编码转换

    Linux查看文件编码格式及文件编码转换 时间:2011-04-08作者:woyoo分类:linux评论:0 我友分享: 新浪微博 腾讯微博 搜狐微博 网易微博 开心网 QQ空间 msn 如果你需要在 ...

  5. ASP.NET Web基本原理

    ASP.NET Web基本原理 浏览器与服务器之间的交互 浏览器向服务器发送HTTP请求,具体如下: 1.浏览器向服务器发送TCP包,要求服务器打开连接 TCP包首部32位,占20字节,格式如图一: ...

  6. Windows7 x64 编译Dlib库

    最近用到Dlib库,需要先编译. 本文利用 cmake + Sublime Text 2 + MinGW实现编译. 1. 下载dlib源码[dlib18.17]http://pan.baidu.com ...

  7. 源于《Unity官方实例教程 “Space Shooter”》思路分析及相应扩展

    教程来源于:Unity官方实例教程 Space Shooter(一)-(五)       http://www.jianshu.com/p/8cc3a2109d3b 一.经验总结 教程中步骤清晰,并且 ...

  8. linux 内核的futex - requeue 以及 requeue-pi

    futex为更好支持pthread_cond的实现(,最主要是broadcast),设计了requeue功能,并以futex系统调用提供操作接口,包括一对配对的操作 futex_wait_requeu ...

  9. python 基础之pickle 与json 报错问题解决方案

    Python 基础之pickle与json 有没有在搞pickle与json在进行数据储存的时候老是报错,这个有些让人烦恼,在之前有一篇介绍过它们的基本用法以及在使用过长中避免一些坑,但是今天在把对象 ...

  10. vue2.0实践 —— Node + vue 实现移动官网

    简介 使用 Node + vue 对公司的官网进行了一个简单的移动端的实现. 源码 https://github.com/wx1993/node-vue-fabaocn 效果 组件 轮播图(使用 vu ...