栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Mybatis知识点全总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Mybatis知识点全总结

Mybatis知识点全总结
  • 一.什么是 MyBatis?
    • 1.框架是什么?
    • 2.MyBatis的开发流程
    • 3.JDBC的优缺点
      • 优点
      • 缺点
  • 二.MyBatis的基础知识
    • 1.引入MyBatis的Maven依赖
    • 2.创建并编写核心配置文件
      • 配置文件的详细讲解
        • 环境配置(environments)
          • 事务管理器(transactionManager)
          • 数据源(dataSource)
    • 3.创建实体类
    • 4.创建Mapper XML映射器
      • Mybatis的数据查询
    • 5.执行SQL语句
        • (1)构建 SqlSessionFactory
        • (2)从 SqlSessionFactory 中获取 SqlSession
    • 6.封装初始化工具类MybatisUtils
    • 7.设置(settings)
    • 8.SQL传参
      • 传入一个参数时的写法
      • 要传入多个参数时的写法
    • 9.多表关联查询
      • 获取多表关联查询结果
    • 10.ResultMap结果映射
    • 11.Mybatis的数据插入、修改与删除的操作
      • MySQL相关知识拓展----事务
        • (1)事务简介
        • (2)事务的ACID属性(事务的特点)
        • (3)提交事务
        • (4)回滚事务
        • (5)事务之间的隔离级别
      • Mybatis数据插入操作
        • selectKey 元素的属性
        • useGeneratedKeys属性的用法
      • 数据的更新与删除操作
      • 12预防SQL注入攻击
        • Mybatis的两种传值方式
    • 三.Mybatis进阶-----高级特性
      • 1.Mybatis日志管理
      • 2.Mybatis动态SQL
      • 3.Mybatis二级缓存
        • 二级缓存概述
        • 二级缓存的运行规则
        • 案例演示
      • 4.Mybatis多表级联查询
      • 5.分页插件----PageHelper
          • PageHelper的使用流程
      • 6.Mybatis配置C3P0连接池
      • 7.Mybatis批处理
        • 批量插入
        • 批量删除
      • 8.Mybatis注解开发
    • 四.完结感言

一.什么是 MyBatis?

MyBatis 是一款优秀的持久层框架,原名叫ibatis,后来迁移到GitHub后改名为Mybatis。它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

1.框架是什么?

框架就是一个软件,完成了部分功能。框架是一种规则,保证开发者遵循相同的方式开发程序。框架提倡“不要重复造轮子”,对基础功能进行封装。框架是可以升级和改造的,框架是安全的。但是框架只对某一个方面有用,不是全能的。

框架的优点:

  1. 极大地提高了开发效率
  2. 统一的编码规则,利于团队管理
  3. 灵活的配置,拥有更好的维护性

Mybatis是持久层框架,使用XML将SQL与程序解耦,便于维护。底层基于JDBC。

2.MyBatis的开发流程
  1. 引入MyBatis的Maven依赖
  2. 创建核心配置文件
  3. 创建实体(entity)类
  4. 创建Mapper映射文件
  5. 初始化sqlSessionFactory
  6. 利用Sqlsession对象操作数据
3.JDBC的优缺点 优点
  1. 直观,好理解
缺点
  1. 创建很多的对象(比如:Connection,Preparedstatement,ResultSet等)。
  2. 注册驱动非常麻烦。
  3. SQL语句和业务逻辑代码混在了一起,不好管理。
二.MyBatis的基础知识

后面的学习是通过案例实践来总结知识点的,这些案例要用到的资源有数据库的建库脚本,我把它上传上了我CSDN的资源文件了。链接: 数据建库脚本,我用的是MySQL数据库,关于脚本怎么使用,点开idea专业版右侧的database添加MySQL数据库后,右键选择run script后选择此文件来创建数据库。如果你不会使用,评论区或者私信联系我,我24小时在线答疑。

1.引入MyBatis的Maven依赖

使用 Maven 来构建项目,则需将下面的依赖代码配置于 pom.xml 文件中,还要导入jdbc驱动和其他的依赖,这里不列举:


  org.mybatis
  mybatis
  x.x.x

2.创建并编写核心配置文件

XML 配置文件中包含了对 MyBatis 系统的核心设置,包括获取数据库连接实例(DataSource)以及决定事务作用域和控制方式的事务管理器(TransactionManager)等。MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。

