Mybatis学习笔记

Posted *^O^*—*^O^*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mybatis学习笔记相关的知识,希望对你有一定的参考价值。

ORM框架

ORM(Object Relational Mapping),即对象关系映射。在面向对象编程语言中,将关系型数据库中的
数据与对象建立起映射关系,进而自动的完成数据与对象的互相转换:

  1. 将输入数据(即传入对象)+SQL 映射成原生 SQL
  2. 将结果集映射为返回对象,即输出对象
    ORM 把数据库映射为对象:
    数据库表(table)–> 类(class)
    记录(record,行数据)–> 对象(object)
    字段(field) --> 对象的属性(attribute)
    一般的 ORM 框架,会将数据库模型的每张表都映射为一个 Java 类。

常见的ORM框架

Mybatis
Mybatis是一种典型的半自动的 ORM 框架,所谓的半自动,是因为还需要手动的写 SQL 语句,再由框
架根据 SQL 及 传入数据来组装为要执行的 SQL。其优点为:

  1. 因为由程序员自己写 SQL,相对来说学习门槛更低,更容易入门。
  2. 更方便做 SQL的性能优化及维护。
  3. 对关系型数据库的模型要求不高,这样在做数据库模型调整时,影响不会太大。适合软件需求变更
    比较频繁的系统,因此国内系统大部分都是使用如 Mybatis 这样的半自动 ORM 框架。
    其缺陷为:
    不能跨数据库,因为写的 SQL 可能存在某数据库特有的语法或关键词
    Hibernate
    Hibernate是一种典型的全自动 ORM 框架,所谓的全自动,是 SQL 语句都不用在编写,基于框架的
    API,可以将对象自动的组装为要执行的 SQL 语句。其优点为:
  4. 全自动 ORM 框架,自动的组装为 SQL 语句。
  5. 可以跨数据库,框架提供了多套主流数据库的 SQL 生成规则。
    其缺点为:
    学习门槛更高,要学习框架 API 与 SQL 之间的转换关系
    对数据库模型依赖非常大,在软件需求变更频繁的系统中,会导致非常难以调整及维护。可能数据
    库中随便改一个表或字段的定义,Java代码中要修改几十处。
    很难定位问题,也很难进行性能优化:需要精通框架,对数据库模型设计也非常熟悉。

Mybatis整体执行步骤

  1. 根据application.properties配置,初始化数据库连接(真实的其实是执行SQL时连接)
  2. Spring能扫描到的接口,如果是带@Mapper注解,会基于Mybatis框架,将接口生成代理类
    (为什么可以直接使用接口来调用方法:代理类会注册到容器中,注入或者装配时,接口父类引用指向代理子类对象)
