6.MyBatis

文章介绍了MyBatis作为ORM工具如何简化SQL查询,对比了MyBatis与Hibernate、SpringJdbcTemplate的差异。重点讲述了MyBatis的使用,包括注解和XML配置方式,以及遇到的问题和解决方案。同时提到了SpringBean的作用域和生命周期,以及AOP在处理公共逻辑中的应用。
摘要由CSDN通过智能技术生成

一、为什么使用MyBatis

java中直接使用JDBC进行SQL查询,太麻烦,重复代码很多。

MyBatis为了方便SQL查询,设计总之比较偏向ORM方格。

1.主要思路:

  1. ORM(Object Relational Mapping) :

尝试把一张表中的一条条记录完全映射成一个个的对象。——去掉SQL

如果表结构 + SQL查询真的做简单映时,非常方便。但是如果有复杂查询时(一次涉及多表或者多表的优化比较特殊),就不好了。

2.保留SQL,简化SQL的编写

仍然是SQL那套。

Hibernate框架 偏向简化SQL的模式

MyBatis框架 偏向ORM的模式

Spring内部提供的JdbcTemplate 偏向简化SQL的模式

JPA 完全倒向了ORM的形式,建表的过程都被抽象,我们看到的只有类(我写了类,框架根据类进行建表)


官网全中文:https://mybatis.org/mybatis-3/zh/index.html

MyBatis本身独立,并不需要一定结合Spring才能使用,但我们只学习如何进行结合。

2.需要添加的依赖:

选择Spring Data JDBC,是因为导入这个依赖可以把DataSource对象注册到Spring中(默认HakiraDataSource)

选择MySQL Driver(无论是Durid or Hakira最终依赖MySQL官方提供的DataSource)

MyBatis Framework(引入了Mybatis + MybatisSpring)

3.Mybatis的使用:

  1. 通过注解使用(比较容易,但是做一些复杂功能时,不太灵活)

在UserMapper接口中,(@Mapper修饰,@Repository修饰)

@Select/@Insert +@Options/@Update/@Delete 完成SQL查询(必须掌握,大部分场景就够了)

注解有些地方实现不了:

(ResultMap的映射(表的字段名和对象的属性名称不一致的情况下,需要动态SQL拼接))

就需要通过XML的形式了。

  1. 通过XML配置文件的形式(比较规则,缺点是XML一大堆,又没有语法检查,出错不容易排查)

出现这种情况,通过添加@Repository注解,消除无限制IDEA的报错提示,实际中并没有什么作用。

一般利用XML去动态的生成SQL:

3.如果遇见如下问题:

required a bean of type....,很可能是导包错误,或者其它层没写注解,添加即可。

4.Controller层中的注解:@ResponseBody

作用是:将Controller方法返回的对象转化为指定格式后,写入到response对象的Body区,最终返回JSON或者XML

5.MyBatis XML相关文档: https://mybatis.org/mybatis-3/sqlmap-xml.html

对象中的a < - > 表中的uid

对象中的b < - > 表中的username

对象中的c < - > 表中的password

二、SSM中使用频率少,但面试会问到的

1.Spring bean 的作用域问题(生命周期)

Spring中针对一个类管理的bean,到底可以存在多久。“我”从各处,通过Spring获取bean对象,是同一个还是有什么其他规则?

(1)默认情况下,Spring Bean的作用域是单例形式(singleton)

并且,Spring创建这些单例bean,没有采用懒加载(lazy-inti : 用到的时候才进行触发)

(2)Spring Bean支持的集中作用域:

  1. singleton 单例(最常见)

  1. prototype 每次从Spring容器中get bean对象都会触发一次创建过程。每个对象都是独立对象

context.getBean(Person.class) <=> new Person( )

  1. request 以请求为单位。一次请求过程中,从开始到结尾,期间context.getBean(...)拿到的都是同一个对象。但如果是不同请求,则获取不同的对象。

  1. session 以用户session为为单位。每个用户(Session-id)都有自己的独立对象。context.getBean(...)根据不同的session,给予不同的对象。

  1. application Spring ApplicationContext中可以配置多个Application.所以,这个作用域表示每个都有自己独立的对象。

  1. websocket 一种协议方式。

  1. 自定义scope

通过@Scope("singleton")或者@Scope("prototype")来修改Bean的作用域


2.Spring启动过程:

  1. 根据不同的方式,进行BeanDefinition的加载。(来源:xml中的<bean>、扫描类的过程中发现的@Component)

  1. Bean(产生最终产品)

Bean Definition(如何生产产品的说明书)

Bean的生产必须在Bean Definition的指导下完成。

在一个ApplicationContext中,实际上就是定义好Map <id ,Bean Definition>....;

Map<Class,Bean Definition>....;

//真正的产品 (prototype一般不保存,只保存单例)

Map<id, Object>