配置文件的详细讲解

在项目的Resource文件夹下,创建一个mybatis-config.xml的核心配置文件。配置文件的名字其实也可以去其他的名字。

下面就是这个配置文档的代码的一个案例,通过后面的学习,会有更多其他配置项的详细讲解。




  
  
    
        
        
            
            
            
            
                
                
                
                
            
        
    
    
        
    

这里我们就创建好了一个最基本的mybatis配置文件了,当然,还有很多可以在 XML 文件中配置的选项,上面的示例仅罗列了最关键的部分。下面我来对里面的配置项依次解释:

首先,就是每个XML文件都有的声明:


然后定义了该配置文件的约束条件,约束了根标签为configuration和其他的一些配置项约束:


环境配置(environments)

MyBatis 可以配置多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。
不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。如果忽略了环境参数,那么将会加载默认环境
所以,如果你想连接两个数据库,就需要创建两个 SqlSessionFactory 实例,每个数据库对应一个。而如果是三个数据库,就需要三个实例,依此类推.

  • 默认使用的环境 ID(比如:default=“dev”)。
  • 每个 environment 元素定义的环境 ID(比如:id=“dev”)。
  • 事务管理器的配置(比如:type=“JDBC”)。
  • 数据源的配置(比如:type=“POOLED”)。

默认环境和环境 ID 顾名思义。 环境可以随意命名,但务必保证默认的环境 ID 要匹配其中一个环境 ID。

事务管理器(transactionManager)

在 MyBatis 中有两种类型的事务管理器(也就是 type="[JDBC|MANAGED]")

  • JDBC – 这个配置直接使用了 JDBC 的提交和回滚设施,它依赖从数据源获得的连接来管理事务作用域。
  • MANAGED – 这个配置几乎没做什么。它从不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 J2EE 应用服务器的上下文)。 默认情况下它会关闭连接。然而一些容器并不希望连接被关闭,因此需要将 closeConnection 属性设置为 false 来阻止默认的关闭行为。

  

[提示]:如果你正在使用 Spring + MyBatis,则没有必要配置事务管理器,因为 Spring 模块会使用自带的管理器来覆盖前面的配置。

数据源(dataSource)

有三种内建的数据源类型(也就是 type="[UNPOOLED|POOLED|JNDI]"):
UNPOOLED:这个数据源的实现会每次请求时打开和关闭连接。虽然有点慢,但对那些数据库连接可用性要求不高的简单应用程序来说,是一个很好的选择。
UNPOOLED 类型的数据源仅仅需要配置以下 5 种property属性:

property解释
driver这是 JDBC 驱动的 Java 类全限定名(并不是 JDBC 驱动中可能包含的数据源类)。
url这是数据库的 JDBC URL 地址。
username登录数据库的用户名。
password登录数据库的密码。
defaultTransactionIsolationLevel默认的连接事务隔离级别。
defaultNetworkTimeout等待数据库操作完成的默认网络超时时间(单位:毫秒)。

POOLED: 这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来,避免了创建新的连接实例时所必需的初始化和认证时间。 这种处理方式很流行,能使并发 Web 应用快速响应请求。

除了上述提到 UNPOOLED 下的属性外,还有更多属性用来配置 POOLED 的数据源。可以根据自己以后的需求来进行配置:

property解释
poolMaximumActiveConnections在任意时间可存在的活动(正在使用)连接数量,默认值:10
poolMaximumIdleConnections任意时间可能存在的空闲连接数。
poolMaximumCheckoutTime在被强制返回之前,池中连接被检出(checked out)时间,默认值:20000 毫秒(即 20 秒)
poolTimeToWait这是一个底层设置,如果获取连接花费了相当长的时间,连接池会打印状态日志并重新尝试获取一个连接(避免在误配置的情况下一直失败且不打印日志),默认值:20000 毫秒(即 20 秒)。
poolMaximumLocalBadConnectionTolerance这是一个关于坏连接容忍度的底层设置, 作用于每一个尝试从缓存池获取连接的线程。 如果这个线程获取到的是一个坏的连接,那么这个数据源允许这个线程尝试重新获取一个新的连接,但是这个重新尝试的次数不应该超过 poolMaximumIdleConnections 与 poolMaximumLocalBadConnectionTolerance 之和。 默认值:3(新增于 3.4.5)
poolPingQuery发送到数据库的侦测查询,用来检验连接是否正常工作并准备接受请求。默认是“NO PING QUERY SET”,这会导致多数数据库驱动出错时返回恰当的错误消息。
poolPingEnabled是否启用侦测查询。若开启,需要设置 poolPingQuery 属性为一个可执行的 SQL 语句(最好是一个速度非常快的 SQL 语句),默认值:false。
poolPingConnectionsNotUsedFor配置 poolPingQuery 的频率。可以被设置为和数据库连接超时时间一样,来避免不必要的侦测,默认值:0(即所有连接每一时刻都被侦测 — 当然仅当 poolPingEnabled 为 true 时适用)。

