新手上路使用MyBatis连接数据库

        经过一个阶段的学习和了解本菜鸟对MyBatis框架有了一些比较浅显的认识,下面就让我来跟大家分享一下,欢迎大家批评指正。

        众所周知MyBatis是一个半自动的ORM(对象关系映射)框架,使用反射、动态代理等机制对JDBC进行了封装,几乎消除了所有的JDBC代码和参数的手动设置以及结果集的需检索,大大的提高了编写代码的效率跟灵活性,仅需要我们编写POJO类、SQL语句和映射关系等就可以实现连接数据库。    

        以上几句是非常标准化的官方语言,在各种版本的书籍资料上都能看到类似说法,相信很多刚接触MyBatis的小伙伴也像我一样,看完概念描述感觉好像明白点了,但实际上还有点云里雾里的感觉,

        实际上MyBatis原理很简单,通过SqlSessionFactory读取mybatis-config.xml,进而读取Mapper.xml映射文件,执行其中的SQL语句,然后创建一个包含PrepareStatement的Map,然后SqlSession根据SQL的id找到相对应的statement,然后执行响应的方法,最后讲记录转换成实体对象或者实体对象组成的集合。

        下边是本鸟手工绘制的一张图有点惨凑合看吧

新手上路使用MyBatis连接数据库

        如果还不了解没关系,那么接下来请大家跟我一起看一个小例子吧,我来为大家具体剖析一下mybatis到底是怎么连接数据库的。

创建Maven项目

    首先我们创建一个Maven项目,额......等等你为什么创建Maven项目,Maven是个啥不是说MyBatis吗你建个Maven干什么,就知道你们会这么问,那么本鸟在这先解释一下。

    Maven顾名思义就是“知识的积累”我查了一下英汉词典也可以翻译为“专家”或者是“内行”,它是Apache组织中一个非常成功的开源项目,主要服务于基于Java平台的项目构建依赖项目信息管理。这么说你可能还不明白那我在说明白点,构建就是指我们编译、运行单元测试、生成文档、打包和部署项目这种繁琐的工作;依赖是指一种关系,比如说你的项目可能要依赖于其他项目,比如说Apache-common包,mysql-connector-java包还有junit包。Maven可以简化繁琐的构建步骤,可以自动下载jar包,同时它跨平台,并对外还提供了接口。现在明白为什么要创建一个Maven项目了吧!

        那么话不多少我们回到正题,首先我们在IDE里创建一个Maven,下图是一个在IDEA里创建好的Maven项目

新手上路使用MyBatis连接数据库

打开Maven项目的配置文件pom.xml可以看到如下配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.bdqn</groupId>
    <artifactId>WorkerSystem</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>

以上是Maven的基本配置信息,我们还需要为他手导入几个jar包,及其配置读取src包下的xml文件代码如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.bdqn</groupId>
    <artifactId>WorkerSystem</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
    </dependencies>
    <!--配置读取src目录下的xml文件-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

OK,如此pom.xml文件就配置好了

准备数据库

配置好了pom接下来我们应该先准备创建一个数据库设置好主外键并向其中插入信息

CREATE DATABASE workorder;

CREATE TABLE project(
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '项目编号',
projectName VARCHAR(50) NOT NULL COMMENT '项目名称'

);

CREATE TABLE workorder(
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '工单编号',
projectId BIGINT NOT NULL COMMENT '项目编号',
executor VARCHAR(50) NOT NULL COMMENT '执行人',
description VARCHAR(50) NOT NULL COMMENT '任务描述',
orderLevel INT(20) NOT NULL COMMENT '工单级别',
creatDate DATETIME NOT NULL COMMENT '创建时间'

);

ALTER TABLE `workorder` ADD CONSTRAINT fk_p_w FOREIGN KEY(`projectId`) REFERENCES `project`(`id`);

配置MyBatis

配置MyBatis的方式有很多,我们采用最基础和常用的xml配置文件的方式进行配置

使用xml形式进行配置,首先在src/main/resources下面创建mybatis-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>
    <!--引入database.properties文件-->
    <properties resource="database.properties"/>
    <!--settings中的logImpl属性配置指定使用LOG4J输出日志-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>
    <typeAliases>
        <package name="cn.bdqn.entity"/>
    </typeAliases>
    <!--配置数据源环境使用iddev-->
    <environments default="dev">
        <!--配置iddev的数据源-->
        <environment id="dev">
            <!--配置数据库事务,采用JDBC方式手工提交-->
            <transactionManager type="JDBC"></transactionManager>
            <!--使用数据库连接池-->
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.userName}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--Mapper映射器-->
    <mappers>
        <!--加载映射器资源文件-->
        <mapper resource="cn/bdqn/dao/WorkMapper.xml"/>
    </mappers>
</configuration>

database.properties配置文件的代码如下,记得改密码哦!

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/workorder
jdbc.userName=root
jdbc.password=root

        <environment>环境配置中主要配置了数据库连接,使用的是本机中名为workerorder的数据库,后面的userName和password是数据库的用户名和密码

          <mappers>中配置了一个包含完整路径的WorkMapper.xml,这是一个MyBatis的SQL语句和映射的配置文件,一会后面我们会用到

创建实体类和Mapper.xml

创建实体类(也叫pojo类)Worker.java

package cn.bdqn.entity;

