Spring框架—Mybatis
1.Mybatis是什么
●Mybatis是一个半ORM(对象关系映射)框架,内部封装了JDBC,开发时只需要关注SQL语句本身,不用去关心加载驱动,创建连接,创建Statement等繁琐的过程,程序员直接编写SQL语句即可。
●使用XML或注解来配置和映射原生信息,将POJO映射为数据库中的记录,避免了JDBC代码和手动设置参数。
2.ORM
●ORM(Object Relation Mapping)对象关系映射,一种为了解决关系型数据库与简单java对象(POJO)的映射关系的技术。简单的说,ORM是通过使用描述对象和数据库映射的元数据,将程序中的对象自动持久化到关系型数据库中。
●Mybatis在查询关联对象(多表连接,内连接外连接)或关联集合对象时,需要手动编写sql来完成,所以称之为半自动ORM
●Hibernate属于全自动ORM映射关系,当查询关联对象或者关联对象集合时,根据对象模型直接获取。
●ORM的优点(也可以作为Mybatis的优点)
■基于SQL语句编程,不会对应用程序或数据库的现有设计造成任何影响,SQL写在xml里,解除了sql与程序代码的耦合。
■提供xml标签,支持编写动态SQL
▼静态SQL:直接写就可以了,编译器可以确定数据库要做什么(个别参数未定义也算静态sql)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WqlCrL0W-1650540924214)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/163.png)]
▼动态SQL:Mybatis的动态SQL可以让我们在xml文件中以标签的形式编写动态sql,完成逻辑判断和动态拼接的功能,提供9种动态sql标签trim|where|set|foreach|if|choose|when|otherwise|bind(原理是根据表达式的值动态拼接sql)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ycNn5zG5-1650540924215)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/164.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yHrSdTYM-1650540924216)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/165.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uWQdcZDY-1650540924217)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/166.png)]
■与JDBC相比,减少了大量的代码量,不需要手动开关连接。
■提供标签映射,支持对象与数据库ORM字段关系映射
3.JDBC的不足以及Mybatis的改进
● 数据库链接创建、释放频繁造成系统资源浪费,从而影响系统性能。
■在mybatis-congif.xml中配置数据库连接池,使用连接池管理数据库链接。
●Sql语句编写在JAVA代码中间不易维护
■将SQL语句配置在mapper.xml文件中,实现了Java和sql的隔离
●向sql语句传参麻烦,因为sql语句的where条件不一定,可能多可能少,占位符要一一对应
■Mybatis自动将java对象映射至sql语句,参数按名字分配
●结果集解析麻烦
■Mybatis自动将sql执行结果映射至java对象。
4.Mybatis原理过程
●读取mybatis配置文件—mybatis.config.xml
●加载mapper映射文件,即SQL映射文件,这个文件中配置了操作数据库的sql语句,(mapper映射文件在mybatis.config.xml中加载,每个映射文件对应数据库的一张表)
●根据配置文件信息创建sqlSessionFactory
●通过sqlSessionFactory创建sqlSession对象(该对象包含执行sql语句的所有方法)
●通过sqlSession.execute()执行数据库操作(mybatis底层定义了一个Executor接口来操作数据库,根据sqlSession传递的参数动态的生成需要执行的sql语句,同时负责查询缓存的维护)
■MappedStatement对象:在Executor接口的执行方法中有一个MappedStatement类型的参数,该参数就是对映射信息的封装,用于存储要映射的SQL语句的id,参数等信息。
■输入参数/输出参数映射:类型可以是Map、List等集合类型,也可以是基本数据类型和POJO数据类型,映射过程类似JDBC对preparedStatement对象设置参数的过程
●调用session.commit();提交事务
●调用session.close();关闭会话
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hHOobELx-1650540924219)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/167.png)]
5.Mybatis功能架构
●使用过SSM框架都应该知道,根据url找到相应的Controller方法,方法中封装着service,service封装着dao,dao层里面指定里采用mapper中的哪个方法。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TlhFPslJ-1650540924220)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/168.png)]
Mybatis架构分为三层:
●API接口层(DAO):提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库。接口层一收到调用请求就会调用数据处理层来完成具体的数据处理。这层写java的基础功能,比如是银行卡中钱增加减少,然后service层中封装为转账业务。
●数据处理层(mapper):负责具体的SQL查找,sql解析,sql执行和执行结果映射。
●基础支持层(配置问价负责的):负责最基础的功能支撑。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xQLfzCpw-1650540924220)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/169.png)]
●初始化(加载配置):一是从mybatis-config.xml中加载,再就是从Java中代码的注解进行加载。
●SQL解析:当API层(提供给外部使用的接口API,开发人员通过这些本地API来操纵数据库)接收到请求(出入SQL的IDhe对象),Mybatis会根据SQL的id找到对应的mappedStatement,然后根据传入参数对象对mappedStatement进行解析,解析后得到最终要执行的SQL语句和参数。
●SQL执行:将最终得到的SQL和参数拿到数据库执行,得到结果
●结果映射:将数据库的结果按映射配置转换,并将结果返回。
6.DBMS
●即数据库管理系统,是一种操纵数据库的大型软件。通过DBMS对数据库进行维护,常见的有Mysql,sqlService,oracle
7.预编译
●预编译指数据库驱动在发送SQL语句和参数给DBMS之前对SQL语句进行编译,这样DBMS执行SQL的时候就不需要再重新编译。
●为什么要预编译:
■JDBC使用对象PreparedStatement来抽象预编译语句,使用预编译。预编译阶段可以优化sql的执行,预编译之后的sql多数情况下可以直接执行,DBMS不需要再次编译,越复杂的sql,编译的复杂度将越大,预编译阶段可以合并多次操作为一次操作。同时预编译语句对象可以重复利用。把一个sql预编译后产生的PreparedStatement对象缓存下来,下次对于同一个sql,可以直接使用这个缓存的prepareStatement对象(Mybatis默认对所有的sql进行预编译)
■还有一个原因:防止sql注入
8.Mybatis有哪些Executor执行器
●SimpleExecutor(默认):每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
●ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就用,不存在就创建,用完后,不关闭Statement对象,而是放在Map<String,Statement>内,供下一次使用
●BatchExecutor:执行update(select不支持批处理),将所有sql都添加到批处理中(addBatch()),等待同一执行(executeBatch),它缓存了多个statement对象,每个Statement对象都是addBatch()完毕后,等待逐一executeBatch()批处理
●Mybatis配置文件中,在settings可以指定默认的ExecutorType执行器类型。也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型的参数。
9.Mybatis是否支持延迟加载,原理是什么
●延迟加载又称懒加载,是指在进行表的关联查询时,按照设置延迟规则推迟对关联对象的select查询。(例如在进行一对多查询时,只查询出一方,当程序中需要多方数据时,mybatis再发出sql语句进行查询)主要是为了减少数据库的压力。期延迟加载只是对关联对象的延迟有延迟设置。
●Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的是一对一,collection指的是一对多查询(Mybatis文件中,根据配置lazyLoadingEnable = true|false来设置是否启动延迟加载)
●原理是使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null,那么就会单独发送事先保存好的查询关联B对象的SQL,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB(),getName()方法的调用。
10.映射器
●#{}与${}
■#{}是占位符,预编译处理;${}是拼接符,字符串替换,没有预编译处理
■Mybatis在处理#{}时,#{}传入参数是以字符串传入,会将SQL中的#{}替换为?,调用perparedStatement的set方法来复制。
■#{}可以有效防止SQL注入,而${}不能
■#{}的变量替换是在DBMS中,而${}的变量替换是在DBMS外
11.mapper中如何传参,mapper层与Dao层建立映射
●参数不多的时候建议使用@param注解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sj9uCgra-1650540924221)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/170.png)]
■#{}里面的名称对应的是注解Param括号里面的名字(方法是DAO层里的哦)
●当参数比较多的时候适合用Map传参
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FFYPEZGj-1650540924222)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/171.png)]
■#{}里面的对应的是Map里面key的名称
●当参数恰好都是一个类的属性时使用javaBean传参
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OvCevHRi-1650540924223)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/172.png)]
■#{}里面的对应的是User类中的属性名
12.常见操作
●如何获取生成列的主键:新增标签添加keyProperty = “ID”即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r5kPe8Fr-1650540924223)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/173.png)]
●当实体类的属性名与表中字段不一致怎么办:
■在查询语句中定义字段的别名,让别名与实体类属性一致
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EfwqVyhN-1650540924224)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/174.png)]
■使用来进行映射
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ooPlNAtB-1650540924225)(http://luxiaolumm.gitee.io/luxiao-lu-mm/pic/175.png)]
13.Mybatis接口绑定
●就是把Dao层接口中的方法与Mapper层中的Sql语句绑定,这样我们在会接调用接口方法就可以了,比原来使用sqlSession提供的方法更加灵活。
●绑定方式:
■通过xml里面写SQL来绑定,xml映射文件里面的namespace必须为接口的全路径名
■通过注解绑定:在接口的方法上加@select,@update等注解(注解里面是sql语句)
●接口调用时的要求
■Dao接口方法名与mapper.xml中的sql的id相同(第一种绑定方式)
■Dao接口输入参数类型和mapper.xml中定义的每个sql的parameterType类型相同
■Dao接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType相同
■Mapper.xml文件的namespace是mapper接口的类路径
●不同的xml映射文件中,如果配置了namespace,那么id可以重复,因为namespace+id是作为Map<String,MappedStatement>的key 使用的,不会重复即可
●接口就是Dao层,其原理就是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成Proxy对象,代理对象proxy会拦截接口方法,转而执行mappedStatement所代表的sql,并将sql接口返回(Dao里的方法不能重载,因为是全限名+方法名的保存查找策略)
14.Mybatis的一级、二级缓存
●一级缓存:基于HashMap本地缓存,其存储作用域为session,当session flush或close后,该session中的所有Cache就清空。默认打开一级缓存,在同一个SQLSession中,执行相同的SQL查询时,第一次会去查数据库,并写在缓存中,第二次直接从缓存中取。HashMap的key为hashcode+statemendId+sql语句,value为查询出来的结果映射成的java对象。
●二级缓存:机制相同也是采用HashMap存储,其作用域为mapper(nameSpace),可以自定义存储源,默认不打开。第一次调用mapper下的sql会去查询用户的信息,查询到的信息存放在mapper对应的二级缓存区,第二次调用相同的sql去查用户信息,会从二级缓存中取。
●缓存更新机制:当某一个作用域(一级缓存/二级缓存)进行了C/U/D操作后,默认该作用域下所有的select中缓存全被clear●
15.Mybatis如何将sql执行结果封装为对象
●对于得到的每一列,采用别名形式,使其与每个属性对应
●然后将这个mapper的resultType改为对应类的全名。