Mybatis基础

jdbc 问题分析

  1. 数据库链接创建、释放频繁造成系统资源浪费从而影响系统性能,如果使用数据库链接池可解决此问题。
  2. Sql 语句在代码中硬编码,造成代码不易维护,实际应用 sql 变化的可能较大, sql 变动需要改变java 代码。
  3. 使用 preparedStatement 向占有位符号传参数存在硬编码,因为 sql 语句的 where 条件不一定,可能多也可能少,修改 sql 还要修改代码,系统不易维护。
  4. 对结果集解析存在硬编码(查询列名), sql 变化导致解析代码变化,系统不易维护,如果能将数据库记录封装成 pojo 对象解析比较方便

框架要解决的问题:
在这里插入图片描述
mybatis 是一个优秀的基于 java 的持久层框架,它内部封装了 jdbc,使开发者只需要关注 sql 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建 statement 等繁杂的过程。

​ mybatis 通过xml 或注解的方式将要执行的各种statement 配置起来,并通过java 对象和statement 中sql的动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql并将结果映射为 java 对象并返回。

​ 采用 ORM 思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与 jdbc api打交道,就可以完成对数据库的持久化操作。

官网

mybatis 3.5.8 API
在这里插入图片描述

一、入门

1、创建Maven工程(jar)导入坐标

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <!--引入lombok的依赖-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
      <scope>provided</scope>
    </dependency>
    <!--mysql驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>
    <!--mybatis的依赖-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.3</version>
    </dependency>
  </dependencies>

2、创建POJO

3、创建 UserDao 接口

UserDao 接口就是我们的持久层接口(也可以写成 UserMapper) .我们就写成UserDao ,具体代码如下:

public interface UserDao {
    public List<User> findAll();
}

4、创建 UserDao.xml 映射文件

注意:

  1. 映射配置文件存储的路径在resources里面,要和对应的Dao接口的路径保持一致 (创建目录使用 /)
  2. 映射配置文件的文件名必须和Dao接口名保持一致
  3. 一定要引入约束文件
<?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,一个映射配置文件,就对应一个dao接口
    根标签的namespace属性的值就对应dao接口的全限定名
-->
<mapper namespace="com.it.dao.UserDao">
    <!--
        根标签的每一个子标签就对应dao接口的每一个方法:
            查询方法就对应select标签
			添加方法就对应insert标签
			删除方法就对应delete标签
			修改方法就对应update标签
			
			标签的parameterType就对应方法的参数类型
			
        标签的id的值对应方法的名字
        标签的resultType的值就对应封装结果的类型,如果封装结果的类型是List就对应其泛型的类型
        标签体的内容就是要执行的SQL语句
    -->
    <select id="findAll" resultType="com.it.pojo.User">
        select * from t_user
    </select>
</mapper>

5、创建 SqlMapConfig.xml 配置文件(核心配置文件)

注意事项

  1. 存放路径必须是resources的根路径
  2. 配置文件的名字,随便写
  3. 一定要引入约束文件
<?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
-->
<configuration>
    <!--
        配置数据库的环境信息:
        environments: 表示里面可以配置多个环境,default表示使用哪个环境
            environment: 每一个environment表示一种环境
        为什么要配置多个环境: 因为我们有多个环境(开发环境、生产环境(真正项目之后运行的环境)、测试环境)
    -->
    <environments default="dev">
        <!--开发环境-->
        <environment id="dev">
            <!--
                事务管理者,type为JDBC表示使用JDBC的事务管理者(了解)
            -->
            <transactionManager type="JDBC"></transactionManager>
            <!--
                dataSource表示数据源,1. POOLED表示使用自带连接池  2. UNPOOLED表示不使用连接池  3. JNDI表示使用JNDI的连接池
            -->
            <dataSource type="POOLED">
                <!--连接池的配置信息-->
                <property name="username" value=""/>
                <property name="password" value=""/>
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql:///mybatis_day01?characterEncoding=utf8"/>
            </dataSource>
        </environment>
        <!--生产环境-->
        <environment id="pro">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
        <!--测试环境-->
        <environment id="test">
            <transactionManager type=""></transactionManager>
            <dataSource type=""></dataSource>
        </environment>
    </environments>

    <!--
        指定加载哪些映射配置文件: mappers
            mapper标签: 每一个mapper标签负责加载一个映射配置文件;resource指定要加载的映射配置文件的路径
    -->
    <mappers>
        <mapper resource="com/it/dao/UserDao.xml"></mapper>
    </mappers>