#指定Mybatis表和实体映射关系xml配置文件,包含表与实体的映射,字段和属性的映射,及各个sql语句
mybatis.mapper-locations=classpath:mapper/**Mapper.xml
  1. 加载Mybatis的xml映射文件

调用Mapper接口的执行流程

  1. 查找xml映射文件中,namespace 命名空间和mapper全限定名一致的文件

  2. 根据调用的方法找文件中crud标签id相等的语句块,(id和mapper方法名一致的,作为要执行的sql语句)

  3. 替换占位符
    如果有多个参数,方法参数加@Param(“变量名”)注解
    如果是Java对象,作为方法参数,对象属性名绑定占位符变量名

    一个Java对象,不使用@Param注解,在xml中,占位符写法为#(属性名)
    多个方法参数,使用@Param注解作为Java对象变量名,xml占位符的写法为#(对象绑定的变量名.属性名)

  4. 根据查询语句返回值,和要返回的id的类型返回数据

Xml中的配置项
1) 命名空间要和mapper全限定名一致
2) Crud分别为
3) 结果集映射标签
:id的值要和标签的resultMap属性值一致

Mapper接口
1) 根据全限定名查找命名空间一致的xml文件
2) 根据方法名查找crud标签,方法名和id属性值一致的SQL语句
3) 方法参数对应要替换的占位符的值 (xml映射文件,不加parameterType)

接口方法的设计

1) 方法名绑定xml中,crud标签的id
2) 方法参数为要替换的占位符的值
3) 返回类型:如果是更新(新增,修改,删除),统一设计为int,
如果是查询,统一设计为一个对象或List<类型>

Mybatis占位符

1)#{变量名}:实现原理为,先替换为带?的预编译的SQL语句,然后再以jdbc中,操作命令对象,set类型(占位符的索引,替换的值):满足预编译的特性,防止sql注入,预编译提高性能;
2) 变 量 名 : 实 现 原 理 为 , 以 字 符 串 拼 接 的 方 式 , 拼 接 预 编 译 的 s q l 语 句 , {变量名}:实现原理为,以字符串拼接的方式,拼接预编译的sql语句, sql{变量名},组织为变量前的sql字符串+${变量名}字符串+变量后的sql字符串——整个作为带?的预编译sql——存在sql注入问题,及性能问题

查询的结果集数据,如果产生了不同表的关系映射,返回的结果集对应就是多种Java类型,并且包含对象间的关系

1) 希望返回的结果集对象的类型,添加关系的对象

1对1关系,添加属性:private关系对象属性 属性名

public class Article {
    private Integer id;
    private String title;
    private String content;
    private Integer viewCount;
    private Integer userId;
    private Date createTime;
//一个文章对象绑定一个用户对象
    private User user;
}

1对多关系,添加属性:private List<关系对象属性> 属性名

public class User {
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private Boolean sex;
    private Date birthday;
    private String head;
    private Date createTime;

    private List<Article> articles;
}

2) xml映射文件中,修改sql的内容

a) 表关联查询;
b) 返回的查询字段,当前命名空间的结果集字段沿用,关联字段,全部加上统一的字段别名及前缀

3) xml映射文件中,中添加映射标签

a) 1对1的映射为
b) 1对多的映射为
属性都是一样:
Property=”对象中关联的属性名”
columnPrefix=“字段前缀”
resultMap=”关联的Mapper命名空间id.结果集映射id”(外部结果集映射写全)

    <resultMap id="BaseResultMap" type="org.example.model.Article">
        <id column="id" property="id"/>
        <result column="title" property="title"/>
        <result column="content" property="content"/>
        <result column="view_count" property="viewCount"/>
        <result column="user_id" property="userId"/>
        <result column="create_time" property="createTime"/>
        <association property="user"
                     columnPrefix="u_"
                     resultMap="org.example.mapper.UserMapper.BaseResultMap"></association>
    </resultMap>
   <resultMap id="BaseResultMap" type="org.example.model.User">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="nickname" property="nickname"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <result column="head" property="head"/>
        <result column="create_time" property="createTime"/>
        <collection property="articles"
                    columnPrefix="a_"
                    resultMap="org.example.mapper.ArticleMapper.BaseResultMap"/>
    </resultMap>
    <select id="selectById" resultMap="BaseResultMap">
        select
            a.id a_id,
            a.title a_title,
            a.content a_content,
            a.view_count a_view_count,
            a.user_id a_user_id,
            a.create_time a_create_time,
                u.id ,
                u.username ,
                u.password ,
                u.nickname,
                u.sex ,
                u.birthday ,
                u.head ,
                u.create_time
        from article a
            join user u on a.user_id=u.id
            where u.id=#{id}
    </select>

动态sql
1)
<if test=”变量名或者对象属性名 !=null”>
sql片段

满足某种条件,拼接sql的场景

    @Test
    public void selectByCondition(){
        User user = new User();
        user.setUsername("b");
//        user.setPassword("5");
        List<User> list = userMapper.selectByCondition(user);
        list.forEach(System.out::println);
    }
    <select id="selectByCondition" parameterType="org.example.model.User"
            resultMap="BaseResultMap">
        select * from user
        <where>
            <if test="username != null">
                and username=#{username}
            </if>
            <if test="password != null">
                and password=#{password}
            </if>
            <if test="nickname != null">
                and nickname=#{nickname}
            </if>
            <if test="sex != null">
                and sex=#{sex}
            </if>
            <if test="birthday != null">
                and birthday=#{birthday}
            </if>
            <if test="head != null">
                and head=#{head}
            </if>
            <if test="createTime != null">
                and create_time=#{createTime}
            </if>
        </where>
    </select>

2)

    <insert id="insert" useGeneratedKeys="true" keyProperty="id">
        insert into article
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="title != null">
                    title,
                </if>
                <if test="content != null">
                    content,
                </if>
                <if test="viewCount != null">
                    view_count,
                </if>
                <if test="userId != null">
                    user_id,
                </if>
                <if test="createTime != null">
                    create_time,
                </if>
            </trim>

            values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            <if test="title != null">
                #{title},
            </if>
            <if test="content != null">
                #{content},
            </if>
            <if test="viewCount != null">
                #{viewCount},
            </if>
            <if test="userId != null">
                #{userId},
            </if>
            <if test="createTime != null">
                #{createTime},
            </if>
        </trim>
    </insert>

3)
=
CRUD中,只要可以使用条件语句的地方,都可以使用where
4)
=
用于update修改操作
5)
集合遍历
collection:绑定方法参数中的集合,如 List,Set,Map或数组对象
item:遍历时的每一个对象
open:语句块开头的字符串
close:语句块结束的字符串
separator:每次遍历之间间隔的字符串

    <delete id="deleteByIds">
        delete  from article where id in
        <foreach collection="list" item="i" open="(" close=")" separator=",">
            #{i}
        </foreach>
    </delete>

以上是关于Mybatis学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis-05-笔记

学习笔记:python3,代码片段(2017)

mybatis学习(39):动态sql片段

mybatis学习笔记使用generator生成mybatis基础配置代码和目录结构

Mybatis学习笔记-增删改的操作 -对SqlSession的优化封装-优化代码

MyBatis学习笔记