Map<Class, Object>

  1. 针对所有singleton的bean && lazy-init = false

这就需要根据这些beanDefinition生产Bean出来

在生产过程中,有些bean的生产需要依赖另外一些bean。需要获取的另外的bean(这些bean可能已经生产过了,可能还没有。如果没有,就递归去产生另外的bean)

通常来讲,整个依赖关系应该是属性结构。所以一定可以递贵完成。

  1. spring Application启动完成

3.细分创建bean的过程

  1. 根据bean Definition 拿到合适的构造方法
  1. 默认情况下,取的是无参构造

  1. 但如果定义bean对象的类时,通过@Autowired修饰过构造方法,则这里取被修饰过的构造方法

Constructor ctor; //Constructor这个JDK反射对象

3.@Value(...)注解修饰的时候,这类Bean是通过解析配置文件得到的

2.进行Bean对象的实例化(调用上一步取得的构造方法)
  1. 如果是无参构造方法,则可以直接调用

  1. 如果不是无参构造,则需要先把 调用该构造方法需要的参数bean准备好

3.进行属性的注入(@Autowired String name/ setter方法注入)

这两种注入的效果是一样的

走另外的流程,又会导致依赖了一批bean,所以,还是取构造。

4.如果bean的类实现了某些Spring定义过的接口 XXX Aware接口

取调用指定的构造方法

5.装配beanDefinition,可以为这个类制定一个init-method

再去使用无参的方式,盗用init-method

6.至此,Bean才算初始化完成了。

4.产生一个bean的时候,有这么多lifecycle的回调,是因为:

  1. bean对象的实例化过程被交给spring创建了,导致我们没有控制权了

构造方法,属性注入必须分开,这个语言结构上就决定了

2.如果我想在bean被使用之前,做一些工作,没有地方可以做了
  1. 如果直接写在构造方法中,由于属性的注入还没有完成,所以是不行的

  1. 所以出现

一定发身在属性被注入之后,一定发生在bean被使用之前

这两个可以认为功能上基本是互相代替的

3.当我们需要一些Spring内部的信息时,可以使用Aware系列接口,让Spring把这些信息以对象的形式注入进来。

5.面试知识点

1.bean的作用域:

singleton、prototype.... 主要/默认使用singleton模式

singleton(单例)模式下,可以开启lazy-inti

2.bean的生命周期

生产bean阶段的工作: 调用构造方法(*) -> 属性注入(*) ->Aware系列接口 ->afterPropertiesSet/init-method

(*)备注的阶段,可能引起其他bean的产生

使用bean

销毁bean阶段的工作: destory-method / destory

三、总体过程

  1. 注解Mapper的过程:

  1. 拿到一个Mapper接口

  1. 拿到与之对应的XML配置文件(具体需要在Spring中配置XML的查找路径)

利用“对象代理”的原理,生成接口的实现代理对象(InvocationHandler)

然后,所有的接口的方法调用,都会调用到InvocationHandler的invoke 方法中

在这个方法中,通过JDBC完成对应的SQL操作(通过注解形式/XML配置(这个支持动态SQL的过程)

完成SQL操作后,最后完成,表的数据(字段名 = value) 映射成 -> 对象的数据(属性 = value)

利用XML中配置的ResultMap完成(如果同名,可以不去配置)

四、参数占位符 #{} 和 ${}

#{} : 预编译处理

${}: 字符直接替换

同样的指定参数 @Para("username") String name = "mxj"

@Select("select * from users where username =#{username}")

-> SQL: select * from users where username = "mxj";

//会帮我们做引号的处理,防止SQL注入

@Select("select * from users where username = ${username}")

-> SQL: select * from users where username = mxj;

//这是一个纯粹的SQL替换,这条SQL是错误的,因为没有引号,不能用


同样指定参数@Para("username") String name ="小明's笔";

@Select("select * from users where username =#{username}")

-> SQL: select * from users where username ="小明's笔"


那么什么情况下用到${...}

@Select("select * from users where username = #{username} offset ${offset} limit ${limit} ")

指定参数:

@Param("username")String name = "你好";

@Param("offset") int a = 3;

@Param("limit") int b = 30;

select * from users where username = "你好" offset 3 limit 30; // 此时就用到了$

五、AOP(Aspect Oriented Programing

  1. 编程的理念:把很多流程中的公共部分抽离出来,放在一起统一处理

  1. 实现依赖于“对象代理”

  1. 主要的应用场景: 日志打印、错误处理、事务处理

六、Spring MVC的统一处理:

Web开发过程中,有些步骤是很多地方都用到了,写在各处比较麻烦(AOP面临的问题)

这里没有使用AOP形式。

  1. 使用拦截器(Interceptor)

请求 -> Tomcat解析 -> 根据配置调用具体的Servlet对象中的Service()方法

Filter(过滤器) ->真正地进行Servlet对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值