一步步学Mybatis-搭建最简单的开发环境-开篇(1)

  最近抽空学习了 Mybatis 这个框架,在学习的过程中也找了很多的文章,个人感觉官网上的东西太多太杂,不适合许多希望一步步快速上手的朋友们,当然觉得查阅问题的时候可以直接通过官网找还比较快或者是 StackOverflow,鉴于此原因把自己想把自己学习过程中的经验留作笔记以供分享参考之用,尽量少绕弯路。因为想直接了解 Mybatis 的使用方式,而网上有许多学习文章是 Mybatis 与 Spring 的结合范例,或者说直接在 Web Project 项目下创立的范例,感觉对于只是纯粹想了解那个东西怎么使用的朋友应该不需要那么多附加的条件,所以本系列中直接用最简单的 Java Project 作范例演示。

  什么是 Mybatis,前身 iBatis(个人没用过,所以没什么发言权),引述官网的原意来说,Mybatis 是支持普通 SQL 查询,可以更简单直接的操作 SQL,存储过程和高级映射的一种优秀的持久层框架,使用它基本可以消除所有的 JDBC 大麦和参数的手工设置以及结果集的检索,其实个人使用下来感觉,其实主要工作都是在配置 XML 或者注解上,然后将接口和 Java 的 POJO(普通 Java 对象映射成数据库的记录),个人没用过 Java 的 Hb,所以对于两者之间的差异性也没权限发表意见,我相信各个事物的产生总有它自己的目的。

  这段时间学习下来,其实对 Mybatis 来说主要的过程无法是以下几步

  1. 从 XML 配置文件中获取 SessionFactory,然后由 SessionFactory 产生相应的 Session。

  2. 是用 Session 对象对业务数据完成相应的 CRUD 操作(增删改查)和相应的事务控制。

  3. 使用完毕后关闭相应的 Session,以免过度占用资源

  4. 使用配置相应的 Mapper xml 文件进行业务实体的 JavaBean 与数据库表之间做相应的 Map 操作

  

战前准备:

  1. 开发环境 Eclipse JavaEE IDE,JDK 1.6,数据库 mysql 5.5

  2. 下载相应 Jar 包,以备后用

    mybatis-3.2.3.zip 解压后拿出 mybatis-3.2.3.jar,=> 下载地址: http://code.google.com/p/mybatis/ (Mybatis 核心包)

    mybatis-generator-core-1.3.1.jar => 下载地址: http://code.google.com/p/mybatis/wiki/Generator (Mybatis 自动生成配置文件包)

    mysql-connector-java-5.1.26-bin.jar => 下载地址:http://dev.mysql.com/downloads/connector/j/ (Mysql 的 jdbc 驱动包)

  

  接下来大家可以再 Eclipse 下面建一个名为 MybatisDemo 的 Java Project 项目,按照如下图中所示新建相应的包结构和文件夹结构,其中 config 与 mapper 分别为文件夹,

  包 david.mybatis.demo 与包 david.mybatis.model 下分别存放相应的 demo 运行程序与 Javabean 对象,lib 文件夹下存放刚刚下载的那几个第三方 jar 包。

            

  

  

  建完下面的目录,我们可以添加相应的 Jar 包,如下图

  

  

   完成后,执行下面 SQL,建立 DEMO 所需的表结构,分别有 3 张表,Visitor(访问者表),Website(网站表),Channel(频道表)

  

/*创建 Visitor*/
CREATE TABLE Visitor
(
    Id INT(11) NOT NULL AUTO_INCREMENT,
    Name VARCHAR(1000) NOT NULL,
    Email VARCHAR(1000) NOT NULL,
    Status INT NOT NULL DEFAULT 1,
    CreateTime DateTime,
    PRIMARY KEY(Id)
)
/*创建网站表*/
CREATE TABLE Website
(
    Id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    Name VARCHAR(1000) NOT NULL,
    VisitorId INT REFERENCES Visitor(Id),
    Status INT NOT NULL DEFAULT 1,
    CreateTime DateTime
)

/创建频道表/
CREATE TABLE Channel
(
Id
INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
Name
VARCHAR(1000) NOT NULL,
WebsiteId
INT REFERENCES Website(Id),
Status
INT NOT NULL DEFAULT 1,
CreateTime
DateTime
)

建表 SQL

所有这些都完成后,我们就要开始动手啦 ~

就像开头说的,Mybatis 的所有配置都源于一份 XML 配置文件,我们需要在 config 文件夹下,新建名为 mybatis_demo_config.xml 的配置文件,这一份东西就是我们后面所需要操作的核心之一。

在配置这个文件千万要注意<configuration> 节点内的元素都是有层级顺序的要求的,不能够随意更换次序,否则在加载 xml 配置文件的时候会出现异常而导致后续操作不成功。

具体的节点说明大家可以查看http://mybatis.github.io/mybatis-3/zh/configuration.html#,这里只说比较常用的节点,typeAliases,environments,mappers。

1. typeAliases => 别名节点,可以通过设置这个节点的属性,这样配置文件中其他需要实体名字的地方都可以使用此别名而不是完全限定名