</configuration>

6、测试

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;

public class TestMybatis {
    @Test
    public void testFindAll() throws Exception {
        //1. 让mybatis框架去加载主配置文件
        //1.1 将主配置文件SqlMapConfig.xml转换成字节输入流 (需要关闭)
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml"); 
        //1.2 创建一个SqlSessionFactoryBuilder
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        //1.3 使用factoryBuilder对象加载字节输入流,创建SqlSessionFactory对象
        SqlSessionFactory sessionFactory = factoryBuilder.build(is); //使用了构建者模式
        //1.4 使用sessionFactory对象创建出sqlSession对象 (需要关闭)
        SqlSession sqlSession = sessionFactory.openSession(); //使用了工厂模式

        //2. 使用sqlSession对象创建出UserDao接口的代理对象
        UserDao userDao = sqlSession.getMapper(UserDao.class); //使用了动态代理

        //3. 调用userDao代理对象的findAll()方法进行查询
        List<User> userList = userDao.findAll();
        for (User user : userList) {
            System.out.println(user);
        }

        //4. 关闭资源
        sqlSession.close();
        is.close();
    }
}

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

大多数高级映射(比如:嵌套联合映射),仍然需要使用 XML 配置

事实上 MyBatis 提供的所有特性都可以利用基于 XML 的映射语言来实现,

ibatis 相关类和接口

SqlSessionFactory

在连接或数据源中创建SqlSession

SqlSessionFactory 常用方法

SqlSession openSession()

Resources 工具类

通过类加载器简化对资源的访问的类

Resources 常用方法

//以Stream对象的形式返回类路径上的资源
public static InputStream getResourceAsStream(String resource)

SqlSession 接口

用于使用MyBatis的主要Java接口。通过这个接口,您可以执行命令、获取映射器和管理事务。

SqlSession 提供了在数据库执行 SQL 命令所需的所有方法

SqlSession 常用方法

//创建绑定到这个SqlSession的映射器(mapper) 接口的代理对象
 <T> T getMapper(Class<T> type)
 

核心配置文件详解

在这里插入图片描述

1、properties

    使用properties标签引入外部的properties文件
    目的: 也是为了配置文件解耦,专门的信息就放到专门的配置文件中

jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis_day01?characterEncoding=utf-8
jdbc.user=root
jdbc.password=123

引入到核心配置文件

<configuration>
   <properties resource="jdbc.properties">
    </properties>
    <!--数据源配置-->
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="UNPOOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.user}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    ....
</configuration>

2、typeAliases

    使用typeAliases标签定义类的别名,这里面可以定义多个别名
        typeAlias就表示定义一个别名,type属性表示要定义别名的那个类的全限定名,alias表示别名

因为所有要配置别名的类基本上都写在一个包中,所以我们可以使用包扫描配置别名package
通过package标签扫描整个包,就能给该包中的所有类都配置别名,别名就是该类的类名(不区分大小写)
核心配置文件

<typeAliases>
      <typeAlias type="com.it.bean.User" alias="user"></typeAlias>
      <!--<package name="com.it.bean"/>-->
 </typeAliases>

映射配置文件

<select id="findAll" resultType="user">
    SELECT  * FROM  user
</select>

3、Mapper

批量配置(包扫描)

<mappers>
   <package name="com.itheima.dao"></package>
</mappers>

二、进阶

2.1 基本操作

2.1.1 增:

映射文件:

    <insert id="addUser" parameterType="User">
        insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
    </insert>

	<!-- 这个 sql 语句中使用#{}字符, #{}代表占位符,我们可以
	理解是原来 jdbc 部分所学的?,它们都是代表占位符, 具体的值是由 User 类的
	 username 属性来决定的。
	parameterType 属性:代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的
