mybatis 学习笔记

2020-03-06/2021-06-21

1. MyBatis 入门

  • ssm 框架与三层架构

  • MyBatis 是一个持久层框架,用 Java 语言编写,使用 ORM 思想(Object Relational Mapping) 对象关系映射,就是把数据库表和实体类以及实体类的属性对应起来(实体类中的属性和数据库表的字段名称保持一致),让我们操作实体类就实现操作数据库表。

  • MyBatis 中实体类需要实现 Serializable 接口。

  • MyBatis 的环境搭建

    1. 创建 maven 工程并导入坐标
       1<dependency>
       2    <groupId>org.mybatis</groupId>
       3    <artifactId>mybatis</artifactId>
       4    <version>3.4.5</version>
       5</dependency>
       6<dependency>
       7    <groupId>mysql</groupId>
       8    <artifactId>mysql-connector-java</artifactId>
       9    <version>5.1.6</version>
      10</dependency>
      
    2. 创建实体类(javaBean),和 dao 层的接口
    3. 创建 MyBatis 的主配置文件,名字没要求,在此 SqlMapConifg.xml
       1<?xml version="1.0" encoding="UTF-8"?>
       2<!DOCTYPE configuration
       3        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
       4        "http://mybatis.org/dtd/mybatis-3-config.dtd">
       5<!-- mybatis的主配置文件 -->
       6<configuration>
       7    <!-- 配置环境 -->
       8    <environments default="mysql">
       9        <!-- 配置mysql的环境-->
      10        <environment id="mysql">
      11            <!-- 配置事务的类型-->
      12            <transactionManager type="JDBC"></transactionManager>
      13            <!-- 配置数据源(连接池) -->
      14            <dataSource type="POOLED">
      15                <!-- 配置连接数据库的4个基本信息 -->
      16                <property name="driver" value="com.mysql.jdbc.Driver"/>
      17                <property name="url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
      18                <property name="username" value="root"/>
      19                <property name="password" value="1234"/>
      20            </dataSource>
      21        </environment>
      22    </environments>
      23
      24    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
      25    <!-- 在注册映射文件时使用<mapper resource="org/xx/demo/mapper/xx.xml"/>,不需要映射文件名和接口名一样 -->
      26    <!-- 如果使用注解来配置,此处的 resources 应该用 class 来指定被注解的 dao 全限定类名 -->
      27    <mappers>
      28        <mapper resource="com/itheima/dao/IUserDao.xml"/>
      29    </mappers>
      30</configuration>
      
    4. 创建映射配置文件
       1<?xml version="1.0" encoding="UTF-8"?>
       2<!DOCTYPE mapper
       3        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       4        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
       5<mapper namespace="com.itheima.dao.IUserDao">
       6    <!--配置查询所有,id与接口中方法名一样-->
       7    <select id="findAll" resultType="com.itheima.domain.User">
       8        select * from user
       9    </select>
      10</mapper>
      
  • 环境搭建的注意事项

    • 在 MyBatis 中持久层的操作接口名称也和映射文件也叫做 Mapper(以前为 dao)
    • 在 resources 中创建目录的时候,和包不一样,需一级一级创建
    • MyBatis 映射文件的位置必须和 dao 接口的包结构相同
    • 映射配置文件的 mapper 标签 namespace 属性的取值必须是 dao 接口的全限定类名
    • 映射配置文件的操作配置(select),id 属性的取值必须是 dao 接口的方法名
    • 当我们遵循上述后 3 点之后,在开发中无需再写 dao 的实现类
  • 入门案例

     1package com.itheima.test;
     2
     3import com.itheima.dao.IUserDao;
     4import com.itheima.domain.User;
     5import org.apache.ibatis.io.Resources;
     6import org.apache.ibatis.session.SqlSession;
     7import org.apache.ibatis.session.SqlSessionFactory;
     8import org.apache.ibatis.session.SqlSessionFactoryBuilder;
     9
    10import java.io.InputStream;
    11import java.util.List;
    12
    13public class MybatisTest {
    14    public static void main(String[] args)throws Exception {
    15        //1.读取配置文件
    16        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    17        //2.创建SqlSessionFactory工厂
    18        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    19        SqlSessionFactory factory = builder.build(in);
    20        //3.使用工厂生产SqlSession对象,操作数据库对象
    21        SqlSession session = factory.openSession();
    22        //4.使用SqlSession创建Dao接口的代理对象,代理模式
    23        IUserDao userDao = session.getMapper(IUserDao.class);
    24        //5.使用代理对象执行方法
    25        List<User> users = userDao.findAll();
    26        for(User user : users){
    27            System.out.println(user);
    28        }
    29        //6.释放资源
    30        session.close();
    31        in.close();
    32    }
    33}
    

  • 使用注解的时候

    • 不需要映射配置文件
    • 主配置文件中 <mapper class="全限定类型"/>
    • 接口上使用注解 @Select("select * from user")
  • MyBatis 支持写 dao 实现类,一般不用,不简便。

    • 配置映射配置文件
    • 写 dao 的实现类,通过读取配置文件的 SQL 语句来查询
       1public class UserDaoImpl implements IUserDao {
       2    private SqlSessionFactory factory;
       3
       4    public UserDaoImpl(SqlSessionFactory factory) {
       5        this.factory = factory;
       6    }
       7
       8    public List<User> findAll() {
       9        SqlSession session = factory.openSession();
      10        List<User> users = session.selectList("com.itheima.dao.IUserDao.findAll");
      11        session.close();
      12        return users;
      13    }
      14}
      
    • 测试类
       1public static void main(String[] args) throws Exception {
       2        //1.读取配置文件
       3        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
       4        //2.创建SqlSessionFactory工厂
       5        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
       6        SqlSessionFactory factory = builder.build(in);
       7        //3.使用工厂创建dao对象
       8        UserDaoImpl userDao = new UserDaoImpl(factory);
       9        //4.使用代理对象执行方法
      10        List<User> users = userDao.findAll();
      11        for (User user : users) {
      12            System.out.println(user);
      13        }
      14        //5.释放资源
      15        in.close();
      16    }
      

