MyBatis之工作原理,简单实体的增加、修改、删除、查询

一、MyBatis之工作原理

MyBatis是一个半自动映射框架。所谓半自动,是相对Hibernate全表映射而言的,MyBatis需要手动匹配提供POJO、SQL和映射关系。

我们知道,JDBC有四个核心对象:
(1)DriverManager,用于注册数据库连接
(2)Connection,与数据库连接对象
(3)Statement/PrepareStatement,操作数据库SQL语句的对象
(4)ResultSet,结果集或一张虚拟表

而MyBatis也有四大核心对象:
(1)SqlSession对象,该对象中包含了执行SQL语句的所有方法。类似于JDBC里面的Connection。
(2)Executor接口,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。类似于JDBC里面的Statement/PrepareStatement。
(3)MappedStatement对象,该对象是对映射SQL的封装,用于存储要映射的SQL语句的id、参数等信息。
(4)ResultHandler对象,用于对返回的结果进行处理,最终得到自己想要的数据格式或类型。可以自定义返回类型。

MyBatis的工作原理如下图所示:

 

上面中流程就是MyBatis内部核心流程,每一步流程的详细说明如下文所述:

(1)读取MyBatis的配置文件。mybatis-config.xml为MyBatis的全局配置文件,用于配置数据库连接信息。

(2)加载映射文件。映射文件即SQL映射文件,该文件中配置了操作数据库的SQL语句,需要在MyBatis配置文件mybatis-config.xml中加载。mybatis-config.xml 文件可以加载多个映射文件,每个文件对应数据库中的一张表。

(3)构造会话工厂。通过MyBatis的环境配置信息构建会话工厂SqlSessionFactory。

(4)创建会话对象。由会话工厂创建SqlSession对象,该对象中包含了执行SQL语句的所有方法。

(5)Executor执行器。MyBatis底层定义了一个Executor接口来操作数据库,它将根据SqlSession传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。

(6)MappedStatement对象。在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等信息。

(7)输入参数映射。输入参数类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输入参数映射过程类似于JDBC对preparedStatement对象设置参数的过程。

(8)输出结果映射。输出结果类型可以是Map、List等集合类型,也可以是基本数据类型和POJO类型。输出结果映射过程类似于JDBC对结果集的解析过程。

二、简单实体的增加、修改、删除、查询

1、环境

mybatis-3.2版本,jdk1.8版本,Oracle数据库

2、准备工作

2.1 下载mybatis-3.2,需要引用其中的若干包,包括数据库JDBC驱动包

mybatis-3.2.0.jar
    lib/asm-3.3.1.jar
    lib/cglib-2.2.2.jar
    lib/commons-logging-1.1.1.jar
    lib/javassist-3.17.1-GA.jar
    lib/log4j-1.2.17.jar
    lib/slf4j-api-1.7.2.jar
    lib/slf4j-log4j12-1.7.2.jar
ojdbc6.jar

2.2 项目的目录结构

com.clzhang.mybatis.mapper      MemberUserMapper.java           MyBatis的mapper处理类(非必须)
com.clzhang.mybatis.entity      MemberUserBean.java            MyBatis的entity类
com.clzhang.mybatis             MyBatisTest1.java/MyBatisTest2.java   测试类 
resources\config           mybatis
-config.xml            MyBatis的配置文件
resources\com\clzhang\mybatis\mapper  MemberUserMapper.xml        MyBatis的mapper配置文件

2.3 假定数据库已经创建,表结构也已经创建,并且有测试数据

CREATE TABLE MEMBER_USER (
ID NUMBER NOT NULL PRIMARY KEY,
NAME VARCHAR2(30),
PERSONMOBILE VARCHAR2(20),
ADDRESS VARCHAR2(255),
AGE NUMBER);

CREATE SEQUENCE SEQ_MEMBER_USER;

3、具体步骤

3.1 创建entity类

package com.clzhang.mybatis.entity;

public class MemberUserBean {
    private int id;
    private String name;
    private String personMobile;
    private String address;
    private int age;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPersonMobile() {
        return personMobile;
    }

    public void setPersonMobile(String personMobile) {
        this.personMobile = personMobile;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "MemberUser [id=" + id + ", name=" + name + 
                       ", personMobile=" + personMobile + ", address=" + address + ", age=" + age + "]";
    }
}

3.2 创建Mapper接口(非必须)

package com.clzhang.mybatis.mapper;

import java.util.*;
import com.clzhang.mybatis.entity.MemberUserBean;

public interface MemberUserMapper {
    public void insertUser(MemberUserBean user);

    public void updateUser(MemberUserBean user);

    public void deleteUser(int id);

    public MemberUserBean getUserById(int id);

