java基础巩固-宇宙第一AiYWM:为了维持生计,Spring全家桶_Part4(持久层Mybatis前半部分:概念、为什么要用(JDBC太麻烦了,所以我出来进行封装)、优缺点、使用步骤)~整起

Part1:首先,得先明确几个问题:

  • 为什么要有持久层或者说为什么要叫持久层
    • 答案就是,我想把数据永久或者长时间保存起来(因为大家直接咱们虽然说数据放到内存中读写都比较快,但是当咱们电脑断电后内存上的数据就会丢了
    • 其次,内存太贵了,用一堆内存来存效率高是高,但是咱们项目的成本也就上来了
  • MyBatis是什么?
    • Mybatis是一个半ORM(对象关系映射)框架【ORM框架: Object Relational Mapping,用于实现面向对象编程语言里不同类型系统的数据之间的转换】,它内部封装了JDBC,加载驱动、创建连接、创建statement等繁杂的过程,开发者开发时只需要关注如何编写SQL语句,可以严格控制sql执行性能,灵活度高。
      • 不同类型系统的数据之间的转换,如下图所示:Mybatis作为一个翻译官而已。
        在这里插入图片描述
      • 为什么说Mybatis是半自动ORM映射工具?它与全自动的区别在哪里?
        • Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的,而 Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM映射工具
          • Hibernate 和 MyBatis 的区别
            • 相同点:都是对jdbc的封装,都是持久层的框架,都用于dao层的开发
            • 不同点:
              • MyBatis 是一个半自动映射的框架,配置Java对象与sql语句执行结果的对应关系,多表关联关系配置简单;Hibernate 是一个全表映射的框架,配置Java对象与数据库表的对应关系,多表关联关系配置复杂
              • Hibernate 对SQL语句封装,提供了日志、缓存、级联(级联比 MyBatis 强大)等特性,此外还提供 HQL(Hibernate Query Language)操作数据库,数据库无关性支持好,但会多消耗性能。如果项目需要支持多种数据库,代码开发量少,但SQL语句优化困难;
                • Hibernate 对象/关系映射能力强,数据库无关性好,对于关系模型要求高的 软件,如果用 hibernate 开发可以节省很多代码,提高效率
              • MyBatis 需要手动编写 SQL,支持动态 SQL、处理列表、动态生成表名、支持存储过程。开发工作量相对大些。直接使用SQL语句操作数据库不支持数据库无关性【如果需要实现支持多种数据库的软件,则需要自定义多套 sql 映射文件】,但sql语句优化容易
                • Mybatis 直接编写原生态 sql,可以严格控制 sql 执行性能,灵活度高,非常适合对关系数据模型要求不高的软件开发,因为这类软件需求变化频繁,一但需求变化要求迅速输出成果。但是灵活的前提是 mybatis 无法做到数据库无关性, Mybatis 如果需要实现支持多种数据库的软件,则需要自定义多套 sql 映射文件,工作量大。
    • 作为一个半ORM框架,MyBatis 可以使用 XML 或注解来配置和映射原生信息将 POJO映射成数据库中的记录,避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。
    • 通过xml 文件或注解的方式将要执行的各种 statement 配置起来,并通过java对象和 statement中sql的动态参数进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射为java对象并返回。(从执行sql到返回result的过程)。
  • 为什么要用Mybatis框架
    在这里插入图片描述
    • 因为在框架之前,当咱们用记事本、硬盘(通过IO操作)等都不太方便
    • 由于MyBatis专注于SQL本身,灵活度高,所以比较适合对性能的要求很高,或者需求变化频繁,大型的项目,如互联网项目
    • 用JDBC操作数据库时,就是那几个固定步骤(注册数据库驱动了,获取连接等…),但是咱们细看就会发现其实当咱们项目代码多时咱们总是只要改动这个固定步骤中的某一两步(写SQL语句),其他的步骤咱们只是将上一个的其他步骤抄过来基本上就能用,所以咱们为什么要费时费力花大功夫做那些收效很低的工作呢(虽然有时候不得不这样,但是这里显然有更好的办法)。所以,框架就出来了(其实我感觉是一样的,当咱们参加复试、面试时要做简历的话,一份两份可以,如果很多份时每一份都要自己去做简历中的每条线、每个图标、每个表格,那么就有点不太划算了,而拿来一个简历模板就显得很实用),框架就是大企业用的一个大型模板喽 (Mybatis感觉就像是JDBC的升级版(简化了JDBC的操作,咱们就不用像JDBC那里一样要手动设置参数以及获取结果集)
      • JDBC:稍微复习一下:
        • 可以把MyBatis看作是JDBC的插件【插件就是在具体的执行流程插一脚(触发点、拦截器)来实现具体的功能】,只是功能越来来多,越来越强大,最后我们给了他一个新名字,叫做框架。MyBatis是对JDBC的抽象、封装
        • JDBC的执行流程:
          在这里插入图片描述
          • 注册驱动:Class.forName(“com.mysql.jdbc.Driver”);
          • 获取Connection连接:Connection con = DriverManager.getConnection(url, username, password);
          • 执行预编译:Statement stmt = con.createStatement();
          • 执行SQL:ResultSet rs = stmt.executeQuery(“SELECT * FROM …”);
          • 封装结果集:
            在这里插入图片描述
          • 释放资源:一般在finally中进行资源的释放或者说关闭
            在这里插入图片描述
      • JDBC编程有哪些不足之处,MyBatis是如何解决这些问题:

那是不是用Mybatis就只有优点没有缺点呢,肯定不是,把Mybatis的特点整理如下:

  • 优点:基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响(是不是和AOP差不多呀,我可以增强原有代码的功能,但是不用去修改原有代码,非侵入式),SQL写在XML里,解除sql与程序代码的耦合,便于统一管理,支持编写动态 SQL 语句,并可重用
    在这里插入图片描述
    • 与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接
    • 很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以 只要JDBC支持的数据库MyBatis都支持)。
    • 能够与Spring很好的集成
    • 提供映射标签,支持对象与数据库的ORM字段关系映射
    • 提供对象关系映射标签,支持对象关系组件维护
    • 程序猿DD老师关于Fluent Mybatis、原生Mybatis,、Mybatis Plus 的大对比
  • 缺点:
    • SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。
    • SQL语句依赖于数据库,导致数据库移植性差不能随意更换数据库

Part2:同样的,SSM可以说是maven项目,那肯定离不开这些步骤:【官方文档:https://mybatis.org/mybatis-3/zh/getting-started.html

  • 在pom.xml中导入依赖坐标:这里主要是导入mybatis依赖以及mysql相关的依赖(其实导依赖和咱们最开始学javaSE一样,用到的一些jar包,导进去就一劳永逸了,后面接着用就行,有新的就把新的加进去嘛)
    在这里插入图片描述
  • 写相应的配置文件:mybatis这里我觉得主要就是两类配置文件
    • 第一类配置文件:mybatis核心配置文件(起别名、(虽然名字起啥都行,但是习惯叫这个名字))(mybatis核心配置文件中的标签的顺序是有规定的
      在这里插入图片描述
      • MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系:
        • MyBatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中, <parameterMap> 标签会被解析为 ParameterMap 对象,其每个子元素会被解析为 ParameterMapping 对象。 <resultMap> 标签会被解析为 ResultMap 对象,其每个子元素会被解析为 ResultMapping 对象。每一个 <select>、<insert>、<update>、<delete> 标签均会被解析为 MappedStatement 对象,标签内的 sql 会被解析为 BoundSql 对象
        • xml 映射文件中,除了常见的 select、insert、update、delete 标签之外,还有哪些标签?
          • < resultMap > 、 < parameterMap > 、 < sql > 、 < include > 、 < selectKey >加上动态 sql 的 9 个标签, trim|where|set|foreach|if|choose|when|otherwise|bind 等,其中 为 sql 片段标签,通过 <include> 标签引入 sql 片段, <selectKey> 为不支持自增的主键生成策略标签
      • 最佳实践中,通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?
        • Dao 接口就是人们常说的 Mapper接口,接口的全限名,就是映射文件中的 namespace 的值接口的方法名,就是映射文件中 MappedStatement 的 id 值接口方法内的参数,就是传递给 sql 的参数
          • 在 MyBatis 中,每一个 <select> 、 <insert> 、 <update> 、 <delete> 标签,都会被解析为一个 MappedStatement 对象
          • Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement ,举例: com.mybatis3.mappers. StudentDao.findStudentById ,可以唯一找到 namespace 为 com.mybatis3.mappers. StudentDao 下面 id = findStudentById 的 MappedStatement 。在 MyBatis 中,每一个 < select> 、 < insert> 、 < update> 、 < delete> 标签,都会被解析为一个 MappedStatement 对象。
        • Dao 接口里的方法可以重载,但是 Mybatis 的 XML 里面的 ID 不允许重复【多个接口对应的映射必须只有一个】。【Mybatis 的 Dao 接口可以有多个重载方法,但是多个接口对应的映射必须只有一个,否则启动会报错。】
          • Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行 MappedStatement 所代表的 sql,然后将 sql 执行结果返回
          • 不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。原因就是 namespace+id 是作为 Map<String, MappedStatement> 的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同
          • Dao 接口方法可以重载,但是需要满足以下条件:
            • 仅有一个无参方法和一个有参方法
            • 多个有参方法时,参数数量必须一致。且使用相同的 @Param ,或者使用 param1 这种
        • Mapper 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 MappedStatement
          • 举个例子:com.mybatis3.mappers. StudentDao.findStudentById ,可以唯一找到 namespace 为 com.mybatis3.mappers. StudentDao 下面 id = findStudentById 的 MappedStatement 。
      • 里面的内容,主要有以下几点:
        • 首先是:用来连接数据库,为了防止写死,咱们可以写一个db.properties,然后连接DB的用户名呀、密码呀…就不用固定写死喽**(后期SSM整合,可能不会放在这里)**
          在这里插入图片描述
        • 其次:咱们Dao层的接口都要以这种形式(用resource或者class)在这里绑定好,才能被找到 (后期SSM整合,可能不会放在这里或者说不这么写)
          在这里插入图片描述
          • Mybatis获取数据源的方式:
            在这里插入图片描述
        • 然后,多环境的配置和选择:(虽然咱们配置了多个,但是每次只能用一个环境)。环境里面的datasource的type有三种:默认的连接池(数据源)就是POOLPOOL就是用完可以回收下一个人可以接着用而不是直接注销,直接注销那么其他人要用又得重新创造一个服务员,系统性能不就差了。用了POOL池子后就可以让web响应更快
          在这里插入图片描述
          在这里插入图片描述
          transactionManahger的type有两种类型:JDBC和MANAGED,MANAGED已不再用
          接下来还有个重要的日志:日志:数据库出现异常用日志排错,咱们之前不就是用System.out.println()和debug去排错呢嘛,日志和他俩是同行(原来不用日志时只会有sql语句执行的结果出来,也就是只有增删改查的记录,但是现在用了日志之后就多了)
        • mybatis的多个日志实现
          • 用STDOUT_LOGGING实现
            原来不用日志时只会有sql语句执行的结果出来,也就是只有增删改查的记录,但是现在用了日志之后就多了
          • 用LOG4J实现
            在这里插入图片描述
        • 最后一个就是起别名:
          在这里插入图片描述
    • 第二类配置文件:mybatis映射文件(就相当于咱们Dao层接口的子实现类,之前咱们不是先写好Controller->service->dao层,dao层中接口写了很多CRUD抽象方法,然后之前咱们是写子实现类去继承或者implements dao层接口并重写其中的方法。但是咱们用了框架之后相当于映射文件就是咱们dao层接口的子实现类,然后咱们在SSM中的spring配置文件中整合好后,就直接能用了):
      在这里插入图片描述
      • 通常一个Xml映射文件,都会写一个Dao接口与之对应,那么这个Dao接口的工作原理是什么?Dao接口里的方法、参数不同时,方法能重载吗?
        • Dao接口(Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。)即Mapper接口。接口的全限名就是映射文件中的namespace的值(Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名的拼接字符串作为key值,可唯一定位一个MapperStatement。)
        • 接口的方法名,就是映射文件中Mapper的Statement的id值
        • 接口方法内的参数,就是传递给sql的参数
        • Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略
      • Mybatis映射文件:XxxMapper.xml(习惯叫这种形式的名字),映射文件其实就相当于Dao层中的XxxDao.java或者有的也叫XxxMapper.java接口的子实现类(映射器MapperRegistery:用来注册绑定我们的XxxMapper映射文件)
        • 映射文件中有以下几点需要注意(使用MyBatis的Mapper接口调用时有哪些要求?):
          • Mapper接口方法名和mapper.xml中定义的每个sql的id相同
          • Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType类型相同
          • Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同
          • Mapper.xml文件中的namespace即是mapper接口的类路径。(namespace中的包名要和接口的包名一致;)
          • 增删改查标签中的一个id就是对应的是namespace中的方法名即接口中的一个方法名
            • 不同的xml映射文件,如果配置了namespace,那么id可以重复(原因是namespace+id是作为Map<String,MapperStatement>的key使用的,如果没有namespace,就剩下id,那么id重复会导致数据互相覆盖。有了namespace,自然id就可以重复,namespace不同,namespace+id自然也不同。)
            • 如果没有配置namespace,那么id不能重复
              在这里插入图片描述
        • 在Mapper中如何传递多个参数:
          • 若Dao层函数有多个参数,那么其对应的xml中,#{0}代表接收的是Dao层中的第一个参数,#{1}代表Dao中的第二个参数,以此类推
          • 使用@Param注解:在Dao层的参数中前加@Param注解,注解内的参数名为传递到Mapper中的参数名
          • 多个参数封装成Map,以HashMap的形式传递到Mapper中
      • 另外有一点就是使用like进行模糊查询:
        • 有个小问题就是模糊查询这里要多注意sql注入:

          在这里插入图片描述
          在这里插入图片描述
      • 此外,并且一般来说,我们的实体类或者数据库中的表、字段或者参数过多时,parameter中应该考虑使用Map(Map传递参数时直接在sql调用的时候取出key即可)。
        在这里插入图片描述
        //Map传递参数时可以直接在sql中取出key即可
        parameterType="map"
        
        //对象传递参数时直接在sql中取对象的属性即可
        parameterType = "Object"
        

在这里插入图片描述

  • 最后一点就是,有时候数据库中字段和实体中的属性名对应不一致时,那肯定就是找不到呀值肯定就不能顺利传过呀,不能传过来造成的结果就是存到数据库中的是个null值或者说从数据库中查的时候是个null值(因为你根本这条路没走通嘛,怎么可能存了正确的值或者取出来正确的值),所以有两种解决方案
    • 一是:用起别名标签给数据库中字段起别名,强行让一致不就行了
    • 二是:用resultMap(结果集映射)这个标签解决
      在这里插入图片描述
      比如官网举的例子,把五张表中的字段和实体中的相应属性一致对应起来
      在这里插入图片描述
      上面看完了Mybatis的配置文件们,下来唠唠:

PART3:就是咱们的 Mybatis的执行流程(MyBatis编程步骤),一起学习哈:
在这里插入图片描述
在这里插入图片描述

  • step1:读取MyBatis的核心配置文件
  • step2:加载映射文件
  • step3:构造会话工厂获取创建SqlSessionFactory :说白了就是用SqlSessionFactoryBuilder来创建获取SqlSessionFactory
    在这里插入图片描述
    在这里插入图片描述
  • step4:通过SqlSessionFactory创建SqlSession
    • SqlSessions 是由 SqlSessionFactory 实例创建的,SqlSessionFactory 对象包含创建 SqlSession 实例的各种方法。SqlSessionFactory 有六个方法创建 SqlSession 实例。
      在这里插入图片描述
    • 当 Mybatis 与一些依赖注入框架(如 Spring 或者 Guice)搭配使用时,SqlSession 将被依赖注入框架创建并注入,所以咱们不需要使用 SqlSessionFactoryBuilder 或者 SqlSessionFactory,
  • step5:通过sqlsession执行数据库操作 ,也就是执行SQL语句
    • 使用 MyBatis 的主要 Java 接口就是 SqlSession,SqlSession 在 MyBatis 中是非常强大的一个类。它包含了所有执行语句、提交或回滚事务以及获取映射器实例的方法【可以通过这个sqlsession接口来执行命令,获取映射器实例和管理事务】
    • SqlSession 类的方法大概有如下几种:
      • 语句执行方法:这些方法被 用来执行定义在 SQL 映射 XML 文件中的 SELECT、INSERT、UPDATE 和 DELETE 语句。你可以通过名字快速了解它们的作用,每一方法都接受语句的 ID 以及参数对象,参数可以是原始类型(支持自动装箱或包装类)、JavaBean、POJO 或 Map。
        在这里插入图片描述
      • 立即批量更新方法:
        在这里插入图片描述
      • 事务控制方法:
        在这里插入图片描述
      • 本地缓存:
        在这里插入图片描述
    • 调用session.commit()提交事务
    • 调用session.close()关闭会话:确保 SqlSession 被关闭,对于你打开的任何 session,你都要保证它们被妥善关闭
      在这里插入图片描述
  • step6:MappedStatement对象、输入参数映射、封装结果集
    在这里插入图片描述
    下图中这个工具类相当于将获取了一个数据库连接、获取sqlSessionFactory对象等操作给封装起来了。
    在这里插入图片描述
    再看看图中涉及到的几个对象:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

PART4:下来就是比上面还零碎的注意事项小点了:

  • 单元测试:写某个类的单元测试类,尽量让这个类的目录层级和被测试类的目录层级一致,只是测试类和被测试类的类名差了个Test而已
    在这里插入图片描述
    在这里插入图片描述
  • 另外:注意点:常见错误。读错从后向前读
    mybatis核心配置文件中少了<mappers …>
    在这里插入图片描述
    解决方法:
    在这里插入图片描述
  • 另一个常见出错点:
    在这里插入图片描述
    解决方法:在pom.xml中补充坐标依赖,maven静态资源过滤
    在这里插入图片描述
  • 另外就是有的时候咱们为了不把程序或者说连接数据库的信息写死,就引入了xxx.properties配置文件(xxx.properties配置文件:需要在Mybatis核心配置文件中引用),如下:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • #{}和${}的区别:
      • #{}是占位符,预编译处理;
      • $ {}是拼接符,字符串替换,没有预编译处理。并且 $ {}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换比如$ {driver}会被静态替换为com.mysql.jdbc. Driver
      • #{}是 sql 的参数占位符, Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?号,在 sql 执行前会调用PreparedStatement的set方法来赋值,按序给 sql 的? 号占位符设置参数值,比如 ps.setInt(0, parameterValue),#{item.name} 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 param.getItem().getName();
        • mybatis 组装 sql 语句这段代码有时候会出现性能问题,在 sql 很长的并且入参很多的时候将#{属性名}替换成?是很耗费 cpu 的
          在这里插入图片描述
          • 当入参 list 的数量达到 10 万级别的时候,cpu 就飙升到了 120%,执行了 29s,是造成线程等待的元凶,所以在使用 list 做 mapper 入参,一定要考虑上限。另外,sql 的 in 里面的数据也太多了吧,sql 太长超过 max_allow_packet 会报错的。这个 MySQL 配置,建议不要往大了改
      • Mybatis在处理时 ${}, ${}是原值传入 ,就是把{}替换成变量的值,相当于JDBC中的Statement编译
      • 变量替换后,#{} 对应的变量自动加上单引号 ‘’;
      • 变量替换后,${} 对应的变量不会加上单引号 ‘’
      • **#{} 可以有效的防止SQL注入,提高系统安全性;
      • ${} 不能防止SQL 注入**
      • #{} 的变量替换是在DBMS 中;
      • ${} 的变量替换是在 DBMS 外
  • 参数校验:有时候即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据JSR(Java Specification Requests) 是一套 JavaBean 参数校验的标准,它定义了很多常用的校验注解,我们可以直接 将这些注解加在我们 JavaBean 的属性上面,这样就可以在需要校验的时候进行校验了,非常方便。
    • 校验的时候我们实际用的是 Hibernate Validator 框架。
      • 常用的字段验证的注解
        在这里插入图片描述
      • 验证请求体:
        在这里插入图片描述
      • 验证请求参数(Path Variables 和 Request Parameters),一定一定不要忘记在类上加上 @Validated 注解了,这个参数可以告诉 Spring 去校验方法参数
        @RestController
        @RequestMapping("/api")
        @Validated
        public class PersonController {
        
            @GetMapping("/person/{id}")
            public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5,message = "超过 id 的范围了") Integer id) {
                return ResponseEntity.ok().body(id);
            }
        }
        
    • SpringBoot 项目的 spring-boot-starter-web 依赖中已经有 hibernate-validator 包,不需要引用相关依赖。可以通过 idea 插件Maven Helper 生成:
      在这里插入图片描述

巨人的肩膀:
Mybatis官方文档https://mybatis.org/mybatis-3/zh/getting-started.html
https://www.bilibili.com/video/BV1PE411i7CV?p=60
https://www.javalearn.cn/
https://javaguide.cn/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值