2. 自定义 MyBatis 框架

  • MyBatis 在使用代理 dao 的方式实现增删改查时做了什么事情
    1. 创建代理对象
    2. 在代理对象中调用 selectList 方法
  • 执行查询所有分析
  • 创建代理对象的分析
  • 自定义 MyBatis 开发流程图

3. MyBatis 的 CRUD

  • CRUD 使用要求

    • 持久层接口和持久层接口的映射配置必须在相同的包下
    • 持久层映射配置中 mapper 标签的 namespace 属性取值必须是持久层接口的全限定类名
    • SQL 语句的配置标签 <select>,<insert>,<delete>,<update> 的 id 属性必须和持久层接口的方法名相同。
  • MyBatis 动态执行 SQL。

  • MyBatis 默认手动提交事务,需要 sqlSession.commit();

  • insert 操作:

    1<insert id="saveUser" parameterType="pers.ylq.domain.User">
    2    <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
    3        select last_insert_id();
    4    </selectKey>
    5    insert into user(username,address,sex,birthday) values(#{username},#{address},#{sex},#{birthday});
    6</insert>
    
    • parameterType 属性:用于指定传入参数的类型,全类名。
    • resultType 属性:用于指定结果集的类型(查询的每条结果要封装的类型)。简单数据类型可以随意写,能识别就好,比如 int、Integer、String、java.liang.String ,如果结果是一个类,则需要写全类名。
    • SQL 语句中使用 #{} 字符 :
      • 它代表占位符,相当于原来 JDBC 部分所学的 ?,都是用于执行语句时替换实际的数据。具体的数据是由 #{} 里面的内容决定的。
      • 语法格式就是使用 #{对象.属性} 的方式,#{user.username} 它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用 getUsername() 方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user. 而直接写 username。
    • selectKey 的作用:配置保存时获取插入的 id,id 为自增长,keyProperty 表示返回给对象的哪一个属性,keyColumn 指向表中的主键,可省略,order 表示在什么时候执行。
    • select last_insert_id() 查询上一条自增长数据的 id。
  • update 操作

    1<update id="updateUser" parameterType="pers.ylq.domain.User">
    2    update user set username=#{username},address=#{address},sex=#{sex},birthday=#{birthday} where id=#{id};
    3</update>
    
    • #{} 中的值代表 User 对象中的属性。
  • delete 操作

    1<delete id="deleteUser" parameterType="int">
    2    delete from user where id=#{id};
    3</delete>
    
    • 由于参数类型是基本类型,#{} 中内容可随意填写。
  • select 操作:

    1List<User> findAll();
    2<select id="findAll" resultType="pers.ylq.domain.User">
    3    select * from user;
    4</select>
    
    • resultType 为查询的结果封装的类型,不是方法的返回值类型。
  • 模糊查询:

    1List<User> findByName(String username);
    2<select id="findByName" parameterType="String" resultType="pers.ylq.domain.User">
    3    select * from user where username like #{name};
    4</select>
    5List<User> users = userDao.findByName("%王%");
    
    • 在传递参数的时候传递 % 可实现动态模糊查询
    1<select id="findByName" parameterType="String" resultType="pers.ylq.domain.User">
    2    select * from user where username like concat('%',#{name},'%');
    3</select>
    4List<User> users = userDao.findByName("王");
    
    • 使用 concat 函数连接参数。
    1List<User> users = userDao.findByName("王");
    2<select id="findByName" parameterType="String" resultType="pers.ylq.domain.User">
    3    select * from user where username like '%${value}%';
    4</select>
    
    • 通过 ${} 可以将 parameterType 传入的内容拼接在 SQL 中且不进行 JDBC 类型转换,${}可以接收简单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值 ${}括号中只能是 value
     1public class QueryVo implements Serializable {
     2    private User user;
     3    public User getUser() { return user; }
     4    public void setUser(User user) { this.user = user; }
     5}
     6
     7<select id="findUserByVo" resultType="pers.ylq.domain.User" parameterType="pers.ylq.domain.QueryVo">
     8    select * from user where username like #{user.username};
     9</select>
    10
    11QueryVo vo = new QueryVo();
    12User user = new User();
    13vo.setUser(user);
    14user.setUsername("%王%");
    15List<User> users = userDao.findUserByVo(vo);
    
    • 查询的参数对象中存有对象
  • MyBatis 传递多个参数

    • 传递多个参数的时候,不能使用 parameterType 指定参数类型。
    • 可以通过参数传递顺序取值
      1<select id="findByNameAndAddress" resultType="pers.ylq.domain.User">
      2    select * from user where username = #{arg0} and address = #{arg1};
      3</select>
      4
      5List<User> users = userDao.findByNameAndAddress("老王", "北京");
      
    • 在 dao 层通过注解 @Param 实现多参传递,注解中的属性为参数的名字,在 XML 中通过此名字获取参数。
      1List<User> findByNameAndAddress(@Param("username") String username, @Param("address") String address);
      2
      3<select id="findByNameAndAddress" resultType="pers.ylq.domain.User">
      4    select * from user where username = #{username} and address = #{address};
      5</select>
      6
      7List<User> users = userDao.findByNameAndAddress("老王", "北京");
      
  • 解决实体类属性和数据库列名不对应的两种方式

    • 第一种:为查询出的数据用 as 关键字起别名,别名跟实体类中名字一样,即可成功封装为对象。
    • 第二种:建立属性名和列名的对应关系,然后使用 resultMap 属性,指向此对应表即可
       1<!-- 配置 查询结果的列名和实体类的属性名的对应关系 -->
       2<!-- id为对应表的唯一标识,可以随意起名 -->
       3<resultMap id="userMap" type="pers.ylq.damain.User">
       4    <!-- 主键字段的对应 -->
       5    <id property="userId" column="id"></id>
       6    <!--非主键字段的对应-->
       7    <result property="userName" column="username"></result>
       8    <result property="userAddress" column="address"></result>
       9    <result property="userSex" column="sex"></result>
      10    <result property="userBirthday" column="birthday"></result>
      11</resultMap>
      12
      13<select id="findById" parameterType="INT" resultMap="userMap">
      14    select * from user where id = #{uid}
      15</select>
      

4. 主配置文件的配置和顺序

  • properties 标签:配置属性

    •  1<properties>
       2    <property name="driver" value="com.mysql.jdbc.Driver"/>
       3    <property name="url" value="jdbc:mysql://localhost:3306/eesy-mybatis"/>
       4    <property name="username" value="root"/>
       5    <property name="password" value="123456"/>
       6</properties>
       7<environments default="mysql">
       8    <environment id="mysql">
       9        <transactionManager type="JDBC"></transactionManager>
      10        <dataSource type="POOLED">
      11            <property name="url" value="${url}"/>
      12            <property name="driver" value="${driver}"/>
      13            <property name="username" value="${username}"/>
      14            <property name="password" value="${password}"/>
      15        </dataSource>
      16    </environment>
      17</environments>
      

      配置完成之后,可在下面通过 ${name} 取值。

    • resources 属性:用于指定配置文件的位置,是按照类路径的写法来写,并且必须存在于类路径下。

      1<properties resource="jdbcConfig.properties">
      2</properties>
      3
      4<properties resource="pers/ylq/dao/jdbcConfig.properties">
      5</properties>
      

      此文件若处于类的根路径下,因此直接写文件名就行。
      下面依旧通过 ${name} 来取值。

    • url 属性

      1<properties url="file:///C:/Users/10766/Desktop/jdbcConfig.properties">
      2</properties>
      

      URL:Uniform Resource Locator 统一资源定位符。它是可以唯一标识一个资源的位置。
      它的写法:http://localhost:8080/mybatisserver/demo1Servlet 协议 主机 端口 URI
      URI:Uniform Resource Identifier 统一资源标识符。它是在应用中可以唯一定位一个资源的。

  • settings 标签:对 MyBatis 进行一些设置,比如延迟加载。

  • typeAliases 标签:为类型起别名

    1<typeAliases>
    2    <typeAlias type="pers.ylq.domain.User" alias="user"></typeAlias>
    3</typeAliases>
    

    type 为实体类类型,alias 为别名,起了别名之后,不再区分大小写,在映射配置文件中可以用别名。
    package 标签:用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写。

    1<typeAliases>
    2    <package name="pers.ylq.domain"></package>
    3</typeAliases>
    
  • environments 标签(环境集合属性对象)

    • environment(环境子属性对象)
      • transactionManager(事务管理)
      • dataSource(数据源)
  • mappers 标签

    • mapper:指定映射的接口或者 XML 文件,因为两者路径一样,指定哪个都行。
      • resource:指定映射配置文件
      • class:指定 mapper 接口类路径,此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。
      • package:用于指定 dao 接口所在的包,当指定了之后就不需要再写 mapper 以及 resource 或者 class 了。此种方法要求 mapper 接口名称和 mapper 映射文件名称相同,且放在同一个目录中。

5. 执行过程分析(了解)

  • 分析编写 dao 实现类 MyBatis 的执行过程
  • 分析代理 dao 的执行过程

6. MyBatis 连接池及事务

  • MyBatis 提供了 3 中连接池的配置方式
    • 配置的位置:主配置文件的 DataSource 标签,type 属性。
    • 取值:
      • POOLED 采用传统的 javax.sql.DataSource 规范中的连接池,MyBatis 有针对规范的实现。
      • UNPOOLED 采用传统的获取连接的方式,虽然也实现了 DataSource 接口,但并没有使用池的思想。
      • JNDI 采用服务器提供的 JNDI 技术实现,来获取 DataSource 对象,不同服务器所能拿到的 DataSource 是不一样的。Tomcat 获取的连接池就是 dbcp 连接池。
        注意:如果不是 Web 或者 maven 的 war 工程,是不能使用的。
  • MyBatis 中事务通过 sqlsession 对象的 commit 方法和 rollback 方法实现事务的提交和回滚。
  • SqlSession openSession(boolean var1); 可通过设置参数为 true 来自动提交事务。

7. 动态 SQL

  • if 标签

    1<select id="findUserByCondition" parameterType="User" resultMap="userMap">
    2    select * from user where 1 = 1
    3    <if test="username!=null">
    4        and username=#{username}
    5    </if>
    6</select>
    
  • where 标签

     1<select id="findUserByCondition" parameterType="User" resultMap="userMap">
     2    select * from user
     3    <where>
     4        <if test="username!=null">
     5            and username=#{username}
     6        </if>
     7        <if test="sex!=null">
     8            and sex=#{sex}
     9        </if>
    10    </where>
    11</select>
    
  • foreach 标签

    1<select id="findUserByList"  resultMap="userMap">
    2    select * from user
    3    <where>
    4        <foreach collection="list" open="id in(" close=")" item="id" separator=",">
    5            #{id}
    6        </foreach>
    7    </where>
    8</select>
    
    • 如果传入的是单参数且参数类型是一个 List 的时候,collection 属性值为 list
    • 如果传入的是单参数且参数类型是一个 array 数组的时候,collection 的属性值为 array
  • SQL 标签:声明 SQL 语句,下面可以直接引入

    1<sql id="defaultUser">
    2    select * from user
    3</sql>
    4<select id="findAll" resultMap="userMap">
    5    <include refid="defaultUser"></include>
    6</select>
    

8. 多表查询

  • 一对一查询(多对一查询)
    • 有两个表,User 表和 Account 表,Account 表中有外键 uid 于 User 中 id 对应。

    • 方式一:定义一个新的类,AccountUser extends Account,还包含用户的信息字段,将返回结果封装到此类中。

    • 方式二:在 Account 类中加入 User 类的对象作为 Account 类的一个属性,定义一个 resultMap

       1<resultMap id="accountUserMap" type="Account">
       2    <id property="id" column="aid"/>
       3    <result property="uid" column="uid"/>
       4    <result property="money" column="money"/>
       5
       6    <association property="user" javaType="User">
       7        <id property="id" column="id"/>
       8        <result property="username" column="username"/>
       9        <result property="address" column="address"/>
      10        <result property="sex" column="sex"/>
      11        <result property="birthday" column="birthday"/>
      12    </association>
      13</resultMap>
      

      查询结果的 resultMap 指向此映射关系。

  • 一对多查询:
    • User 类中加入 List<Account> accounts;
       1<resultMap id="userAccountMap" type="User">
       2    <id property="id" column="id"/>
       3    <result property="username" column="username"/>
       4    <result property="address" column="address"/>
       5    <result property="sex" column="sex"/>
       6    <result property="birthday" column="birthday"/>
       7
       8    <collection property="accounts" ofType="Account">
       9        <id property="id" column="aid"/>
      10        <result property="uid" column="uid"/>
      11        <result property="money" column="money"/>
      12    </collection>
      13</resultMap>
      14
      15<select id="findAll" resultMap="userAccountMap">
      16    SELECT u.*,a.id aid,uid,money FROM USER u LEFT JOIN account a ON u.id=a.uid;
      17</select>
      
  • 多对多查询:在两个表的实体类中分别加入对方实体类的 List 集合,在各自配置文件配置 resultMap 查询即可。

9. MyBatis 延迟加载

  • 延迟加载:需要数据的时候才加载,不需要不加载。
  • 实现:先从单表查询,需要时再去从关联表关联查询。
  • 主配置文件配置:
    1<settings>
    2    <!-- 延迟加载全局开关 -->
    3    <setting name="lazyLoadingEnabled" value="true"/>
    4    <!-- 开启时,任何方法调用都会加载该对象所有属性,否则,按需加载,默认false(true in<=3.4.1)       -->
    5    <setting name="aggressiveLazyLoading" value="false"/>
    6</settings>
    
  • 实体类配置文件:
    • 一对一实现延迟加载,association 实现

       1<resultMap id="accountUserMap" type="Account">
       2    <id property="id" column="id"/>
       3    <result property="uid" column="uid"/>
       4    <result property="money" column="money"/>
       5    <association property="user" column="uid" javaType="User"
       6                 select="pers.ylq.dao.IUserDao.findById"/>
       7</resultMap>
       8
       9<select id="findAll" resultMap="accountUserMap">
      10   select * from account
      11</select>
      

      select 标签声明延迟加载调用的方法,clomu 为所传递的参数,property 指向实体类中的成员变量

    • 一对多实现延迟加载,collection 实现

       1<resultMap id="userMap" type="user">
       2    <id property="id" column="id"/>
       3    <result property="username" column="username"/>
       4    <result property="address" column="address"/>
       5    <result property="sex" column="sex"/>
       6    <result property="birthday" column="birthday"/>
       7    <collection property="accounts" ofType="Account" column="id"
       8                select="pers.ylq.dao.IAccountDao.findAccountById"/>
       9</resultMap>
      10
      11<select id="findAll" resultMap="userMap">
      12    select * from user
      13</select>
      

10. 缓存

  • MyBatis 中有一级缓存和二级缓存
  • 一级缓存:
    • 它指的是 MyBatis 中 SqlSession 对象的缓存。
    • 当我们执行查询之后,查询的结果会同时存入到 SqlSession 为我们提供一块区域中。
    • 该区域的结构是一个 Map。当我们再次查询同样的数据,MyBatis 会先去 sqlsession 中查询是否有,有的话直接拿出来用。
    • 当 SqlSession 对象消失时,MyBatis 的一级缓存也就消失了。
  • 一级缓存的清空:一级缓存是 SqlSession 范围的缓存,当调用 SqlSession 的修改,添加,删除,commit(),close() 等方法时,就会清空一级缓存。
  • 二级缓存:它指的是 MyBatis 中 SqlSessionFactory 对象的缓存。由同一个 SqlSessionFactory 对象创建的 SqlSession 共享其缓存。
  • 二级缓存的使用步骤:
    1. 让 MyBatis 框架支持二级缓存(在主配置文件中配置),默认为 true
      1<settings>
      2    <setting name="cacheEnabled" value="true"/>
      3</settings>
      
    2. 让当前的映射文件支持二级缓存(在映射配置文件中配置),<cache/>
    3. 让当前的操作支持二级缓存(在 select 标签中配置),useCache=true
  • 如果有 SqlSession 去执行相同 mapper 映射下 SQL 语句,执行 commit 提交,将会清空该 mapper 映射下的二级缓存区域的数据。
  • 二级缓存存的是数据,而不是对象,从缓存中查询数据的时候将数据封装进对象,所以多次查询获取的对象的地址是不同的。

11. MyBatis 注解开发

  • 在 MyBatis 中,CRUD 共 4 个注解

    • @Select
    • @Insert
    • @Update
    • @Delete
  • 一个接口只能使用注解或 XML 文件,无法共存,即使用注解又使用 XML 会报错。即使 mapper 中使用 class 指向注解也会报错。

  • 当实体类的成员变量名和数据库字段名不对应的时候,可以使用 @Results 来配置对应关系

    1@Select("select * from user")
    2@Results(id = "userMap", value = {
    3        @Result(id = true, property = "userId", column = "id"),
    4        @Result(property = "userName", column = "username"),
    5        @Result(property = "userAddress", column = "address"),
    6        @Result(property = "userSex", column = "sex"),
    7        @Result(property = "userBirthday", column = "birthday"),
    8})
    9List<User1> findAll();
    
    • id 为该对应关系的唯一标识,供别的方法引用。
    • @Result 中的 id=true,代表其为主键
    • @Result 实现结果集的封装。
    • 别的方法可通过 @ResultMap("id") 引用此映射关系
  • 一对一查询配置(多对一)

    • MyBatis 中没有多对一的概念,多对一是通过一对一的方式来实现的。

    • 首先在 Account 实体类中添加 User 变量,生成 getter 和 setter 方法。

    • 在接口中使用注解配置 @Result

      1@Select("select * from account")
      2@Results(id = "accountMap", value = {
      3        @Result(id = true, property = "id", column = "id"),
      4        @Result(property = "uid", column = "uid"),
      5        @Result(property = "money", column = "money"),
      6        @Result(property = "user",column = "uid",one = @One(select = "pers.ylq.dao.IUserDao.findById",fetchType = FetchType.EAGER))
      7})
      8List<Account> findAll();
      
      • 最后一个 @Result 中,property 代表实体类中的变量,column 代表要传入的数据库的列名
      • @Result 中有:One one() default @One;Many many() default @Many;,one 代表一对一,many 代表一对多,代表此对象对应几个对象。
      • @One 中的属性 select 代表要执行的语句的唯一标识。
      • fetchType 有三个取值:LAZY(延迟加载),EAGER(立即加载),DEFAULT(默认)。
  • 一对多查询配置:

    • 在 User 实体类中添加 private List<Account> accounts;

    • 配置接口的注解

       1@Select("select * from user")
       2@Results(id = "userMap", value = {
       3        @Result(id = true, property = "id", column = "id"),
       4        @Result(property = "username", column = "username"),
       5        @Result(property = "address", column = "address"),
       6        @Result(property = "sex", column = "sex"),
       7        @Result(property = "birthday", column = "birthday"),
       8        @Result(property = "accounts",column = "id",
       9                many = @Many(select = "pers.ylq.dao.IAccountDao.findAccountByUid",
      10                        fetchType = FetchType.LAZY))
      11})
      12List<User> findAll();
      
      • many 代表一对多的关系。
      • FetchType.LAZY 代表延迟加载,此属性代替了在主配置文件中 settings 中的配置。
  • 注解使用二级缓存:在 dao 层的接口上配置 @CacheNamespace(blocking=true)

  • 常用注解说明:

    • @Insert:实现新增
    • @Update:实现更新
    • @Delete:实现删除
    • @Select:实现查询
    • @Result:实现结果集封装
    • @Results:可以与 @Result 一起使用,封装多个结果集
    • @ResultMap:实现引用 @Results 定义的封装
    • @One:实现一对一结果集封装
    • @Many:实现一对多结果集封装
    • @SelectProvider: 实现动态 SQL 映射
    • @CacheNamespace:实现注解二级缓存的使用
  • @SelectProvider: 实现动态 SQL 映射

    • @SelectProvider(type = Provider.class,method = "selectProvider") 指定了一个类的 class 和类中的方法。
    • 此方法返回一个字符串,即为所要执行的 SQL 语句。
    • 1public class Provider {
      2    public String selectProvider(String name) {
      3        String sql = "select * from user where 1=1 ";
      4        if (name != null && !name.equals(" ")) {
      5            sql += " and username=#{name} ";
      6        }
      7        return sql;
      8    }
      9}
      

12. mapper 层注解

  • @Mapper, mybatis 注解
  • @Repository, sping 注解

相同点:

@Mapper 和 @Repository 都是作用在 dao 层接口,使得其生成代理对象 bean,交给 spring 容器管理

不同点:

@Mapper 不需要配置扫描地址,可以单独使用,如果有多个mapper 文件的话,可以在项目启动类中加入 @MapperScan(“mapper文件所在包”),这样就不需要每个 mapper 文件都加 @Mapper 注解了。

@Repository 需要配置扫描地址

但在 idea 中,使用 @Repository 可以消除在业务层中注入 mapper 对象时的错误


标题:mybatis 学习笔记
作者:Rainsheep
地址:HTTPS://www.rainsheep.cn/articles/2020/03/06/1583434614785.html

评论
发表评论
       
       
取消