更多资源分享就在【Java帮帮】微信公众号与QQ空间
Mybatis第二天
复习
mybatis
是什么
?
l Mybatis是apache组织下的顶级项目,封装了jdbc的持久层的框架
l Mybatis解决了jdbc频繁连接、关闭Connectioin照成的资源浪费
l Mybatis解决了jdbc硬编码造成的sql分散,不易维护的情况
l Mybatis解决了参数封装必须顺序进行,这样不易进行开发
l Mybatis解决了结果映射直接封装到JavaBean中
Mybatis只需要程序员把精力放在sql语句上,方便进行sql的优化,和维护,适用需求变化灵活的项目。
Mybatis学习成本低,只需要会sql,就会开发。
Mybatis框架的执行流程:
l Mybatis的全局配置文件(sqlMapConfig.xml)加载
? 加载数据源
? 加载事务
? 加载封装sql语句的XML文件Mapper文件
l 通过sqlMapConfig配置文件加载运行环境,创建sqlSessionFactory会话工厂
注意:sqlSessionFactory工厂使用单列模式
l 使用sqlSessionFactory创建sqlSession会话来操作数据库,sqlSession是面向用户的接口,提供操作数据库的方法。SqlSession不是线程安全的,建议在方法内部使用。
注意:sqlSession并没有执行数据库,他只负责搬运数据。
l 调用sqlSession的方法进行操作数据库,需要进行提交事务
l 释放资源,关闭sqlSession
Mybatis
的dao开发方式:
l 原始的开发方式:需要程序员实现接口和实现类
? 需要在dao中注入sqlSessionFactory。
l 代理模式开发方式:只需要程序员编写接口即可
? 接口的全路径必须和mapper.xml文件的namespace相同
? 接口中方法名必须和mapper.xml中statement的Id相同
? 如果是是使用扫描模式:接口和mapper.xml文件必须在同一个目录
? Statement的parameterType的输入参数必须和接口中的方法参数匹配
? Statement的resultType类型必须和接口中方法的返回值类型一致,mybatis底层根据接口方法返回值类型进行判断需要使用的查询方法。
SqlMapConfig配置文件详解:
注意:sqlMapConfig配置文件配置:properties 引入外部资源
数据源,事务,引入Mapper映射文件。别名,扫描等等。
输入映射:
parameterType:指定输入参数类型:pojo,基本类型,map等等。
注意:由于使用parameterType,那么输入参数只能是一个对象参数
在传递参数之前我们必须做处理。
输出映射:
resultType:指定输出参数类型,可以是基本类型,也可以是pojo
注意:如果是pojo,那么必须保证查询字段和映射的Javabean字段一模一样
resultMap:可以使用resultMap进行一些高级映射
如果查询的数据记录和pojo的属性不一致,那么需要使用resultMap进行关系映射
高级映射:
将关联查询映射到一个pojo中
将关联查询映射到一个List<pojo>中
动态sql:(重点)
If判断【掌握】
Where
foreach
Sql片段
课程安排
对订单商品数据模型进行分析
高级映射:
实现一对一、一对多,多对多查询
延迟加载
查询缓存
一级缓存
二级缓存(了解mybatis二级缓存应用场景)
Mybatis和spring进行整合
逆向工程
代码逆向
插件逆向
一.订单
商品数据模型
1.数据表
2.模型关系分析
用户订单表:一个用户有多个订单,一个订单必定属于一个用户
用户à订单:一个用户有多个订单
订单à用户:一个订单只能由一个用户创建
订单à订单明细:一个订单对应多个订单明细,因为每一个订单可以购买多个商品,每一个商品对应一个订单明细。
订单明细à订单:一个订单明细只能包含在一个订单中,一对一。
商品à订单明细:商品和订单明细是一对多的关系
订单明细à商品:一个订单明细只能有一个商品
基于这样的关系:
订单和商品可以通过订单明细进行关联。
二.高级映射查询
1.一对一查询(resultType)
1.1.需求
查询订单信息,关联查询下单用户信息(一个订单对应一个用户)
注意:因为一个订单只能是一个用户的,这就是一对一。从订单查询用户就是一对一。
一个用户有多个订单,这就是一对多的关系,从用户查询订单就是一对多
1.2.使用包装类进行查询(方法一)
思路:查询订单的同时需要把订单所属的用户信息查询出来。归根结底:查询出来的数据需要封装到javabean中,那么我们需要定义响应的javabean对象。
1.2.1.sql语句分析
分析:根据订单查询用户,也就是说以订单为主。从订单一方进行查询同时关联查询用户。
订单关联用户:使用内链接?外连接?
只查询符合条件的数据记录。那么我们应该是内连接。
如下sql语句:
SELECT * FROM orders o,USER u WHERE o.`user_id`=u.`id`等价与
SELECT * FROM orders o INNER JOIN USER u ON o.`user_id`=u.`id`
也可以使用如下sql语句,更简洁,去掉多余的字段:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
1.2.2.创建POJO
分析:将上面的sql查询的字段映射到pojo中,pojo必须包含所查询字段列名。
原始的Orders类不能映射全部字段,那么我们需要创建新的pojo。
创建一个pojo类继承查询主类:
1.2.3.接口代码(Mapper.java)
1.2.4.映射文件
对应的mapper.xml
2.一对一查询(resultMap)
2.1.sql语句
和使用resultType使用的sql语句相同
2.2.使用resultMap映射思路
思路:将查询出来的订单信息映射到订单属性中,在订单中定义一个User对象的属性,然后通过resultMap关系映射,把User的响应属性映射到用户属性上面。
2.3.在Orders添加User属性
2.4.映射文件
2.4.1.定义resultMap
2.4.2.statement定义
2.5.接口代码
2.6.测试代码
2.7.总结
实现一对一查询:
ResultType:使用resultType查询较为简单,如果pojo中没有包含查询出来的列名,需要在pojo中增加对应属性。
ResultMap:需要单独定义resultMap,实现比较灵活,数据库列名可以和pojo中属性字段不一致。resultMap可以实现延迟加载
3.一对多查询
3.1.需求
查询订单及订单明细信息
3.2.sql语句
确定主查询表:从Orders订单表开始查询
关联查询表:订单明细表
直接在Orders订单对象添加包含订单明细的集合即可.
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id
FROM
orders,
USER,
orderdetail
WHERE orders.user_id = user.id
AND orders.id=orderdetail.orders_id
3.3.分析
使用resultType进行封装数据,这样会出现重复记录;
resultType只能进行每条记录对应映射,有几条映射几条。
这时候我们需要使用resultMap进行映射,在Orders中定义集合List<Orderdetail> orderdetail
最终查询结果会将订单信息映射到Orders中,把订单明细映射到List集合中
最终映射Orders记录为2条(orders没有重复记录)
每个Orders的orderDetail存储了订单对应的订单明细
3.4.在Orders中添加订单明细
3.5.映射文件
3.5.1.映射resultMap
3.5.1.1.resultMap(一)
直接定义在resultMap下面:
<!--定义resultMap:将订单查询结果的字段都封装到Orders对象中 -->
<resultMap type="cn.itcast.bean.Orders" id="BaseResultMap">
<!-- id:查询列表中的唯一标识,订单信息中的唯一标识,如果有多个Id,那么就定义多个ID
column:订单信息唯一标识列名(也就是数据库主键列名)
property:订单信息唯一标识映射到pojo的字段名 -->
<id column="id" property="id"/>
<!-- 定义普通属性查询列和pojo属性名之间的映射关系 -->
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<result column="createtime" property="createtime"/>
<result column="note" property="note"/>
<!-- 配置关联关系映射 -->
<!-- association: 配置一对一关联关系
property:要将关联查询映射到Orders中的那个属性
javaType:这是一对一中被关联的映射对象 -->
<association property="user" javaType="cn.itcast.bean.User">
<!-- id:关联查询用户的唯 一标识
column:指定唯 一标识用户信息的列
-->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
<!-- 定义集合:一对多的关系
collection:对关联查询一对多的多条记录映射到集合对象中
property:定义要映射到Orders里面那个集合属性
ofType:需要被关联映射的对象-->
<collection property="orderList" ofType="cn.itcast.bean.Orderdetail">
<id column="orderdetail_id" property="id"/>
<result column="orders_id" property="ordersId"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="items_num"/>
</collection>
</resultMap>
3.5.1.3.resultMap(二)
另外单独定义一个resultMap:
使用extends继承前面一个resultMap
3.5.2.statement定义
3.5.2.1.使用方式一
3.5.2.2.使用方式二
3.6.接口定义
3.7.测试代码
3.8.小结
mybatis使用collection对关联查询的多条记录封装到一条集合中,不能使用resultType,会出现重复记录
4.多对多查询
4.1.需求
查询用户及用户购买商品的信息
4.2.sql语句
查询用户表关联查询出商品信息
主表:用户表,从用户表查询
从表:由于用户表和商品表没有直接的关系,所以必须通过订单表、订单明细表关联到商品表,故而关联商品表:orders,orderdetail,items.
如下sql语句:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address,
orderdetail.id orderdetail_id,
orderdetail.items_id,
orderdetail.items_num,
orderdetail.orders_id,
items.name items_name,
items.detail items_detail,
items.price items_price
FROM
orders,
USER,
orderdetail,
items
WHERE orders.user_id = user.id AND orderdetail.orders_id=orders.id AND orderdetail.items_id = items.id
4.3.映射思路
分析:能不能直接把商品记录映射到用户表中?
不能,用户表和商品表没有直接的对应关系。
映射思路:
用户表(User)à订单表(Orders)à订单明细(orderdetail)à商品表(items)
在用户表(User)中定义集合List<Orders>集合来保存订单信息
在订单Orders中定义集合List<Orderdetail>进行封装数据
在Orderdetail中添加items属性来封装商品信息
4.4.映射文件
4.4.1.resultMap
<mapper namespace="cn.itcast.dao.UserMapper">
<!--需求:使用sql语句:select id id_,username _username from user
使用sql语句的别名来表示数据库的字段名,这个别名和javabean字段不相同
type:resultMap最终映射的java对象
id:标识resultMap的唯一标识
-->
<resultMap type="user" id="BaseResultMap">
<!-- 返回结果映射:id表示查询结果集中的唯一标识
column:查询出来的列名
property:查询出来映射的pojo的属性名
最终resultMap对象列名和javabean中属性进行一个映射
-->
<id column="id" property="id"/>
<!-- result:对普通列名进行定义
column:查询出来的列名
property:对应的javabean属性名 -->
<result column="username" property="username"/>
<result column="birthday" property="birthday"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 一个用户有多个订单
collection:集合,表示一个用户有多个订单
property:表示查询被关联到User中的属性
ofType:表示被关联属性类型-->
<collection property="ordersList" ofType="orders">
<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"/>
<!-- 订单中嵌套一层关系:一个订单有很多订单明细
集合中嵌套集合 -->
<collection property="detailList" ofType="orderdetail">
<id column="orderdetail_id" property="id"/>
<result column="orders_id" property="ordersId"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="items_num"/>
<!-- 订单明细中包含:商品 -->
<association property="items" javaType="items">
<id column="id" property="id"/>
<result column="name" property="name"/>
<result column="price" property="price"/>
<result column="detail" property="detail"/>
<result column="pic" property="pic"/>
<result column="createtime" property="createtime"/>
</association>
</collection>
</collection>
</resultMap>
4.4.2.statement定义
4.5.接口代码
4.6.测试
5.级联保存(添加内容)
6.批量保存(foreach)
三.
延迟加载
1.什么是延迟加载
resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
需求:
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。
2.使用association进行延迟加载
2.1.需求
查询订单关联查询用户信息
2.2.映射文件
2.2.1.statement定义
需要定义2个statement,一个是查询订单的statement,一个定义的是查询用户的statement
当查询订单的时候,如果不需要用户信息,就不用查询用户信息,也就是不用运行第二个statement了。
第一个statement如下:只查询订单信息
SELECT * FROM orders
在查询订单的statement中使用association去延迟加载(执行)下边的satatement(关联查询用户信息)
关联查询用户信息
通过上边查询到的订单信息中user_id去关联查询用户信息
使用UserMapper.xml中的findUserById
上边先去执行findOrdersUserLazyLoading,当需要去查询用户的时候再去执行findUserById,通过resultMap的定义将延迟加载执行配置起来。
2.2.2.resultMap
思考:只定义上面2个它就能互相调用了么?
不能,我们需要在resultMap中进行指明调用方法的ID
使用association中的select指定延迟加载去执行的statement的id。
<!-- 延迟加载的resultMap -->
<resultMap type="cn.itcast.bean.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"/>
<!-- 实现对用户信息进行延迟加载
select:指定延迟加载需要执行的statement的id(是根据user_id查询用户信息的statement)
要使用userMapper.xml中findUserById完成根据用户id(user_id)用户信息的查询,如果findUserById不在本mapper中需要前边加namespace
column:订单信息中关联用户信息查询的列,是user_id
关联查询的sql理解为:
SELECT orders.*,
(SELECT username FROM USER WHERE orders.user_id = user.id)username,
(SELECT sex FROM USER WHERE orders.user_id = user.id)sex
FROM orders
-->
<association property="user" javaType="cn.itcast.bean.User"
select="cn.itcast.dao.UserMapper.findUserById" column="user_id">
<!-- 实现对用户信息进行延迟加载 -->
</association>
</resultMap>
2.3.接口代码
2.4.测试代码
2.5.延迟加载思路
思考:上述代码起作用了吗?答案是没有起作用。我们还没有进行延迟加载开启配置
2.6.配置延迟加载
mybatis默认没有开启延迟加载,需要在SqlMapConfig.xml中setting配置。
在mybatis核心配置文件中配置:
lazyLoadingEnabled、aggressiveLazyLoading
设置项 | 描述 | 允许值 | 默认值 |
lazyLoadingEnabled | 全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。 | true | false | false |
aggressiveLazyLoading | 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。 | true | false | true |
在SqlMapConfig.xml中配置:
2.7.总结
延迟加载:需要开启查询缓存,按需加载。需求时就就加载,不需要是不用加载。
四.查询缓存
Mybatis提供查询缓存,提高查询性能,减轻数据库压力。
Mybatis提供了一级缓存、二级缓存。
分析:回忆hibernate学习时,我们也学习了一级缓存和二级缓存,那么这里的缓存和hibernate的一级缓存和二级缓存是一样的。
一级缓存:是sqlSession级别的缓存。当每一个用户拥有一个sqlsession时候,每一个sqlsession内部都有一个数据结构(HashMap)来存储缓存数据。当你第二次使用相同sql语句进行查询的时候,就会检测你是否使用相同的sql语句进行查询,如果是相同的sql语句,那么就不会再查询数据库,直接从缓存中获取数据。减轻了数据库的压力。
二级缓存:二级缓存是sessionFactory级别的缓存。需要引入外部插件来实现这一缓存。
为什么要使用缓存:提高查询效率,减轻数据库压力。
1. 一级缓存
1.1.一级缓存原理
第一次查询先去缓存中找,如果缓存中没有我们所需的数据,就去数据库查询。
一级缓存原理:把sql语句作为Key,查询时对比一级缓存区域的key,如果key相同
那么就表示一级缓存中有我们需要的数据。如果没有那么就需要去数据库进行查询。
当用户进行修改,或者删除需要对一级缓存进行更新操作。
1.2.一级缓存测试
Mybatis默认支持一级缓存,不需要进行配置。
1.3.应用场景
应用:mybatis和spring进行整合。分为三层进行开发,service层交给事务进行管理。
也就是把sqlsession交给事务进行管理。
Service{
第一步:获取sqlSession
第二步:进行操作数据库,查询用户ID为1的用户
第三步:第二次从Mapper中查询ID为1的数据
第四步:sqlSession关闭
}
整合spring后,service中有很多方法共享Mapper文件中的sql语句。
2.二级缓存
2.1.二级缓存原理
二级缓存是sessionFactory级别的缓存。
2.2.开启二级缓存
在核心配置文件SqlMapConfig.xml中加入
<settingname="cacheEnabled"value="true"/>
描述 | 允许值 | 默认值 | |
cacheEnabled | 对在此配置文件下的所有cache 进行全局性开/关设置。 | true false | true |
要在你的Mapper映射文件中添加一行: <cache /> ,表示此mapper开启二级缓存。
开启本地二级缓存:
2.3.调用pojo类实现序列化接口
因为二级缓存存储介质多种多样,不一定在内存。取出数据执行反序列化操作。
2.4.测试方法
2.5.禁用二级缓存
在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
2.6.刷新缓存
在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。
设置statement配置中的flushCache="true" 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。
如下:
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
2.7.Mybatis Cache参数
flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。
size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。
如下例子:
<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>
这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有, 默认的是 LRU:
1. LRU – 最近最少使用的:移除最长时间不被使用的对象。
2. FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
3. SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
4. WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
3.mybatis整合ehcache
EhCache 是一个纯Java的进程内缓存框架,是一种广泛使用的开源Java分布式缓存,具有快速、精干等特点,是Hibernate中默认的CacheProvider。
3.1.分布式缓存
分析:如果没有采用分布式缓存管理,不方便系统优化和维护。对系统的性能有较大影响。
Mybatis无法自己实现分布式缓存,需要与其他插件进行整合。
3.2.整合方法
Mybatis提供了一个cache缓存接口,如果需要实现自己的缓存逻辑,就实现cache接口即可。
Mybatis和ehcache整合,mybatis和ehcache整合包中提供一个cache的实现类。
Mybatis默认实现cache类如下:
3.3.加入ehcache包
3.4.整合ehcache
配置mapper中cache中的type为ehcache对cache接口的实现类型。
根据需求调整缓存参数:
<cachetype="org.mybatis.caches.ehcache.EhcacheCache">
<propertyname="timeToIdleSeconds"value="3600"/>
<propertyname="timeToLiveSeconds"value="3600"/>
<!-- 同ehcache参数maxElementsInMemory -->
<propertyname="maxEntriesLocalHeap"value="1000"/>
<!-- 同ehcache参数maxElementsOnDisk -->
<propertyname="maxEntriesLocalDisk"value="10000000"/>
<propertyname="memoryStoreEvictionPolicy"value="LRU"/>
</cache>
3.5.加入ehcache配置文件
在classpath下面配置ehcache.xml配置文件:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="F:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
属性说明:
l diskStore:指定数据在磁盘中的存储位置。
l defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
以下属性是必须的:
l maxElementsInMemory - 在内存中缓存的element的最大数目
l maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
l eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
l overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
以下属性是可选的:
l timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
l timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
l diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
l diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
l memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
3.6.二级缓存应用场景
对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用mybatis二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。
实现方法如下:通过设置刷新间隔时间,由mybatis每隔一段时间自动清空缓存,根据数据变化频率设置缓存刷新间隔flushInterval,比如设置为30分钟、60分钟、24小时等,根据需求而定。
3.7.局限性
mybatis二级缓存对细粒度的数据级别的缓存实现不好,比如如下需求:对商品信息进行缓存,由于商品信息查询访问量大,但是要求用户每次都能查询最新的商品信息,此时如果使用mybatis的二级缓存就无法实现当一个商品变化时只刷新该商品的缓存信息而不刷新其它商品的信息,因为mybaits的二级缓存区域以mapper为单位划分,当一个商品信息变化会将所有商品信息的缓存数据全部清空。解决此类问题需要在业务层根据需求对数据有针对性缓存。
五.mybatis与
spring整合
1.整合思路
需要spring来管理sessionFactory,sessionFactory是单列的。
Spring和mybagtis整合生成代理对象。sessionFactory生成sqlSession
持久层Mapper需要spring来管理
2.整合环境
创建一个新的java工程(接近实际开发的工程结构)
jar包:
mybatis3.2.7的jar包
spring3.2.0的jar包
mybatis和spring的整合包:早期ibatis和spring整合是由spring官方提供,mybatis和spring整合由mybatis提供。
全部jar包
3.原始整合开发方式
3.1.创建Java工程
3.2.修改sqlMapConfig
只需要以上配置即可。
3.3.配置beans
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
<!-- 配置数据源 -->
<context:property-placeholder location="classpath:db.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 配置工厂 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:sqlMapConfig.xml"></property>
</bean>
<bean id="userDao" class="cn.itcast.dao.UserDaoImpl">
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- 管理事务 -->
</beans>
3.4.引入其他配置文件
分析:使用原始的开发方式,不需要Mapper.xml文件和pojo名称相同,也不需要在同一个目录。没有特别的规定。
需要引入:映射文件,日志文件,数据库资源文件
3.5.接口
3.6.接口实现类
3.7.测试
4.代理开发方式
分析:代理开发方式需要注意的问题:映射文件和接口Dao必须在同意个目录,并且名字相同,映射文件的namespace必须和dao接口的全类路径名。
4.1.mapper.xml和mapper.java
4.2.通过MapperFactoryBean创建代理对象
此方法问题:
需要针对每个mapper进行配置,麻烦。
4.3.通过MapperScannerConfigurer进行mapper扫描(建议使用)
4.4.测试代码
六
.
逆向工程
1.什么是逆向工程
mybaits需要程序员自己编写sql语句,mybatis官方提供逆向工程 可以针对单表自动生成mybatis执行所需要的代码(mapper.java,mapper.xml、po..)
企业实际开发中,常用的逆向工程方式:
由于数据库的表生成java代码。
2.下载逆向工程
3.使用方法(会用)
3.1.运行逆向工程
建议使用java程序方式,不依赖开发工具。
3.2.生成代码配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--数据库连接的信息:驱动类、连接地址、用户名、密码 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis" userId="root"
password="mysql">
</jdbcConnection>
<!-- <jdbcConnection driverClass="oracle.jdbc.OracleDriver"
connectionURL="jdbc:oracle:thin:@127.0.0.1:1521:yycg"
userId="yycg"
password="yycg">
</jdbcConnection> -->
<!-- 默认false,把JDBC DECIMAL 和 NUMERIC 类型解析为 Integer,为 true时把JDBC DECIMAL 和
NUMERIC 类型解析为java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO类的位置 -->
<javaModelGenerator targetPackage="cn.itcast.ssm.po"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理前后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="cn.itcast.ssm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="cn.itcast.ssm.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定数据库表 -->
<table tableName="items"></table>
<table tableName="orders"></table>
<table tableName="orderdetail"></table>
<table tableName="user"></table>
</context>
</generatorConfiguration>
3.3.执行生成程序
生成后的代码:
3.4.使用生成的代码
需要将生成工程中所生成的代码拷贝到自己的工程中
测试ItemsMapper中的方法
使用example可以进行类似的查询:
查询条件如下所示:
//自定义条件查询
@Test
publicvoid testSelectByExample() {
ItemsExample itemsExample = new ItemsExample();
//通过criteria构造查询条件
ItemsExample.Criteria criteria = itemsExample.createCriteria();
criteria.andNameEqualTo("笔记本3");
//可能返回多条记录
List<Items> list = itemsMapper.selectByExample(itemsExample);
System.out.println(list);
}
//根据主键查询
@Test
publicvoid testSelectByPrimaryKey() {
Items items = itemsMapper.selectByPrimaryKey(1);
System.out.println(items);
}
//插入
@Test
publicvoid testInsert() {
//构造 items对象
Items items = new Items();
items.setName("手机");
items.setPrice(999f);
itemsMapper.insert(items);
}
//更新数据
@Test
publicvoid testUpdateByPrimaryKey() {
//对所有字段进行更新,需要先查询出来再更新
Items items = itemsMapper.selectByPrimaryKey(1);
items.setName("水杯");
itemsMapper.updateByPrimaryKey(items);
//如果传入字段不空为才更新,在批量更新中使用此方法,不需要先查询再更新
//itemsMapper.updateByPrimaryKeySelective(record);
}
更多资源分享就在【Java帮帮】微信公众号与QQ空间