全名称。-->

关闭资源之前要提交事务:

		//提交事务
        sqlSession.commit();

新增用户后, 同时还要返回当前新增用户的 id 值,因为 id 是由数据库的自动增长来实现的,所以就相当于我们要在新增后将自动增长 auto_increment 的值返回。
SelectKey获取主键
在这里插入图片描述

	<!--
        resultType只有select标签才有

        我们需要在标签体的SQL语句中,获取pojo类型的参数的属性: #{属性名}


        selectKey标签: 查询主键
            keyColumn 表示要查询的列名
            keyProperty 表示要赋值的属性名
            resultType 表示查询出来的结果的类型
            order 表示在前或者在后执行
        select last_insert_id() 查询最后一个自增长的id的值,只适用与自增主键
    -->
<insert id="addUser" parameterType="User">
    <selectKey resultType="int" order="AFTER" keyProperty="uid" keyColumn="uid">
        select last_insert_id()
    </selectKey>
    insert into t_user (username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>

使用last_insert_id()函数得到自增的id

Mybatis新增数据,存在就更新,不存在就添加,Mysql避免重复插入数据的4种方式

1)ON DUPLICATE KEY UPDATE
是Mysql特有的语法,仅Mysql有效。

#-- 在原sql后面增加 ON DUPLICATE KEY UPDATE
INSERT INTO test ( id, NAME, age )
VALUES( 1, '张三', 13 ) 
	ON DUPLICATE KEY UPDATE id = 1,
	NAME = '张三',
	age = 133

ON DUPLICATE KEY UPDATE子句写的是固定值,怎么动态赋值呢?如果一次插入多条数据,怎么动态获取主键冲突所要更新的值呢?

ON DUPLICATE KEY UPDATE age = VALUES(age)
  1. ON DUPLICATE KEY UPDATE检查主键或唯一索引字段是否冲突。
  2. update的字段值与现存的字段值相同,则不更新。
  3. 动态更新字段值用VALUES(字段名称)。

2.1.2 删:

    <!--
    	int deleteById(int id);
        我们需要在标签体的SQL语句中,获取简单类型的参数,我们使用#{任意字符串}
    -->
    <delete id="deleteById" parameterType="int">
        delete from t_user where uid=#{id}
    </delete>

2.1.3 改:

	<!--void  updateUser(User user);-->
<update id="updateUser" parameterType="User">
    update t_user set username=#{username},sex=#{sex},address=#{address} where uid=#{uid}
</update>