对于配置文件的mappers标签,我们后面再解释。

3.创建实体类

上一步,创建并编写好了配置文件。现在要创建数据表所对应的实体类。我们在Java目录下建一个org.haiexijun.entity的一个包,用来放置所有与数据表对应的实体类。这里就以数据库中的t_goods这张表为例,创建一个实体类。我们给这个实体类取名为Goods.然后按照JavaBean的相关的规范来创建字段和get、set方法。

package org.haiexijun.entity;

public class Goods {
    private Integer goodId;//商品编码
    private String title;//标题
    private String subTitle;//子标题
    private Float  originalCost;//原始的价格
    private Float currentPrice;//当前的价格
    private Float discount;//折扣率
    private Integer isFreeDelivery;//是否包邮。1包邮,0不包邮
    private Integer categoryId;//分类编号

    public Integer getGoodId() {
        return goodId;
    }

    public void setGoodId(Integer goodId) {
        this.goodId = goodId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getSubTitle() {
        return subTitle;
    }

    public void setSubTitle(String subTitle) {
        this.subTitle = subTitle;
    }

    public Float getOriginalCost() {
        return originalCost;
    }

    public void setOriginalCost(Float originalCost) {
        this.originalCost = originalCost;
    }

    public Float getCurrentPrice() {
        return currentPrice;
    }

    public void setCurrentPrice(Float currentPrice) {
        this.currentPrice = currentPrice;
    }

    public Float getDiscount() {
        return discount;
    }

    public void setDiscount(Float discount) {
        this.discount = discount;
    }

    public Integer getIsFreeDelivery() {
        return isFreeDelivery;
    }

    public void setIsFreeDelivery(Integer isFreeDelivery) {
        this.isFreeDelivery = isFreeDelivery;
    }

    public Integer getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Integer categoryId) {
        this.categoryId = categoryId;
    }
}
4.创建Mapper XML映射器

MyBatis 的真正强大在于它的语句映射,这是它的魔力所在。由于它的异常强大,映射器的 XML 文件就显得相对简单。如果拿它跟具有相同功能的 JDBC 代码进行对比,你会立即发现省掉了将近 95% 的代码。MyBatis 致力于减少使用成本,让用户能更专注于 SQL 代码。我们的SQL语句就是再在里面编写的。

在Resource包下创建mappers文件夹,在里面创建一个名为goods.xml的文件,然后对goods.xml进行如下的配置:




    
    标签进行定义查询语句,每个select标签都有一个id值,用来标识各语句。在select标签中要定义resultType属性为实体类的全类名。表示查询结果返回为指定的那一个实体entity。配置完后要在核心配置文件里面引用到这个mapper。在mybatis-config.xml根节点下面添加一个mappers节点:

    
        
    

这个节点里面,可以设置我们在goods.xml中定义好的mapper。

SQL 映射文件只有很少的几个顶级元素(按照应被定义的顺序列出)

元素解释
cache该命名空间的缓存配置。
cache-ref引用其它命名空间的缓存配置。
resultMap描述如何从数据库结果集中加载对象,是最复杂也是最强大的元素。
sql可被其它语句引用的可重用语句块。
insert映射插入语句。
update映射更新语句。
delete映射删除语句。
select映射查询语句。
Mybatis的数据查询

查询语句是 MyBatis 中最常用的元素之一——光能把数据存到数据库中价值并不大,还要能重新取出来才有用,多数应用也都是查询比修改要频繁。 MyBatis 的基本原则之一是:在每个插入、更新或删除操作之间,通常会执行多个查询操作。

