【MyBatis源码分析】环境准备

栏目: 数据库 · 发布时间: 8年前

内容简介:【MyBatis源码分析】环境准备

前言

之前一段时间写了【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);
            }
        }
    }
    
}

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

当然,单元测试也可以单独跑每一个,我个人使用Eclipse/MyEclipse,都是支持的,相信其他IDE肯定也是支持这个功能的。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Hacking Growth

Hacking Growth

Sean Ellis、Morgan Brown / Crown Business / 2017-4-25 / USD 29.00

The definitive playbook by the pioneers of Growth Hacking, one of the hottest business methodologies in Silicon Valley and beyond. It seems hard to believe today, but there was a time when Airbnb w......一起来看看 《Hacking Growth》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器