2.1.4 模糊查询

	<!--
        模糊查询
        另外一种在SQL语句中引用方法的参数的方式:${}(直接拼接,而#{}是?占位符)
            1. 引用pojo中的属性: '${属性名}'
            2. 引用简单类型的参数: '${value}',但是高版本的mybatis中可以'${任意字符串}'
    -->
<select id="searchByUsername" parameterType="string" resultType="User">
    <!--select * from t_user where username like "%"#{username}"%"-->
    <!--select * from t_user where username like concat("%",#{username},"%")-->

    select * from t_user where username like '%${value}%'
</select>

注意如果用模糊查询的这种写法,那么${value}的写法就是固定的,不能写成其它名字。

#{}与${}的区别

  1. #{}一定不能写在引号里面,${}一定要写在引号里面
  2. 如果是pojo、map类型的参数,无论是#{}还是${}里面都是些属性名
  3. 如果是简单类型的参数,#{}里面可以写任意字符串,但是${}里面只能写value(以前的版本)
  4. 如果使用#{}引入参数的话,其实是先使用?占位符,然后再设置参数;而使用${}引入参数的话,是直接拼接SQL语句

日志的使用

我们在使用MyBatis的时候, 其实MyBatis框架会打印一些必要的日志信息, 在开发阶段这些日志信息对我们分析问题,理解代码的执行是特别有帮助的; 包括项目上线之后,我们也可以收集项目的错误日志到文件里面去; 所以我们采用专门的日志系统来处理.

1、导入坐标:

<!-- log start -->
<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.12</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.6.6</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.6</version>
</dependency>
<!-- log end -->

2、拷贝log4j.properties到resources目录

log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
#[%-5p] %t %l %d %rms:%m%n
#%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n
log4j.appender.stdout.layout.ConversionPattern=[%-5p] %t %l %d %rms:%m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=D:\\idea_project\\it_mm_backend.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS\} %-5p [%t] {%c}-%m%n

级别:error > warn > info>debug>trace

  • 开发阶段: log4j.rootLogger= debug,std,file
  • 上线之后: log4j.rootLogger= error ,file

parameterType深入

3.1 传递简单类型

单个参数,方法就以简单类型传入即可,那么在映射配置文件中的parameterType的值就是这个简单类型的别名;在SQL语句中引入简单类型的参数#{任意字符串}

User findById(int id);
<select id="findById" parameterType="int" resultType="User">
    select * from t_user where uid=#{id}
</select>

3.2 传递 pojo 对象 或者 Map

  1. 将多个参数封装到一个POJO中,那么在映射配置文件中parameterType的值就是这个POJO的全限定名或者别名; 在SQL语句中引入参数#{POJO的属性名}或者’${POJO的属性名}’
  2. 将多个参数封装到一个Map中(要封装的参数没有对应的POJO),那么在映射配置文件中parameterType的值是map; 在SQL语句中引入参数#{map的key}或者’${map的key}’
void addUser(User user);

void updateUser(Map map);
<insert id="addUser" parameterType="User">
    insert into t_user(username,sex,birthday,address) values (#{username},#{sex},#{birthday},#{address})
</insert>

<update id="updateUser" parameterType="map">
    update t_user set username=#{username},sex=#{sex} where uid=#{uid}
</update>

3.3 传递多个参数

​ 使用Param注解指定参数名称

User findByUsernameAndAddress(@Param("uname") String username, @Param("addr") String address);
<select id="findByUsernameAndAddress" resultType="User">
    select * from t_user where username=#{uname} and address=#{addr}
</select>

3.4传递 pojo 包装对象类型

pojo 包装对象:pojo 中的属性类型又是其它的pojo

​ 通过 pojo 传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。Pojo 类中包含 pojo。

​ 需求:根据用户id查询用户信息并进行分页,查询条件放到 QueryVo 的 user 属性中。

  • QueryVo

// * Vo  ViewObject 视图对象
// * QueryVo 就是封装查询视图的数据
@Data
@AllArgsConstructor
@NoArgsConstructor
public class QueryVo {
    public QueryVo(Long currentPage, Integer pageSize, User queryCondition) {
        this.currentPage = currentPage;
        this.pageSize = pageSize;
        this.queryCondition = queryCondition;
    }

    private Long currentPage;
    private Integer pageSize;
    /**
     * 查询条件
     */
    private User queryCondition;

    private Long offset;

    public Long getOffset() {
        return (currentPage - 1)*pageSize;
    }
}
  • UserDao接口
public interface UserDao {
    List<User> searchByCondition(QueryVo queryVo);
}
  • UserDao.xml文件
<select id="searchByCondition" parameterType="QueryVo" resultType="User">
    select * from t_user where sex=#{queryCondition.sex} and address=#{queryCondition.address}
    limit #{offset},#{pageSize}
</select>
  • 测试代码
@Test
public void test03(){
    SqlSession sqlSession = SqlSessionFactoryUtil.openSqlSession();
    UserDao mapper = sqlSession.getMapper(UserDao.class);

    User user = new User();
    user.setSex("男");
    user.setAddress("北京");

    QueryVo queryVo = new QueryVo(1l,5,user);
    List<User> userList = mapper.searchByCondition(queryVo);

    for (User user1 : userList) {
        System.out.println(user1);
    }

    SqlSessionFactoryUtil.commitAndClose(sqlSession);
}

2.1 动态 SQL

动态 SQL 是 MyBatis 的强大特性之一。
根据不同条件拼接 SQL 语句
使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。
借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,

2.1.1 foreach

动态 SQL 的另一个常见使用场景是对集合进行遍历(尤其是在构建 IN 条件语句的时候)。比如:

<select id="selectPostIn" resultType="domain.blog.Post">
  SELECT *
  FROM POST P
  <where>
    <foreach item="item" index="index" collection="list"
        open="ID in (" separator="," close=")" nullable="true">
          #{item}
    </foreach>
  </where>
</select>

collection - 指定集合属性的名称,这里是list
open - 指定拼接SQL的开头前缀,这里是“(”
separator - 分隔符,这里是“,”
close - 指定拼接SQL的结束尾缀,这里是“)”
item - 代表当前遍历集合中一个元素,这里是一个name
index - 索引变量

foreach 元素的功能非常强大,允许你指定一个集合,声明可以在元素体内使用的集合项(item)和索引(index)变量。它也允许你指定开头与结尾的字符串以及集合项迭代之间的分隔符。这个元素也不会错误地添加多余的分隔符,看它多智能!

你可以将任何可迭代对象(如 List、Set 等)、Map 对象或者数组对象作为集合参数传递给 foreach。当使用可迭代对象或者数组时,index 是当前迭代的序号,item 的值是本次迭代获取到的元素。当使用 Map 对象(或者 Map.Entry 对象的集合)时,index 是键,item 是值。

2.2 结果映射 (resultMap)

resultMap 元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets 数据提取代码中解放出来,并在一些情形下允许你进行一些 JDBC 不支持的操作

有时,一份 resultMap 能够代替实现同等功能的数千行代码。ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。

<select id="selectUsers" resultType="map">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

上述语句只是简单地将所有的列映射到 HashMap 的键上,这由 resultType 属性指定。虽然在大部分情况下都够用,但是 HashMap 并不是一个很好的领域模型
MyBatis 对JavaBean 或 POJO(Plain Old Java Objects,普通老式 Java 对象)都提供了支持

2.2.1 类型别名

类型别名是你的好帮手。使用它们,你就可以不用输入类的全限定名了。

<!-- mybatis-config.xml 中 -->
<typeAlias type="com.someapp.model.User" alias="User"/>

<!-- SQL 映射 XML 中 -->
<select id="selectUsers" resultType="User">
  select id, username, hashedPassword
  from some_table
  where id = #{id}
</select>

在这些情况下,MyBatis 会在幕后自动创建一个 ResultMap,再根据属性名来映射列到 JavaBean 的属性上。
这就是 ResultMap 的优秀之处——你完全可以不用显式地配置它们。

2.2.2 列名和属性名不能匹配上

1)如果列名和属性名不能匹配上,可以在 SELECT 语句中设置列别名(这是一个基本的 SQL 特性)来完成匹配。比如:

<select id="selectUsers" resultType="User">
  select
    user_id             as "id",
    user_name           as "userName",
    hashed_password     as "hashedPassword"
  from some_table
  where id = #{id}
</select>

2)解决列名不匹配的另外一种方式。