Select 元素的属性:

属性描述
id在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。
resultType期望从这条语句中返回结果的类全限定名或别名。 注意,如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身的类型。 resultType 和 resultMap 之间只能同时使用一个。
resultMap对外部 resultMap 的命名引用。结果映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂的映射问题都能迎刃而解。 resultType 和 resultMap 之间只能同时使用一个。
flushCache将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖数据库驱动)。
fetchSize这是一个给驱动的建议值,尝试让驱动程序每次批量返回的结果行数等于这个设置值。 默认值为未设置(unset)(依赖驱动)。
statementType可选 STATEMENT,PREPARED 或 CALLABLE。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetTypeFORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖数据库驱动)。
databaseId如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有不带 databaseId 或匹配当前 databaseId 的语句;如果带和不带的语句都有,则不带的会被忽略。
resultOrdered这个设置仅针对嵌套结果 select 语句:如果为 true,将会假设包含了嵌套结果集或是分组,当返回一个主结果行时,就不会产生对前面结果集的引用。 这就使得在获取嵌套结果集的时候不至于内存不够用。默认值:false。
resultSets这个设置仅适用于多结果集的情况。它将列出语句执行后返回的结果集并赋予每个结果集一个名称,多个名称之间以逗号分隔。
5.执行SQL语句

前面我们对mybatis已经配置得差不多了,现在差不多就可以使用mybatis来执行SQL语句了。在项目的Test测试文件夹中创建一个MybatisTest的一个Java测试类,我们同时要到导入junit的maven依赖:

         
            junit
            junit
            4.11
            test
        

然后创建一个名为testSelectAll的测试方法,编写测试select语句的相关代码,代码如下:

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.haiexijun.entity.Goods;
import org.junit.Test;

import java.io.IOException;
import java.io.Reader;
import java.util.List;

public class MybatisTest {
    @Test
    public void testtestSelectAll() throws IOException {
        //利用Reader加载classpath下的mybatis-config.xml环形配置文件
        Reader reader=Resources.getResourceAsReader("mybatis-config.xml");
        //初始化SqlSessionFactory
        SqlSessionFactory sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
        SqlSession sqlSession=null;
        try {
            sqlSession=sqlSessionFactory.openSession();
            sqlSession.selectList("goods.selectAll");
            List goods= sqlSession.selectList("goods.selectAll");
            for (Good g:goods){
                System.out.println(g.getSubTitle());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            //如果type=”POOLED",代表连接池,close则是将连接回收到连接池中
            //如果type=“UNPOOLED",代表将连接关闭
            if (sqlSession!=null){
                sqlSession.close();
            }
        }
    }
}

运后能成功查询到相关的数据。

下面对代码进行一些步骤的解释:

(1)构建 SqlSessionFactory

每个基于 MyBatis 的应用都是以一个 SqlSessionFactory 的实例为核心的。SqlSessionFactory是Mybatis的核心对象。用于初始化Mybatis,创建SqlSession对象。要保证SqlSessionFactory在全局中唯一。

SqlSessionFactory 的实例可以通过 SqlSessionFactoryBuilder 获得。而 SqlSessionFactoryBuilder 则可以从 XML 配置文件或一个预先配置的 Configuration 实例来构建出 SqlSessionFactory 实例。

从 XML 文件中构建 SqlSessionFactory 的实例非常简单,建议使用类路径下的资源文件进行配置。 可以使用任意的输入流(Reader、InputStream)实例。
如:

String resource = "org/mybatis/example/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
(2)从 SqlSessionFactory 中获取 SqlSession

既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。

SqlSession是Mybatis操作数据库的核心对象,底层使用JDBC与数据库进行交互。 SqlSession对象提供了数据表CRUD对应的方式。

看到这里,就算完成了对Mybatis的最基本的操作了。恭喜你!入门了。但是这只是入门而已,我们仍然能发现代码的很多问题。比如,我们的代码无法保证SqlSessionFactory在全局中唯一。所以我们可以对代码做进一步的优化改善。所以下面要封装一个MybatisUtils初始化工具类来对我们的代码进一步优化。

6.封装初始化工具类MybatisUtils

在项目的main下Java下创建一个org.haiexijun.utils的工具包,用于存放我们封装的工具类。
然后再utils包下面创建一个叫做MybatisUtils的java类。代码如下:

package org.haiexijun.utils;

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

//工具类的方法和属性一般都用static关键字修饰
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory=null;
    //用于初始化静态对象
    static {
        Reader reader= null;
        try {
            reader = Resources.getResourceAsReader("mybatis-config.xml");
            sqlSessionFactory=new SqlSessionFactoryBuilder().build(reader);
        } catch (IOException e) {
            e.printStackTrace();
            //把异常抛出去,让使用到这个工具类的程序也知道我们这段代码出错了
            //ExceptionInInitializerError是初始化异常
            throw new ExceptionInInitializerError(e);
        }
    }
    //创建一个方法获取SqlSession对象
    public static SqlSession openSession(){
        return sqlSessionFactory.openSession();
    }
    //关闭(回收)SqlSession的连接的方法
    public static void closeSession(SqlSession session){
        if (session !=null){
            session.close();
        }
    }
}