public class Work {
    private int id;
    private String projectName;

    @Override
    public String toString() {
        return "Work{" +
                "id=" + id +
                ", projectName='" + projectName + '\'' +
                '}';
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }
}

这里创建的实体类实际上是一个数据值对象,在实际应用中一般会对应一个实体,用于增、删、改、查操作,所以姑且称这个简单的对象为实体类

创建WorkerMapper.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">

<!--定义操作Work对象的命名空间-->
<mapper namespace="cn.bdqn.dao.WorkMapper">
    <resultMap id="workMap" type="Work">
        <id property="id" column="id"/>
        <result property="projectName" column="projectName"/>
    </resultMap>
    <!--执行查询操作-->
    <select id="queryAll" resultMap="workMap">
        select * from project;
    </select>
</mapper>

        在MyBatis中,根据官方的命名习惯我们通常把Mapper作为xml文件和接口的类名的后缀。

        SQL语句定义在了WorkMapper.xml文件中 ,这样做可以让我们方便的修改定义SQL语句。

        <mapper>是xml的根元素,里边的namespace定义了当前的命名空间。

        在这里我想重点说一下<select>查询标签里的两个属性resultType和resultMap,resultType是直接表示返回值类型的,而resultMap是对外部ResultMap的引用,这两个属性不能够同时存在。当我们使用resultType时,实际上MyBatis会将Map里面的键值对取出来赋值给resultType指定的对象对应的属性,所以其实相当于返回类型也还是resultMap,只不过在用resultType时MyBatis自动把值赋给了resultType所指定的对象。

        上边代码选用了resultMap属性,因为Map不能很好的表示这个集合,需要我们自己进一步把他转化为别的对象

配置log4j

在src下的resources中创建log4j.properties文件将以下代码复制进去

log4j.rootLogger=DEBUG,CONSOLE,file
log4j.logger.cn.smbms.dao=debug
log4j.logger.com.ibatis=debug 
log4j.logger.com.ibatis.common.jdbc.SimpleDataSource=debug 
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=debug 
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=debug 
log4j.logger.java.sql.Connection=debug 
log4j.logger.java.sql.Statement=debug 
log4j.logger.java.sql.PreparedStatement=debug 
log4j.logger.java.sql.ResultSet=debug 
log4j.logger.org.tuckey.web.filters.urlrewrite.UrlRewriteFilter=debug
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.Threshold=error
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern= [%p] %d %c - %m%n
log4j.appender.file=org.apache.log4j.DailyRollingFileAppender
log4j.appender.file.DatePattern=yyyy-MM-dd
log4j.appender.file.File=log.log
log4j.appender.file.Append=true
log4j.appender.file.Threshold=error
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-M-d HH:mm:ss}%x[%5p](%F:%L) %m%n
log4j.logger.com.opensymphony.xwork2=error 

配置log4j是让MyBatis在执行数据库操作的时候可以将执行的SQL和其他信息输出到控制台

编写接口

package cn.bdqn.dao;

import cn.bdqn.entity.Work;

import java.util.List;

public interface WorkMapper {
    List<Work> queryAll();

}

Mapper接口开发需要遵循以下规范

1.Mapper.xml文件中的namespace与mapper接口的类路径相同

2.Mapper接口方法名和Mapper.xml的定义的每个操作标签中的id相同

编写公用的MyBatisUtil类与测试类

package cn.bdqn.util;

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 java.io.Reader;

public class MyBatisUtil {

    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //获取mybatis-config.xml的输入流
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            //创建SqlSessionFactory对象,完成对配置文件的读取
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //创建sqlSession
    public static SqlSession createSqlSession(){
        return sqlSessionFactory.openSession();
    }

    //通用关闭方法
    public static void closeSqlSession(SqlSession sqlSession){
        if(sqlSession!=null){
            sqlSession.close();
        }
    }

}

测试类

import cn.bdqn.dao.WorkMapper;
import cn.bdqn.entity.Pro;
import cn.bdqn.entity.Work;
import cn.bdqn.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;

import java.util.List;

public class Test {

    /**
     * 查询所有项目信息
     */
    @org.junit.Test
    public void queryAll() {
        SqlSession sqlSession = null;
        try {
            sqlSession = MyBatisUtil.createSqlSession();
            List<Work> list = sqlSession.getMapper(WorkMapper.class).queryAll();
            if (list != null) {
                for (Work work : list) {
                    System.out.println(work);
                }
            }
        } finally {
            MyBatisUtil.closeSqlSession(sqlSession);
        }
    }

}

        首先通过Resources工具类将mybatis-config.xml配置文件读入Reader或者InputStream

        然后后再通过SqlSessionFactoryBuilder建造类使用Reader或者InputStream创建SQLSessionFactory工厂对象,在此过程中,他会先解析mybatis-config.xml配置文件,读取配置文件中的mappers配置后会读取Mapper.xml进行具体方法的解析,最后SqlSessionFactory就包含了所有的属性配置和执行SQL的信息。

        MyBatis底层使用JDBC执行SQL,获得查询结果集ResultSet后,根据上面配置文件中resultMap的配置将结果映射为Work类型的集合,返回查询结果,这样就得到了最后的查询结果list,最后把结果在控制台输出,当然到最后还要关闭SQLSession,否则会因为连接没有关闭导致数据库连接过多,造成系统崩溃。