<resultMap id="userResultMap" type="User">
  <id property="id" column="user_id" />
  <result property="username" column="user_name"/>
  <result property="password" column="hashed_password"/>
</resultMap>

然后在引用它的语句中设置 resultMap 属性就行了(注意我们去掉了 resultType 属性)

<select id="selectUsers" resultMap="userResultMap">
  select user_id, user_name, hashed_password
  from some_table
  where id = #{id}
</select>

2.2.3 高级结果映射

MyBatis 创建时的一个思想是:数据库不可能永远是你所想或所需的那个样子。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,可惜它们并不都是那样。 如果能有一种数据库映射模式,完美适配所有的应用程序,那就太好了,但可惜也没有。 而 ResultMap 就是 MyBatis 对这个问题的答案。

resultMap 元素有很多子元素和一个值得深入探讨的结构

<!-- 非常复杂的语句 -->
<select id="selectBlogDetails" resultMap="detailedBlogResultMap">
  select
       B.id as blog_id,
       B.title as blog_title,
       B.author_id as blog_author_id,
       A.id as author_id,
       A.username as author_username,
       A.password as author_password,
       A.email as author_email,
       A.bio as author_bio,
       A.favourite_section as author_favourite_section,
       P.id as post_id,
       P.blog_id as post_blog_id,
       P.author_id as post_author_id,
       P.created_on as post_created_on,
       P.section as post_section,
       P.subject as post_subject,
       P.draft as draft,
       P.body as post_body,
       C.id as comment_id,
       C.post_id as comment_post_id,
       C.name as comment_name,
       C.comment as comment_text,
       T.id as tag_id,
       T.name as tag_name
  from Blog B
       left outer join Author A on B.author_id = A.id
       left outer join Post P on B.id = P.blog_id
       left outer join Comment C on P.id = C.post_id
       left outer join Post_Tag PT on PT.post_id = P.id
       left outer join Tag T on PT.tag_id = T.id
  where B.id = #{id}