    public List getUsersByAge(int startAge, int endAge);
}

3.3 创建mybatis-config.xml的配置文件,位置于resources/config目录

<?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> 
    <settings> 
        <setting name="cacheEnabled" value="false" /> 
        <setting name="useGeneratedKeys" value="true" /> 
        <setting name="defaultExecutorType" value="REUSE" /> 
    </settings> 
    <typeAliases> 
       <typeAlias alias="MemberUser" type="com.clzhang.mybatis.entity.MemberUserBean"/> 
    </typeAliases> 
    <environments default="development"> 
       <environment id="development"> 
           <transactionManager type="JDBC"/> 
           <dataSource type="POOLED"> 
              <property name="driver" value="oracle.jdbc.driver.OracleDriver"/> 
              <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl"/> 
              <property name="username" value="mytest"/> 
              <property name="password" value="test001"/> 
           </dataSource> 
       </environment> 
    </environments> 
    <mappers> 
        <mapper resource="com/clzhang/mybatis/mapper/MemberUserMapper.xml" /> 
    </mappers> 
</configuration>

3.4 创建MemberUserMapper.xml配置文件,位置于:resources\com\clzhang\mybatis\mapper\

<?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="com.clzhang.mybatis.mapper.MemberUserMapper">
    <!--
    默认情况下是没有开启缓存的,下条代码是开启二级缓存的,作用如下:
    1.•映射语句文件中的所有 select 语句将会被缓存。
    2.•映射语句文件中的所有 insert,update 和 delete 语句会刷新缓存。
    3.•缓存会使用 Least Recently Used(LRU,最近最少使用的)算法来收回。
    ......
    -->
    <cache />
    
    <!--以单个对象方式返回-->
    <select id="getUserById" resultType="MemberUser" parameterType="int">
    select
      ID,
      NAME,
      PERSONMOBILE,
      ADDRESS,
      AGE
      FROM MEMBER_USER
    WHERE ID = #{id}
    </select>

    <resultMap type="MemberUser" id="userAgeMap">  
        <id property="id" column="id"/>  
        <!--有需要做数据库到实体类名称转换的,可以写在这里-->
        <!--
        <result property="objname" column="dbname"/>
        -->
    </resultMap>  

    <!--以List方式返回多个结果-->
    <!--参数名称目前不可以自行指定(无法与Mapper中保持一致),待查-->
    <select id="getUsersByAge" resultMap="userAgeMap" parameterType="int">
    <![CDATA[
    select
      ID,
      NAME,
      PERSONMOBILE,
      ADDRESS,
      AGE
      FROM MEMBER_USER
    WHERE AGE > #{param1} AND AGE < #{param2}
    ]]>
    </select>
    
    <!--Oracle的实现自增长主键的方式-->
    <insert id="insertUser" parameterType="MemberUser">
    <selectKey keyProperty="id" resultType="int" order="BEFORE">
      select SEQ_MEMBER_USER.nextval from DUAL
    </selectKey>
      INSERT INTO MEMBER_USER (ID, NAME, PERSONMOBILE, ADDRESS, AGE)
      VALUES(#{id}, #{name}, #{personMobile}, #{address}, #{age})
    </insert>

    <update id="updateUser" parameterType="MemberUser">
      update MEMBER_USER set
        NAME = #{name},
        PERSONMOBILE = #{personMobile},
        ADDRESS = #{address},
        AGE = #{age}
      where id = #{id}
    </update>

    <delete id="deleteUser" parameterType="int">
      delete from MEMBER_USER where ID = #{id}
    </delete>
</mapper>

3.5 创建测试类一,调用SqlSession实现CRUD

package com.clzhang.mybatis;

import java.io.IOException;
import java.io.Reader;
import java.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 org.junit.Test;

import com.clzhang.mybatis.entity.MemberUserBean;

public class MyBatisTest1 {
    private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml";
    private static SqlSessionFactory sqlSessionFactory;

    static {
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        // 一旦你创建了 SqlSessionFactory后,SqlSessionFactoryBuilder这个类就不需要存在了。
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    }

    /**
     * SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。
     * 
     * @return
     */
    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }

//    @Test
    public void testInert() {
        // SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserBean memberUser = new MemberUserBean();
            memberUser.setName("李勇");
            memberUser.setPersonMobile("998877");
            memberUser.setAddress("江苏某地方");
            memberUser.setAge(38);

            int rows = sqlSession.insert("com.clzhang.mybatis.mapper.MemberUserMapper.insertUser", memberUser);
            if (rows > 0) {
                System.out.println("您成功插入" + rows + "条数据!");
            } else {
                System.out.println("执行插入操作失败!!!");
            }

            sqlSession.commit();

            // 查看新加的对象主键
            System.out.println("新加对象的id:" + memberUser.getId());
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void testUpdate() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserBean memberUser = new MemberUserBean();
            memberUser.setId(5);
            memberUser.setName("赵五");
            memberUser.setPersonMobile("12345");
            memberUser.setAddress("天津上地某公司");
            memberUser.setAge(29);

            int rows = sqlSession.update("com.clzhang.mybatis.mapper.MemberUserMapper.updateUser", memberUser);
            if (rows > 0) {
                System.out.println("您成功更新" + rows + "条数据!");
            } else {
                System.out.println("执行更新操作失败!!!");
            }

            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void testDelete() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            int rows = sqlSession.delete("com.clzhang.mybatis.mapper.MemberUserMapper.deleteUser", 5);
            if (rows > 0) {
                System.out.println("您成功删除" + rows + "条数据!");
            } else {
                System.out.println("执行删除操作失败!!!");
            }
            
            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void getUser() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserBean memberUser = sqlSession.selectOne("com.clzhang.mybatis.mapper.MemberUserMapper.getUserById", 1);
            System.out.println(memberUser.toString());
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void getUserByAge() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            Map<String, Object> paramMap = new HashMap<String, Object>();
            paramMap.put("param1", 20);
            paramMap.put("param2", 30);
            List<MemberUserBean> memberUsers = sqlSession.selectList("com.clzhang.mybatis.mapper.MemberUserMapper.getUsersByAge", paramMap);
            for (MemberUserBean memberUser : memberUsers) {
                System.out.println(memberUser);
            }
        } finally {
            sqlSession.close();
        }
    }
}

