1. 程式人生 > >【MyBatis源碼分析】環境準備

【MyBatis源碼分析】環境準備

arch 事物 基本 pub 加載 tro 單元測試工具 主鍵 values

前言
之前一段時間寫了【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=‘郵箱表‘;

建立實體類
建立完畢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>

&lt;properties resource="properties/db.properties" /&gt;

&lt;settings&gt;
    &lt;setting name="cacheEnabled" value="true" /&gt;
    &lt;setting name="lazyLoadingEnabled" value="true"/&gt;
    &lt;setting name="useGeneratedKeys" value="true"/&gt;
&lt;/settings&gt;

&lt;typeAliases&gt;
    &lt;typeAlias alias="Mail" type="org.xrq.mybatis.pojo.Mail"/&gt;
&lt;/typeAliases&gt;

&lt;environments default="development"&gt;
    &lt;environment id="development"&gt;
        &lt;transactionManager type="JDBC"/&gt;
        &lt;dataSource type="POOLED"&gt;
            &lt;property name="driver" value="${driveClass}"/&gt;
            &lt;property name="url" value="${url}"/&gt;
            &lt;property name="username" value="${userName}"/&gt;
            &lt;property name="password" value="${password}"/&gt;
        &lt;/dataSource&gt;
    &lt;/environment&gt;
&lt;/environments&gt;

&lt;mappers&gt;
    &lt;mapper resource="mybatis/mail.xml"/&gt;
&lt;/mappers&gt;

</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">

&lt;resultMap type="Mail" id="MailResultMap"&gt;
    &lt;result column="id" property="id" /&gt;
    &lt;result column="create_time" property="createTime" /&gt;
    &lt;result column="modify_time" property="modifyTime" /&gt;
    &lt;result column="web_id" property="webId" /&gt;
    &lt;result column="mail" property="mail" /&gt;
    &lt;result column="use_for" property="useFor" /&gt;
&lt;/resultMap&gt;

&lt;sql id="fields"&gt;
    id, create_time, modify_time, web_id, mail, use_for
&lt;/sql&gt;

&lt;sql id="fields_value"&gt;
    null, now(), now(), #{webId}, #{mail}, #{useFor}
&lt;/sql&gt;

&lt;insert id="insertMail" parameterType="Mail" useGeneratedKeys="true" keyProperty="id"&gt;
    insert into mail(
        &lt;include refid="fields" /&gt;
    ) values(
        &lt;include refid="fields_value" /&gt;
    );
&lt;/insert&gt;

&lt;delete id="deleteMail" parameterType="java.lang.Long"&gt;
    delete from mail where id = #{id};
&lt;/delete&gt;

&lt;update id="updateMail" parameterType="Mail"&gt;
    update mail 
    &lt;set&gt;
        &lt;if test="web_id != 0"&gt;
            web_id = #{webId}
        &lt;/if&gt;
        &lt;if test="mail != null"&gt;
            mail = #{mail}
        &lt;/if&gt;
        &lt;if test="use_for != null"&gt;
            use_for = #{useFor}
        &lt;/if&gt;
    &lt;/set&gt;
    where id = #{id};
&lt;/update&gt;

&lt;select id="selectMailList" resultMap="MailResultMap"&gt;
    select &lt;include refid="fields" /&gt; from mail;
&lt;/select&gt;

&lt;select id="selectMailById" resultMap="MailResultMap" parameterType="java.lang.Long"&gt;
    select &lt;include refid="fields" /&gt; from mail where id = #{id};
&lt;/select&gt;

</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, "[email protected]", "個人使用");
    Mail mail2 = new Mail(2, "[email protected]", "企業使用");
    Mail mail3 = new Mail(3, "[email protected]", "註冊賬號使用");
    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, "[email protected]", "個人使用");
    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&lt;Mail&gt; mailList = mailDao.selectMailList();
    if (mailList != null && mailList.size() != 0) {
        for (Mail mail : mailList) {
            System.out.println(mail);
        }
    }
}

}

正確的情況下,應當五個方法跑出來全部是綠色的進度條。

當然,單元測試也可以單獨跑每一個,我個人使用Eclipse/MyEclipse,都是支持的,相信其他IDE肯定也是支持這個功能的。

喜歡小編的可以關註一下哦·~私聊小編也是可以的哦

【MyBatis源碼分析】環境準備