Java面试框架——mybatis
mybatis
parameterType :在映射文件中通过parameterType指定输入 参数的类型。
resultType:在映射文件中通过resultType指定输出结果的类型。
#{}和${}:
#{}表示一个占位符号,#{}接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,#{}中可以写成value或其它名称。
#{}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
${}表示一个拼接符号,会引用sql注入,所以不建议使用${}。
${}接收输入参数,类型可以是简单类型,pojo、hashmap。
如果接收简单类型,${}中只能写成value。
${}接收pojo对象值,通过OGNL读取对象中的属性值,通过属性.属性.属性...的方式获取对象属性值。
原始 dao开发问题
1、dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。
2、调用sqlsession方法时将statement的id硬编码了
3、调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。
**
**
思路(mapper代理开发规范)

在SqlMapConfig.xml中加载mapper.xm

SqlMapConfig.xml
mybatis的全局配置文件SqlMapConfig.xml,配置内容如下:
properties(属性)
settings(全局配置参数)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境集合属性对象)
environment(环境子属性对象)
transactionManager(事务管理)
dataSource(数据源)
mappers(映射器)
properties属性
在sqlMapConfig.xml加载属性文件:
<properties resource="db.properties" ></properties>
将数据库连接参数单独配置在db.properties中,只需要在SqlMapConfig.xml中加载db.properties的属性值。
在SqlMapConfig.xml中就不需要对数据库连接参数硬编码。
将数据库连接参数只配置在db.properties中,原因:方便对参数进行统一管理,其它xml可以引用该db.properties。
settings全局参数配置
mybatis框架在运行时可以调整一些运行参数。
比如:开启二级缓存、开启延迟加载。。
<settings>
<!-- 打开延迟加载 的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载即按需要加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
typeAliases(别名)
<typeAliases>
<!-- 单个别名定义 -->
<!-- <typeAlias alias="user" type="cn.it.mybatis.po.User"/> -->
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="cn.it.mybatis.po"/>
<package name="其它包"/>
</typeAliases>
在mapper.xml中,定义很多的statement,statement需要parameterType指定输入参数的类型、需要resultType指定输出结果的映射类型。
如果在指定类型时输入类型全路径,不方便进行开发,可以针对parameterType或resultType指定的类型定义一些别名,在mapper.xml中通过别名定义,方便开发。
5.3.3.1 单个别名定义

引用别名:

5.3.3.2 批量定义别名(常用)

5.4 typeHandlers(类型处理器)
mybatis中通过typeHandlers完成jdbc类型和java类型的转换。
通常情况下,mybatis提供的类型处理器满足日常需要,不需要自定义.
5.5 mappers(映射配置)
5.5.1 通过resource加载单个映射文件

5.5.2 通过mapper接口加载单个mapper

5.5.3 批量加载mapper(推荐使用)

6 输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型。
6.1.2 定义包装类型pojo
6.1.3 mapper.xml

7 输出映射
7.1 resultType
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
7.1.1 输出简单类型

7.1.2 输出pojo对象和pojo列表
不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。
在mapper.java指定的方法返回值类型不一样:
1、输出单个pojo对象,方法返回值是单个对象类型

2、输出pojo对象list,方法返回值是List

生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 ).
7.2 resultMap
mybatis中使用resultMap完成高级输出结果映射。
7.2.1 resultMap使用方法
如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
1、定义resultMap
2、使用resultMap作为statement的输出映射类型
7.2.2 将下边的sql使用User完成映射
SELECT id id_,username username_ FROM USER WHERE id=#{value}
User类中属性名和上边查询列名不一致。
7.2.2.1 定义reusltMap

7.2.2.2 使用resultMap作为statement的输出映射类型

8 动态sql
8.1 什么是动态sql
mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
8.2 需求
用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql。
对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。
8.3 mapper.xml


8.5 sql片段
8.5.1 需求
将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段。
方便程序员进行开发。
8.5.2 定义sql片段

8.5.3 引用sql片段
在mapper.xml中定义的statement中引用sql片段:

8.1 foreach
向sql传递数组或List,mybatis使用foreach解析
8.1.1 需求
在用户查询列表和查询总数的statement中增加多个id输入查询。
sql语句如下:
两种方法:
SELECT * FROM USER WHERE id=1 OR id=10 OR id=16
SELECT * FROM USER WHERE id IN(1,10,16)
8.1.2 在输入参数类型中添加List ids传入多个id

8.1.3 修改mapper.xml
WHERE id=1 OR id=10 OR id=16
在查询条件中,查询条件定义成一个sql片段,需要修改sql片段。

resultType和resultMap实现一对一查询小结
实现一对一查询:
resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。
如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。
resultMap可以实现延迟加载,resultType无法实现延迟加载。
实现一对多查询:
mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。
使用resultType实现:
将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。
6 延迟加载
6.1 什么是延迟加载
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
需求:
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。
6.2 使用association实现延迟加载
6.2.1 需求
查询订单并且关联查询用户信息
6.2.2 mapper.xml
需要定义两个mapper的方法对应的statement。
1、只查询订单信息
SELECT * FROM orders
在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)