我们编写好MybatisUtils初始化工具类后,我们再到之前编写的MybatisTest测试类中对它进行测试,代码如下:

    @Test
    public void testMybatisUtils(){
        SqlSession sqlSession=null;
        try {
            sqlSession=MybatisUtils.openSession();
            List goods= sqlSession.selectList("goods.selectAll");
            for (Good g:goods){
                System.out.println(g.getSubTitle());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSession(sqlSession);
        }
    }

结果显示,使用MybatisUtils工具类后,既保证了SqlSessionFactory在全局中唯一,也使我们的代码更加的直观和整洁了。

你以为到这里就结束了吗?并没有哦。我们的代码还有一个很严重的bug没有解决。我们先来对比一下数据库中的t_goods数据表的字段名和我们实体类定义的字段名。如下图:

数据库表的字段名:

Good的entity实体类的字段名:

我们会发现,有些字段的名字是相互对应的关系,如title和discount这两个字段。但如果字段的名字是由两个以上单词组成时,就不是相互对应的关系了。如good_id这个字段我们在实体里面写为goodId这种大驼峰的写法,但这种定义Mybatis无法对其识别。如果我们这时查询goodId,则查询结果全为null。解决办法就是对mybatis的核心配置文件中增加一个设置项,之后mybatis就会自动对数据表进行驼峰命名转换了。

在mybatis-config.xml中新增加如下代码:

    
        
    
7.设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。我们就是在里面设置对数据表的驼峰命名转化的。
下面我们列出一些setting的选项:

设置名描述有效值默认值
cacheEnabled全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。true 或 falsetrue
lazyLoadingEnabled延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。true 或falsefalse
aggressiveLazyLoading开启时,任一方法的调用都会加载该对象的所有延迟加载属性。 否则,每个延迟加载属性会按需加载(参考 lazyLoadTriggerMethods)。true 或 falsefalse (在 3.4.1 及之前的版本中默认为 true)
multipleResultSetsEnabled是否允许单个语句返回多结果集(需要数据库驱动支持)。true 或 falsetrue
defaultStatementTimeout设置超时时间,它决定数据库驱动等待数据库响应的秒数。任意正整数未设置 (null)
aultFetchSize为驱动的结果集获取数量(fetchSize)设置一个建议值。此参数只可以在查询设置中被覆盖。任意正整数未设置 (null)
defaultResultSetType指定语句默认的滚动策略。(新增于 3.5.2)FORWARD_ONLY或SCROLL_SENSITIVE 或 SCROLL_INSENSITIVE 或DEFAULT(等同于未设置)
safeRowBoundsEnabled是否允许在嵌套语句中使用分页(RowBounds)。如果允许使用则设置为 false。true 或falseFalse
mapUnderscoreToCamelCase是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn。true或false False
。。。、、、、、、、、、

一个配置完整的 settings 元素的示例如下:


  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

8.SQL传参

前面案例里面,有用到select,查询t_goods表的所有的数据。但是,很多时候,我们要查询的数据可能并不是全部数据,而是我们指定要查询的数据。这时候,我们就不能再像以前那样把select语句给写死了。而是根据用户的输入,动态传入参数来查询。

传入一个参数时的写法

要实现SQL传参,就要用到select元素的一个属性:parameterType,来指定参数的类型。
比如我要通过Id值来查询数据:

    
        select * from t_goods where current_price between #{min} and #{max} order by current_price limit 0,#{limit}
    

可以看到,我们把parameterType的值定义为java.util.Map,select语句要传入三个参数:min,max和limit。

在MybatisTest测试类中编写测试方法:

    @Test
    public void testSelectByPriceRange(){
        SqlSession sqlSession=null;
        try {
            sqlSession=MybatisUtils.openSession();
            Map param=new HashMap();
            param.put("min",100);
            param.put("max",500);
            param.put("limit",10);
            List goods= sqlSession.selectList("goods.selectByPriceRange",param);
            for (Good g:goods){
                System.out.println(g.getTitle()+":"+g.getCurrentPrice());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSession(sqlSession);
        }
    }

我们创建了HashMap,并传入3个键值对,这三个键值对与select语句中要传入的参数一 一对应。键名也要对应。

9.多表关联查询

在实际开发中,大量的企业级应用,都是多表联合查询所产生的一个复杂的结果集。查询的结果字段会横跨很多张表。

获取多表关联查询结果

如果要进行多表关联查询,那么查询结果的类型就不是某个具体的实体(entity)了。此时我们要把resultType设置为java.util.Map。也就是说,多表关联查询后返回的结果为map类型。

编写一条select语句,查询t_goods表和t_category这两个表的中category_id相同的结果。

    
        select g.* , c.category_name from t_goods g,t_category c
        where g.category_id = c.category_id
    

更改后运行代码,就有序了:

利用linkedHashMap,保存多表关联查询结果,Mybatis会将每条记录都包装为linkedHashMap对象。Key是字段名,value是字段对应的属性值。字段类型会根据表结构自动判断。
优点:易于拓展和使用
缺点:太过于灵活了,无法进行编译时检查。

10.ResultMap结果映射
  • ResultMap可以将查询结果映射为复杂类型的java对象
  • ResultMap适用于Java对象保存多表关联的结果
  • ResultMap支持对象关联查询等高级特性。
  • resultMap 元素是 MyBatis 中最重要最强大的元素。

写一个案例来体验一下结果映射:
上面的案例我们用linkedHashMap来保存了多表联合查询的结果。
如果此次我想要把多表联合查询的结果保存为Java对象的话,就要用到ResultMap结果映射。

  1. 先创建一个新的包:org.haiexijun.dto。
    DTO(data transfer object)数据传输对象,是一个特殊的javaBean,对原始的对象进行扩展,用于数据保存和传递。
  2. 在org.haiexijun.dto包下面创建一个叫GoodsDTO的Java类。下面是代码:
package org.haiexijun.dto;

import org.haiexijun.entity.Goods;

public class GoodsDTO {
    //Goods实体的引用
    private Goods goods=new Goods();
    //其他字段
    private String categoryName;

    public Good getGoods() {
        return goods;
    }

    public void setGoods(Good goods) {
        this.goods = goods;
    }

    public String getCategoryName() {
        return categoryName;
    }

    public void setCategoryName(String categoryName) {
        this.categoryName = categoryName;
    }
}

那么针对于这个DTO对象,如何让Mybatis自动对其进行对应的赋值呢?在这,我们就要使用ResultMap了。

  1. 配置ResultMap

(1)在goods.xml映射文件中创建新建一个resultMap节点,并对其进行配置:

    
    
        
        
        
        
        
        
        
        
        
        
        
        
    

resultMap的id属性是为了被下面的select元素引用而定义的。type表示把结果存为哪个DTO。resultMap还要顶义一些子标签,id标签是设置主键字段和属性映射,result标签是设置非主键字段与属性映射。每个子标签都有两个属性:property和column。column表示查询的字段名,property这指向了GoodsDTO里面的每个属性的名称,如果一个属性是额外的属性,则直接传入属性名。

(2)在goods.xml映射文件中新建一个select元素,并为其指定resultMap属性,属性值为上面定义的resultMap的id属性值rmGoods:

    
        select  * from t_goods
        where
        //添加1=1
        //或包裹where标签
        
        
            and category_id =#{categoryId}
        
        
            and current_price < #{currentPrice}
        
        
    

使用动态 SQL 最常见情景是根据条件包含 where 子句的一部分,用到了if 标签。如果有>和 <等一些特殊的符号,就要对符号进行转移。如:<要写成< 。1=1起占位作用,防止语法报错。或包裹一个where标签。where 元素只会在子元素返回任何内容的情况下才插入 “WHERe” 子句。而且,若子句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

然后我们在MybatisTest测试类中编写测试方法:

    @Test
    public void testDynamicSQL(){
        SqlSession sqlSession=null;
        try {
            sqlSession=MybatisUtils.openSession();
            Map param=new HashMap();
            param.put("categoryId",44);
            param.put("currenPrice",500);
            List list=sqlSession.selectList("goods.dynamicSQL",param);
            for (Goods g:list){
                System.out.println(g.getTitle());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSession(sqlSession);
        }
    }

当然,实际项目中可能不会这样用了,这里只是了解了解它的基本用法。
具体怎么用,我在以后的项目里再慢慢体会。动态SQL除了if标签外还有其他的标签。下面来简单介绍一下其他标签。

choose、when、otherwise
有时候,我们不想使用所有的条件,而只是想从多个条件中选择一个使用。针对这种情况,MyBatis 提供了 choose 元素,它有点像 Java 中的 switch 语句。

    
    select * from t_goods where goods_id = #{x}
    

有时候,在使用完insert等更新操作的语句后,只有当我们提交了事务后,才会清除缓存。如果你需要程序在执行完insert语句后就立马清除缓存而不是等commit后才清除缓存的话,就要在insert标签中设置flushCache属性的值为true。

    
        insert into t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery,category_id)
        values(#{title},#{subTitle},#{originalCost},#{currentPrice},#{discount},#{isFreeDelivery},#{categoryId})
    
4.Mybatis多表级联查询

多表级联查询和多表关联查询不一样,之前说的关联查询是指两个表通过主外键在一条SQL中完成所有数据的提取,而多表级联查询通常是指通过一个对象来获取与它关联的另外一个对象,执行的SQL语句分为多条。我们都知道,在MySQL等关系型数据库中,他们都有主键和外键,数据的关系也有一对一、一对多和多对多。

例如商品与商品详情对象有一对多的关系,商品是一的一方,详情是多的一方。详情要持有商品的主键。理清楚这个关系之后,我们就可以利用Mybatis的对象关联查询来快捷的获取商品下的所有详情,或者根据某一个详情对象得到与它对应的商品信息。

我们通过案例来体验:

打开t_goods_detail表,这张表是商品的详情信息的表,里面gd_id是自动生成的id,good_id是外键,gd_pic_ur是商品的图片,gd_order代表显示的时候他的排序前后顺序。

然后在entity包下创建t_goods_detail表对应的实体类GoodsDetail:

package org.haiexijun.entity;

public class GoodsDetail {
    private Integer gdId;
    private Integer goodsId;
    private String gdPicUrl;
    private Integer gdOrder;

    public Integer getGdId() {
        return gdId;
    }

    public void setGdId(Integer gdId) {
        this.gdId = gdId;
    }

    public Integer getGoodsId() {
        return goodsId;
    }

    public void setGoodsId(Integer goodsId) {
        this.goodsId = goodsId;
    }

    public String getGdPicUrl() {
        return gdPicUrl;
    }

    public void setGdPicUrl(String gdPicUrl) {
        this.gdPicUrl = gdPicUrl;
    }

    public Integer getGdOrder() {
        return gdOrder;
    }

    public void setGdOrder(Integer gdOrder) {
        this.gdOrder = gdOrder;
    }
}

之后,在resources下的mappers文件夹下创建一个goods_detail的xml文件。




    
    select * from t_goods limit 0,1
    

上面编写了一个 select * from t_goods_detail limit 0,1

编写测试方法:

   @Test
    public void testSelectManyTOne(){
        SqlSession session=null;
        try {
            session=MybatisUtils.openSession();
            GoodsDetail gd= session.selectOne("goodsDetail.selectManyToOne");
            System.out.println(gd);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSession(session);
        }
    }
5.分页插件----PageHelper

PageHelper是一款由中国人开发的Mybatis分页插件,该分页插件支持任何复杂的单表、多表分页。PageHelper官网:https://pagehelper.github.io/

因为这个插件的官方文档非常的详细和清晰,所以下面只做一个简单的案例来体验一下这个插件,以后如果有其他的需求,就去参考官方文档。

PageHelper的使用流程

1.引入maven依赖PageHelp和jsqlparser


    com.github.pagehelper
    pagehelper
    5.3.0

2.mybatis-config.xml增加Plugin配置

    
        
    

3.代码中使用PageHelper.startPage()来完成自动分页
先在goods.xml中编写一条查询语句:

    查询SQL@Param–参数映射@Results结果映射@Result字段映射

这里只是部分注解,如果想了解更多,请参考:https://mybatis.org/mybatis-3/zh/java-api.html

下面来写一个程序,来简单地演示:

实现我们要说明,如果使用注解,我们是不需要使用Mapper的xml文件的,取而代之,我们要创建名为Dao的包,在包中创建一系列的接口。比如GoodsDao,我们利用这些接口加上注解来替代原本的xml文件。

package org.haiexijun.dao;

import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.haiexijun.entity.Goods;

import java.util.List;

public interface GoodsDAO {
    @Select("select * from t_goods where current_price between #{min} and #{max} order by current_price limit 0,#{limit}")
    public List selectByPriceRange(@Param("min") Float min,@Param("max") Float max, @Param("limit") Integer limit);
}

然后在mybatis-config.xml中把dao到入mappers中:
有两种写法

	
        
    

或者:

    
       
   

这两种写法都行,二选一即可。package更实用,因为当dao包下有非常多的dao的时候,如果使用第一种方式导入的话,要写非常多的代码,太麻烦了。直接导入整个dao包不香吗?

到这里,就可以利用这个接口来完成数据查询的操作了。

下面编写测试方法:

    @Test
    public void testAnnotationSelect(){
        SqlSession sqlSession=null;
        try {
            sqlSession=MybatisUtils.openSession();
            GoodsDAO goodsDAO= sqlSession.getMapper(GoodsDAO.class);
             List list=goodsDAO.selectByPriceRange(100f,500f,20);
            System.out.println(list.size());
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSession(sqlSession);
        }
    }

上面是用注解来实现查询,下面再举一个例子来实现一下新增数据

和之前一样,在GoodsDao接口里面定义方法

package org.haiexijun.dao;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectKey;
import org.haiexijun.entity.Goods;

import java.util.List;

public interface GoodsDAO {

    @Insert("insert into t_goods(title, sub_title, original_cost, current_price, discount, is_free_delivery,category_id)values(#{title},#{subTitle},#{originalCost},#{currentPrice},#{discount},#{isFreeDelivery},#{categoryId})")
    @SelectKey(statement = "select last_insert_id()",before = false,keyProperty = "goodId",resultType =Integer.class)
    public int insert(Goods goods);

}

然后编写测试类来对他进行测试:

    @Test
    public void testAnnotationInsert(){
        SqlSession sqlSession=null;
        try {
            sqlSession=MybatisUtils.openSession();
            Goods goods=new Goods();
            goods.setTitle("测试商品");
            goods.setSubTitle("测试商品的子标题");
            goods.setOriginalCost(200f);
            goods.setCurrentPrice(100f);
            goods.setDiscount(0.5f);
            goods.setIsFreeDelivery(1);
            goods.setCategoryId(43);
            GoodsDAO goodsDAO=sqlSession.getMapper(GoodsDAO.class);
            goodsDAO.insert(goods);
            sqlSession.commit();
        }catch (Exception e){
            if (sqlSession!=null){
                sqlSession.rollback();
            }
            e.printStackTrace();
        }finally {
            MybatisUtils.closeSession(sqlSession);
        }
    }

对于其他的用法,需要用时,再去学习就好。

四.完结感言

敲了一个多礼拜,终于把这篇博客给敲出来了。真的很不容易呀!这篇博客到这里已经将近5万字了,真的佩服自己的毅力。但是我知道,学无止境,我肯定还有很多知识点没有概括到。路过的大佬,如果我有什么重要的知识点遗漏了,希望能在评论区告诉我,感谢你。如果发现有错别字,也欢迎指出。这篇博客的案例代码我放在GitHub上了案例代码。

感谢大家的点赞和关注!真心希望这篇博客对大家的Mybatis学习能有所帮助。
再见!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/434809.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号