</select>
<!-- 非常复杂的结果映射 -->
<resultMap id="detailedBlogResultMap" type="Blog">
  <constructor>
    <idArg column="blog_id" javaType="int"/>
  </constructor>
  <result property="title" column="blog_title"/>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
    <result property="password" column="author_password"/>
    <result property="email" column="author_email"/>
    <result property="bio" column="author_bio"/>
    <result property="favouriteSection" column="author_favourite_section"/>
  </association>
  <collection property="posts" ofType="Post">
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <collection property="tags" ofType="Tag" >
      <id property="id" column="tag_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>

resultMap 属性

id 当前命名空间中的一个唯一标识,用于标识一个结果映射。
type 类的完全限定名, 或者一个类型别名
autoMapping 如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。默认值:未设置(unset)。

resultMap 子元素

1) constructor

用于在实例化类时,注入结果到构造方法中

  • idArg - ID 参数;标记出作为 ID 的结果可以帮助提高整体性能
  • arg - 将被注入到构造方法的一个普通结果
2) id 、result

这些元素是结果映射的基础。id 和 result 元素都将一个列的值映射到一个简单数据类型(String, int, double, Date 等)的属性或字段。

这两者之间的唯一不同是,id 元素对应的属性会被标记为对象的标识符,在比较对象实例时使用。 这样可以提高整体的性能,尤其是进行缓存和嵌套结果映射(也就是连接映射)的时候。

关联
<association property="author" column="blog_author_id" javaType="Author">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
</association>

关联(association)元素处理“有一个”类型的关系。
需要指定目标属性名以及属性的javaType(很多时候 MyBatis 可以自己推断出来),在必要的情况下你还可以设置 JDBC 类型,如果你想覆盖获取结果值的过程,还可以设置类型处理器。

MyBatis 有两种不同的方式加载关联:
嵌套 Select 查询:通过执行另外一个 SQL 映射语句来加载期望的复杂类型。
嵌套结果映射:使用嵌套的结果映射来处理连接结果的重复子集。
属性:
property:映射到列结果的字段或属性。JavaBean 中给定名字的属性
javaType: 一个 Java 类的完全限定名,或一个类型别名
jdbcType: JDBC 类型,所支持的 JDBC 类型参见这个表格之前的“支持的 JDBC 类型”
typeHandler: 使用这个属性,你可以覆盖默认的类型处理器。 这个属性值是一个类型处理器实现类的完全限定名,或者是类型别名

association – 一个复杂类型的关联;许多结果将包装成这种类型

  • 嵌套结果映射 – 关联可以是 resultMap 元素,或是对其它结果映射的引用

collection – 一个复杂类型的集合

  • 嵌套结果映射 – 集合可以是 resultMap 元素,或是对其它结果映射的引用

discriminator – 使用结果值来决定使用哪个 resultMap

  • case – 基于某些值的结果映射
    – 嵌套结果映射 – case 也是一个结果映射,因此具有相同的结构和元素;或者引用其它的结果映射

column属性:引用结果集
property属性:引用JavaBean 中的属性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值