3.6 创建测试类二,调用Mapper接口实现CRUD

package com.clzhang.mybatis;

import java.io.IOException;
import java.io.Reader;
import java.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 org.junit.Test;

import com.clzhang.mybatis.mapper.MemberUserMapper;
import com.clzhang.mybatis.entity.MemberUserBean;

public class MyBatisTest2 {
    private static final String MYBATIS_CONFIG_FILENAME = "config/mybatis-config.xml";
    private static SqlSessionFactory sqlSessionFactory;

    static {
        Reader reader = null;
        try {
            reader = Resources.getResourceAsReader(MYBATIS_CONFIG_FILENAME);
        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
        // 一旦你创建了 SqlSessionFactory后,SqlSessionFactoryBuilder这个类就不需要存在了。
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
    }

    /**
     * SqlSessionFactory 应该在你的应用执行期间都存在。没有理由来处理或重新创建它。
     * 
     * @return
     */
    public static SqlSessionFactory getSqlSessionFactory() {
        return sqlSessionFactory;
    }

//    @Test
    public void testInert() {
        // SqlSession 的实例不能被共享,也是线程不安全的。因此最佳的范围是请求或方法范围。
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserBean memberUser = new MemberUserBean();
            memberUser.setName("李勇");
            memberUser.setPersonMobile("998877");
            memberUser.setAddress("江苏某地方");
            memberUser.setAge(38);

            MemberUserMapper mapper = sqlSession
                    .getMapper(MemberUserMapper.class);
            mapper.insertUser(memberUser);

            sqlSession.commit();

            // 查看新加的对象主键
            System.out.println("新加对象的id:" + memberUser.getId());
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void testUpdate() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserBean memberUser = new MemberUserBean();
            memberUser.setId(6);
            memberUser.setName("赵五");
            memberUser.setPersonMobile("12345");
            memberUser.setAddress("天津上地某公司");
            memberUser.setAge(29);

            MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);
            mapper.updateUser(memberUser);

            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void testDelete() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);
            mapper.deleteUser(6);
            
            sqlSession.commit();
        } finally {
            sqlSession.close();
        }
    }

//    @Test
    public void getUser() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);
            MemberUserBean memberUser = mapper.getUserById(1);

            System.out.println(memberUser.toString());
        } finally {
            sqlSession.close();
        }
    }

    @Test
    public void getUserByAge() {
        SqlSession sqlSession = getSqlSessionFactory().openSession();
        try {
            MemberUserMapper mapper = sqlSession.getMapper(MemberUserMapper.class);
            List<MemberUserBean> myList = mapper.getUsersByAge(20, 40);
            for (MemberUserBean entry : myList) {
                int key = entry.getId();
                String value = entry.getAddress();

                System.out.println(key + ":" + value);
            }
        } finally {
            sqlSession.close();
        }
    }
}

4、单独测试各个模块

解除注释JUnit各单元,然后键盘输入:alt+shift+X,T,分别进行测试。

本文参考:http://www.mybatis.cn/archives/706.html

posted @ 2021-07-09 12:52  那些年的事儿  阅读(663)  评论(0编辑  收藏  举报