例如 <typeAlias type="david.mybatis.model.Visitor" alias="Visitor" />

2. environments => 环境节点,配置数据连接相关的信息

3. mappers => 配置 SQL 映射语句。

最简单的配置如下:

<?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>
    <typeAliases>
        <typeAlias type="david.mybatis.model.Visitor" alias="Visitor" />
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <!-- ?useUnicode=true&amp;characterEncoding=utf8 为了支持中文插入 -->
                <property name="url"
                    value="jdbc:mysql://127.0.0.1:3306/mybatis_db?useUnicode=true&amp;characterEncoding=utf8" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mapper/VisitorMapper.xml" />
    </mappers>
</configuration>
XML 配置

在包 david.mybatis.demo 下面新建一个名为 MyBatisUtils 类,里面存放获取 SqlSession 与关闭 SqlSession 的方法,提炼出来方便多次复用。

package david.mybatis.demo;

import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import david.mybatis.model.CRUD_Enum;

public class MybatisUtils {

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> String CONFIG_PATH = "config/mybatis_demo_config.xml"<span style="color: rgba(0, 0, 0, 1)">;

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
 * 获取数据库访问链接
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span><span style="color: rgba(0, 0, 0, 1)"> SqlSession getSqlSession() {
    SqlSession session </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        InputStream stream </span>=<span style="color: rgba(0, 0, 0, 1)"> Resources.getResourceAsStream(CONFIG_PATH);
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">可以根据配置的相应环境读取相应的数据库环境
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> stream, "development"); </span>
        SqlSessionFactory factory = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> SqlSessionFactoryBuilder()
                .build(stream);
        session </span>=<span style="color: rgba(0, 0, 0, 1)"> factory.openSession();
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (Exception e) {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO: handle exception</span>

e.printStackTrace();
}
return session;
}

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
 * 获取数据库访问链接
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> closeSession(SqlSession session) {
    session.close();
}

</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">
 * 返回操作记录消息
 </span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> showMessages(CRUD_Enum type, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> count) {
    </span><span style="color: rgba(0, 0, 255, 1)">switch</span><span style="color: rgba(0, 0, 0, 1)"> (type) {
    </span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> Add:
        System.out.println(</span>"添加了" + count + "条记录。"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> Delete:
        System.out.println(</span>"删除了" + count + "条记录。"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> Update:
        System.out.println(</span>"更新了" + count + "条记录。"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> Query:
        System.out.println(</span>"匹配了" + count + "条记录。"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">case</span><span style="color: rgba(0, 0, 0, 1)"> List:
        System.out.println(</span>"共有" + count + "条记录。"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">default</span><span style="color: rgba(0, 0, 0, 1)">:
        </span><span style="color: rgba(0, 0, 255, 1)">break</span><span style="color: rgba(0, 0, 0, 1)">;
    }
}

}

MybatisUtils 工具类

在包 david.mybatis.model 下面新建一个名为 Visitor 的类,用来作相应的 OR Mapping。

package david.mybatis.model;

import java.text.SimpleDateFormat;
import java.util.Date;

public class Visitor {
private int id;
private String name;
private String email;
private int status;
private Date createTime;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Visitor() {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated constructor stub</span>
    createTime = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Visitor(String name, String email) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.email =<span style="color: rgba(0, 0, 0, 1)"> email;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.status = 1<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.createTime = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Date();
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setName(String name) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getName() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setEmail(String email) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.email =<span style="color: rgba(0, 0, 0, 1)"> email;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getEmail() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> email;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Date getCreateTime() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> createTime;
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> TODO Auto-generated method stub</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> String.format("{Id: %d, Name: %s, CreateTime: %s}"<span style="color: rgba(0, 0, 0, 1)">, id, name,
            </span><span style="color: rgba(0, 0, 255, 1)">new</span> SimpleDateFormat("yyyy-MM-dd HH🇲🇲ss"<span style="color: rgba(0, 0, 0, 1)">).format(createTime));
}

}

Visitor 类

在包 david.mybatis.demo 下面新建一个 VisitorMapper.xml,用来映射相应 SQL 语句。

这里要注意 namespace=>david.mybatis.demo.IVisitorOperation 一定要与对应这个包下面的实际文件名,IVisitorOperation 否则无法成功加载相应的映射文件

<mapper namespace="david.mybatis.demo.IVisitorOperation">
    <select id="basicQuery" parameterType="int" resultType="Visitor">
        select * from visitor where id=#{id} and
        Status>0 order by Id
    </select>
</mapper>
IVisitorOperation 接口

接下来运行下面的程序

    public static void testBasicQuery(int id) {
        SqlSession session = MybatisUtils.getSqlSession();
        try {
            Visitor visitor = (Visitor) session.selectOne("david.mybatis.demo.IVisitorOperation.basicQuery", id);
            MybatisUtils.closeSession(session);
            System.out.println(visitor);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
基础查询

一个最简单的执行结果就出来啦

这算是 Mybatis 系列的 HelloWord,下回会讲述关于使用接口的方式进行相应操作。