sukbear

mybatis 执行过程

2018-08-20
sukbear
ORM

Mybatis

png来源

接口层

与数据库的交互方式API

传统API

传统的传递Statement Id 和查询参数给 SqlSession 对象,使用 SqlSession对象完成和数据库的交互;
MyBatis提供了非常方便和简单的API,供用户实现对数据库的增删改查数据操作,以及对数据库连接信息和MyBatis 自身配置信息的维护操作。 ![](https://raw.githubusercontent.com/sukbear/sukbear.github.io/master/images/my2.png)

Mapper接口

MyBatis 将配置文件中的每一个<mapper> 节点抽象为一个 Mapper 接口,而这个接口中声明的方法和跟<mapper> 节点中的<select|update|delete|insert> 节点项对应;
即<select|update|delete|insert> 节点的id值为Mapper 接口中的方法名称,parameterType 值表示Mapper 对应方法的入参类型,
而resultMap 值则对应了Mapper 接口表示的返回值类型或者返回结果集的元素类型。

根据MyBatis 的配置规范配置好后,通过SqlSession.getMapper(XXXMapper.class) 方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理机制生成一个Mapper 实例; 我们使用Mapper 接口的某一个方法时,MyBatis 会根据这个方法的方法名和参数类型,确定Statement Id,底层还是通过SqlSession.select(“statementId”,parameterObject); 或者SqlSession.update(“statementId”,parameterObject); 等等来实现对数据库的操作

MyBatis 引用Mapper 接口这种调用方式,纯粹是为了满足面向接口编程的需要。 (其实还有一个原因是在于,面向接口的编程,使得用户在接口上可以使用注解来配置SQL语句,这样就可以脱离XML配置文件,实现“0配置”)。

数据处理层

  • 数据处理层是Mybatis的核心 · 通过传入参数构建动态SQL; · SQL语句的执行以及封装查询结果集成List

  • 动态 · MyBatis 通过传入的参数值,使用 Ognl 来动态地构造SQL语句,使得MyBatis 有很强的灵活性和扩展性。 · 参数映射指的是对于java 数据类型和jdbc数据类型之间的转换:这里有包括两个过程:查询阶段,我们要将java类型的数据,转换成jdbc类型的数据,通过 preparedStatement.setXXX() 来设值;另一个就是对resultset查询结果集的jdbcType 数据转换成java 数据类型。

  • SQL语句的执行以及封装查询结果集成List · 动态SQL语句生成之后,MyBatis 将执行SQL语句,并将可能返回的结果集转换成List 列表。MyBatis 在对结果集的处理中,支持结果集关系一对多和多对一的转换,并且有两种支持方式,一种为嵌套查询语句的查询,还有一种是嵌套结果集的查询。

Mybatis核心部件

· SqlSession        作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
· Executor              MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
· StatementHandler   封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
· ParameterHandler   负责对用户传递的参数转换成JDBC Statement 所需要的参数,
· ResultSetHandler    负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
· TypeHandler          负责java数据类型和jdbc数据类型之间的映射和转换
· MappedStatement   MappedStatement维护了一条<select|update|delete|insert>节点的封装, 
· SqlSource            负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
· BoundSql             表示动态生成的SQL语句以及相应的参数信息
· Configuration        MyBatis所有的配置信息都维持在Configuration对象之中。

The code

Maven依赖

<?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>org.sukbear.www</groupId>
    <artifactId>java-se</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.3.3</version>
        </dependency>
    </dependencies>

    <build>
        <!-- 定义classpath -->
        <resources>
            <!-- resources文件 -->
            <resource>
                <directory>src/main/resources</directory>
                <!-- 是否被过滤,如果被过滤则无法使用 -->
                <filtering>false</filtering>
            </resource>
            <!-- java文件夹 -->
            <resource>
                <directory>src/main/java</directory>
                <!-- 引入映射文件等 -->
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

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>
    <settings>
        <setting name="logImpl" value="LOG4J"/>
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>
    <typeAliases>
        <!--<package name="tk.mybatis.simple.model"></package>-->
        <package name="test.model"></package>
    </typeAliases>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC">
                <property name="" value=""/>
            </transactionManager>
            <dataSource type="UNPOOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="mysql"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!-- 引入Mapper.xml -->
        <!--    用package的前提是对包下的接口,循环按接口限定名tk.mybatis.simple.mapper.UserMapper
                转换成tk/mybatis/simple/mapper/UserMapper.xml 然后以.xml后缀搜索XML资源 ,找到就解析。-->
        <!--    <mapper resource="tk/mybatis/simple/mapper/UserMapper.xml"/>
                <mapper resource="tk/mybatis/simple/mapper/DynamicMapperTest.xml"/>-->

       <!-- <mapper resource="test/xml/SysUserMapper.xml"/>-->
        <package name="tk.mybatis.simple.mapper"/>
    </mappers>
</configuration>

POJO

package tk.mybatis.simple.model;

import java.util.Date;
import java.util.List;

/**
 * user
 *
 * @author sukbear
 * @create 2018-12-10 16:21
 */
public class SysUser {
    private Long id;
    private String userName;
    private String userPassword;
    private String userEmail;
    private String userInfo;
    private byte[] headImg;
    private Date createTime;
    private SysRole role;
    private List<SysRole> roleList;
    public Long getId() {
        return id;
    }

    public List<SysRole> getRoleList() {
        return roleList;
    }

    public void setRoleList(List<SysRole> roleList) {
        this.roleList = roleList;
    }

    public SysRole getRole() {
        return role;

    }

    public void setRole(SysRole role) {
        this.role = role;
    }

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

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserPassword() {
        return userPassword;
    }

    public void setUserPassword(String userPassword) {
        this.userPassword = userPassword;
    }

    public String getUserEmail() {
        return userEmail;
    }

    public void setUserEmail(String userEmail) {
        this.userEmail = userEmail;
    }

    public String getUserInfo() {
        return userInfo;
    }

    public void setUserInfo(String userInfo) {
        this.userInfo = userInfo;
    }

    public byte[] getHeadImg() {
        return headImg;
    }

    public void setHeadImg(byte[] headImg) {
        this.headImg = headImg;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

/*    @Override
    public String toString() {
        return this.id+" "+this.userName;
    }*/
}

UserMapper.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="tk.mybatis.simple.mapper.UserMapper">
    <!--建立对象和属性的对应关系-->
    <resultMap id="userMap" type="tk.mybatis.simple.model.SysUser">
        <id property="id" column="id"/>
        <result property="userName" column="user_name"/>
        <result property="userPassword" column="user_password"/>
        <result property="userEmail" column="user_email"/>
        <result property="userInfo" column="user_info"/>
        <result property="headImg" column="head_img" jdbcType="BLOB"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    </resultMap>

    <resultMap id="roleMap" type="tk.mybatis.simple.model.SysRole">
        <id property="id" column="id"/>
        <result property="roleName" column="role_name"/>
        <result property="enabled" column="enabled"/>
        <result property="createBy" column="create_by"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
    </resultMap>

    <!-- 返回类型为对象 -->
    <!--考虑到性能,最好指定查询列,很少使用*号代替所有列 -->
    <select id="findUserByID" parameterType="int" resultType="tk.mybatis.simple.model.SysUser">
        SELECT *
        FROM sys_user
        WHERE id = #{id}
    </select>
    <!-- 返回类型为之前定义的userMap -->
    <!--考虑到性能,最好指定查询列,很少使用*号代替所有列 -->
    <select id="selectById" resultMap="userMap">
        SELECT *
        FROM sys_user
        WHERE id = #{id}
    </select>

    <!-- #{对象的属性名} 用#号(不用$)可以预编译,避免sql注入 -->
    <insert id="insert">
        INSERT INTO sys_user (
            id, user_name, user_password, user_email, user_info, head_img, create_time
        ) VALUES (
            #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
            #{createTime, jdbcType=TIMESTAMP}
        )
    </insert>
    <!--利用JDBC返回主键自增的值 {useGeneratedKeys="true"} -->
    <insert id="insert2" useGeneratedKeys="true" keyProperty="id">
        INSERT INTO sys_user (
            id, user_name, user_password, user_email, user_info, head_img, create_time
        ) VALUES (
            #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
            #{createTime, jdbcType=TIMESTAMP}
        )
    </insert>
    <!-- 使用selectKey返回主键的值 不同数据库selectKey不同 -->
    <insert id="insert3">
        INSERT INTO sys_user (
        id, user_name, user_password, user_email, user_info, head_img, create_time
        ) VALUES (
        #{id}, #{userName}, #{userPassword}, #{userEmail}, #{userInfo}, #{headImg, jdbcType=BLOB},
        #{createTime, jdbcType=TIMESTAMP}
        )
        <selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">
            SELECT last_insert_id()
        </selectKey>
    </insert>

    <select id="selectAll" resultMap="userMap">
        SELECT *
        FROM sys_user

    </select>
    <!-- -->
    <select id="selectRolesByUserId" resultMap="roleMap">
        SELECT
            r.id,
            r.role_name     roleName,
            r.enabled       enabled,
            r.create_by     createBy,
            r.create_time   createTime,
            u.user_name  AS "user.userName",
            u.user_email AS "user.userEamil"
        FROM sys_user u
            INNER JOIN sys_user_role ur ON u.id = ur.user_id
            INNER JOIN sys_role r ON ur.role_id = r.id
        WHERE u.id = #{userId}
    </select>

    <!-- 根据id更新user的信息 -->
    <update id="updateById">
        UPDATE sys_user
        SET
            user_name     = #{userName},
            user_password = #{userPassword},
            user_email    = #{userEmail},
            user_info     = #{userInfo},
            head_img      = #{headImg,jdbcType=BLOB},
            create_time   = #{createTime,jdbcType=TIMESTAMP}
        WHERE id = #{id}
    </update>
    <!-- 根据主键删除列 -->
    <delete id="deleteById">
        DELETE FROM sys_user
        WHERE id = #{id}
    </delete>

    <!-- 多个接口参数(param("userId"))-->
    <!-- 给参数配置@param注解后 mybatis自动将参数封装成Map @param的值成为key 故在SQL部分可以用配置的注解值来使用参数-->
    <!--当参数时javaBean时要通过 对象.属性  比如 (@param("obj") Object obj) 在sql使用的时候就是obj.properties -->
    <select id="selectRolesByUserIdAndRoleEnabled" resultType="tk.mybatis.simple.model.SysRole">
        SELECT
            r.id,
            r.role_name   roleName,
            r.enabled     enabled,
            r.create_by   createBy,
            r.create_time createTime
        FROM sys_user u
            INNER JOIN sys_user_role ur ON ur.user_id = u.id
            INNER JOIN sys_role r ON ur.role_id = r.id
        WHERE u.id = #{userId} AND r.enabled = #{enabled}
    </select>

    <select id="selectRolesByUserIdAndRoleEnabledUseJavaBean" resultType="tk.mybatis.simple.model.SysRole">
        SELECT
            r.id,
            r.role_name   roleName,
            r.enabled     enabled,
            r.create_by   createBy,
            r.create_time createTime
        FROM sys_user u
            INNER JOIN sys_user_role ur ON ur.user_id = u.id
            INNER JOIN sys_role r ON ur.role_id = r.id
        WHERE u.id = #{user.id} AND r.enabled = #{role.enabled}
    </select>
</mapper>

对应接口

package tk.mybatis.simple.mapper;

import org.apache.ibatis.annotations.Param;
import tk.mybatis.simple.model.SysRole;
import tk.mybatis.simple.model.SysUser;

import java.util.List;

/**
 * usermapper
 *
 * @author sukbear
 * @create 2018-12-10 16:31
 */
public interface UserMapper {
    SysUser selectById(Long id);

    int insert(SysUser sysUser);

    int insert2(SysUser sysUser);

    int insert3(SysUser sysUser);

    List<SysUser> selectAll();

    List<SysRole> selectRolesByUserId(Long userId);

    int updateById(SysUser sysUser);

    int deleteById(Long id);

    List<SysRole> selectRolesByUserIdAndRoleEnabled(@Param("userId") Long userId, @Param("enabled") Integer enabled);

    List<SysRole> selectRolesByUserIdAndRoleEnabledUseJavaBean(@Param("user") SysUser user, @Param("role") SysRole role);
}

Test

  • sqlSession基类(直接获取SqlSession)
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.BeforeClass;


import java.io.IOException;
import java.io.Reader;

/**
 * provide sqlsession
 *
 * @author sukbear
 * @create 2018-12-10 16:40
 */
public class BaseMapperTest {
    private static SqlSessionFactory sqlSessionFactory;

    @BeforeClass
    public static void init() {
        try {
            Reader reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}
import org.apache.ibatis.session.SqlSession;

import org.junit.Assert;
import org.junit.Test;
import tk.mybatis.simple.mapper.UserMapper;
import tk.mybatis.simple.model.SysRole;
import tk.mybatis.simple.model.SysUser;

import java.util.Date;
import java.util.List;

/**
 * test
 *
 * @author sukbear
 * @create 2018-12-10 16:49
 */

public class UserMapperTest extends BaseMapperTest {
    /*    @Test
       // 查询测试
        public void testSelectById() {
            SqlSession sqlSession = getSqlSession();
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = userMapper.selectById(1L);
            Assert.assertNotNull(user);
            System.out.println(user.toString());
        }*/
/*    @Test
    // 插入测试
    public void insertTest() {
        SqlSession sqlSession = super.getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = new SysUser();
            user.setUserName("test1");
            user.setUserPassword("123456");
            user.setUserEmail("test@123");
            user.setUserInfo("testInfo");
            user.setHeadImg(new byte[]{1, 2});
            user.setCreateTime(new Date());

            int result = userMapper.insert2(user);
            Assert.assertEquals(1, result);
            System.out.println(user.getId());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }*/
/*    @Test
    public void selectAllTest() {
        SqlSession sqlSession = super.getSqlSession();

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        List<SysUser> userList = userMapper.selectAll();
        userList.stream().forEach(System.out::println);

        List<SysRole> roleList = userMapper.selectRolesByUserId(1L);
        roleList.stream().forEach(System.out::println);
    }

    @Test
    //关联查询测试
    public void test() {
        SqlSession sqlSession = super.getSqlSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<SysRole> roleList = userMapper.selectRolesByUserId(1L);
        roleList.stream().forEach(System.out::println);
    }*/

   /* //更新测试
    @Test
    public void updateByIdTest() {
        SqlSession sqlSession = super.getSqlSession();
        try {
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            SysUser user = userMapper.selectById(1L);
            user.setUserName("admin_test");
            user.setUserEmail("admin@123");

            int result = userMapper.updateById(user);
            Assert.assertEquals(1, result);
            Assert.assertEquals("admin_test", user.getUserName());
        } finally {
            sqlSession.rollback();
            sqlSession.close();
        }
    }*/
   //删除测试
  /* @Test
   public void deleteByIdTest(){
       SqlSession sqlSession = super.getSqlSession();
       try {
           UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
           SysUser user = userMapper.selectById(1L);
           Assert.assertNotNull(user);
           Assert.assertEquals(1,userMapper.deleteById(1L));
       }finally {
           sqlSession.rollback();
           sqlSession.close();
       }
   }*/
  @Test
  public void selectRolesByUserIdAndRoleEnabledTest(){
      SqlSession sqlSession = super.getSqlSession();
      try {
          UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
          SysUser user = userMapper.selectById(1L);
          SysRole role = new SysRole();
          role.setEnabled(1);
          List<SysRole> roleList = userMapper.selectRolesByUserIdAndRoleEnabledUseJavaBean(user,role);
          Assert.assertNotNull(roleList);
      }finally {
          sqlSession.close();
      }
  }
}

参考

blog 书籍:Mybatis从入门到精通。


Comments

Content