zoukankan      html  css  js  c++  java
  • 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);

                }

            }

        }

         

    }

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

  • 相关阅读:
    VS开发ExtJS
    ASP.NET初识9
    程序窗体和对话框
    浏览器的使用
    ASP.NET初识6
    310号的收获 将会决定 业余时间的方向。now foucs
    无代码 无说服力 4种 cast
    android Makefile 的流程—how android makefile workmakefile progress in android
    【资料】父子进程可以共享变量吗? 使用pipeline
    Sysinternals 手册阅读 about vmmap目标运行中优化内存
  • 原文地址:https://www.cnblogs.com/jiabo-yuan/p/6992984.html
Copyright © 2011-2022 走看看