专栏名称: ImportNew
伯乐在线旗下账号,专注Java技术分享,包括Java基础技术、进阶技能、架构设计和Java技术领域动态等。
目录
相关文章推荐
芋道源码  ·  一个RBAC模型的数据范围权限实践 ·  20 小时前  
芋道源码  ·  这款轻量级规则引擎,真香!! ·  20 小时前  
芋道源码  ·  绘制3D架构图,原来这么简单! ·  昨天  
芋道源码  ·  孤陋寡闻了,原来 MySQL 还能这么写? ·  3 天前  
51好读  ›  专栏  ›  ImportNew

MyBatis源码分析 : 环境准备

ImportNew  · 公众号  · Java  · 2017-06-12 12:26

正文

(点击上方公众号,可快速关注)


来源:五月的仓颉 ,

www.cnblogs.com/xrq730/p/6792031.html

如有好文章投稿,请点击 → 这里了解详情


前言


之前一段时间写了【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='邮箱表';


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


建立每张表的时候应当注意唯一约束,像这里,一个网站下的邮箱一定是唯一的,不可能在新浪下同时存在两个名为”[email protected]”的邮箱名,因此对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 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 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:


/span>

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

 

 

   

 

   

       

       

       

   

 

   

       

   

 

   

       

           

           

               

               

               

               

           

       

   

     

   

       

   

     


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


/span>

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

 

 

   

       

       

       

       

       

       

   

 

   

        id, create_time, modify_time, web_id, mail, use_for

   

     

   

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

   

 

   

        insert into mail(

           

        ) values(

           

        );

   

 

   

        delete from mail where id = #{id};

   

     

   

        update mail 

       

           

                web_id = #{webId}

           

           

                mail = #{mail}

           

           

                use_for = #{useFor}

           

       

        where id = #{id};

   

 

   

        select from mail where id = #{id};

   

     


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


  • resultMap

  • 标签

  • 插入主键返回主键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 mailList = mailDao.selectMailList();

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

            for (Mail mail : mailList) {

                System.out.println(mail);

            }

        }

    }

     

}


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


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


看完本文有收获?请转发分享给更多人

关注「ImportNew」,看技术干货