2、关联查询用户信息
通过上边查询到的订单信息中user_id去关联查询用户信息
使用UserMapper.xml中的findUserById

上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。
6.2.3 延迟加载resultMap
使用association中的select指定延迟加载去执行的statement的id。
<!-- 延迟加载的resultMap -->
<resultMap type="cn.it.mybatis.po.Orders" id="OrdersUserLazyLoadingResultMap">
<!--对订单信息进行映射配置 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 实现对用户信息进行延迟加载-->
<association property="user" javaType="cn.it.mybatis.po.User"
select="cn.it.mybatis.mapper.UserMapper.findUserById" column="user_id">
</association>
</resultMap>
6.2.5.2 延迟加载配置
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置:

在SqlMapConfig.xml中配置:

7 查询缓存
7.1 什么是查询缓存
mybatis提供查询缓存,用于减轻数据压力,提高数据库性能。
mybaits提供一级缓存,和二级缓存。

一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
为什么要用缓存?
如果缓存中有数据就不用从数据库中获取,大大提高系统性能。
7.2 一级缓存
7.2.1 一级缓存工作原理

7.2.2 一级缓存测试
mybatis默认支持一级缓存,不需要在配置文件去配置。
按照上边一级缓存原理步骤去测试。
7.2.3 一级缓存应用
正式开发,是将mybatis和spring进行整合开发,事务控制在service中。
一个service方法中包括 很多mapper方法调用。
service{
//开始执行时,开启事务,创建SqlSession对象
//第一次调用mapper的方法findUserById(1)
//第二次调用mapper的方法findUserById(1),从一级缓存中取数据
//方法结束,sqlSession关闭
}
如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,sqlSession就关闭,一级缓存就清空。
7.3 二级缓存
7.3.1 原理

二级缓存与一级缓存区别,二级缓存的范围更大,多个sqlSession可以共享一个UserMapper的二级缓存区域。
UserMapper有一个二级缓存区域(按namespace分) ,其它mapper也有自己的二级缓存区域(按namespace分)。每一个namespace的mapper都有一个二缓存区域,两个mapper的namespace如果相同,这两个mapper执行sql查询到数据将存在相同 的二级缓存区域中。
7.3.2 开启二级缓存
mybaits的二级缓存是mapper范围级别,除了在SqlMapConfig.xml设置二级缓存的总开关,还要在具体的mapper.xml中开启二级缓存。
在核心配置文件SqlMapConfig.xml中加入
<setting name="cacheEnabled" value="true"/>
7.3.5 useCache配置
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
总结:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
7.3.6 刷新缓存(就是清空缓存)
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache=“true” 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
如下:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
总结:一般下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。
7.4 mybatis整合ehcache
ehcache是一个分布式缓存框架。
7.4.1 分布缓存
我们系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)

不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统 开发。所以要使用分布式缓存对缓存数据进行集中管理。
mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
7.4.2 整合方法(掌握)
mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。
mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个cache接口的实现类。

mybatis默认实现cache类是:

7.4.4 整合ehcache
配置mapper中cache中的type为ehcache对cache接口的实现类型。

7.4.5 加入ehcache的配置文件
在classpath下配置ehcache.xml
7.5 二级应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
7.6 二级缓存局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
8 spring和mybatis整合
8.1 整合思路
需要spring通过单例方式管理SqlSessionFactory。
spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession。(spring和mybatis整合自动完成)
持久层的mapper都需要由spring进行管理。
8.3 sqlSessionFactory
在applicationContext.xml配置sqlSessionFactory和数据源
sqlSessionFactory在mybatis和spring的整合包下。
<!-- 加载配置文件 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 数据源,使用dbcp -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${jdbc.driver}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxActive" value="10" />
<property name="maxIdle" value="5" />
</bean>
<!-- sqlSessinFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 加载mybatis的配置文件 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml" />
<!-- 数据源 -->
<property name="dataSource" ref="dataSource" />
</bean>
8.4 原始dao开发(和spring整合后)
8.4.1 User.xml

在SqlMapconfig.xml中加载User.xml

8.4.2 dao(实现类继承SqlSessionDaoSupport)

dao接口实现类需要注入SqlSessoinFactory,通过spring进行注入。
这里spring声明配置方式,配置dao的bean:
让UserDaoImpl实现类继承SqlSessionDaoSupport

8.4.3 配置dao
在applicationContext.xml中配置dao。

8.5 mapper代理开发
8.5.1 mapper.xml和mapper.java
8.5.2 通过MapperFactoryBean创建代理对象
此方法问题:
需要针对每个mapper进行配置,麻烦。

8.5.3 通过MapperScannerConfigurer进行mapper扫描(建议使用)

9 逆向工程
9.1 什么是逆向工程
mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程 可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml、po…)
企业实际开发中,常用的逆向工程方式:
由于数据库的表生成java代码。
9.3 使用方法(会用)
9.3.1 运行逆向工程

浙公网安备 33010602011771号