您的位置:首页 > 其它

Mybatis笔记二

2018-09-01 10:19 49 查看

一对一查询

案例:查询所有订单信息,订单信息中显示下单人信息。

注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单。

方法一:

使用resultType,定义订单信息po类,此po类中包括了订单信息和用户信息:

Sql语句:

SELECT

  orders.*,

  user.username,

  user.address

FROM

  orders,

  USER

WHERE orders.user_id = user.id

定义po类

Po类中应该包括上边sql查询出来的所有字段,如下:

 

public class UserOrder extends Orders {

private String username;// 用户姓名
private String address;// 地址
get/set。。。。

 

UserOrder类继承Orders类后UserOrder类包括了Orders类的所有字段,只需要定义用户的信息字段即可。

 

Mapper.xml
<!-- 查询所有订单信息 -->
<select id="findOrdersList" resultType="cn.itcast.mybatis.po.UserOrder">
SELECT
orders.*,
user.id user_id,
user.username,
user.address
FROM
orders,    USER
WHERE orders.user_id = user.id
</select>
Mapper接口:
public List<UserOrder> findOrdersList() throws Exception;
测试:
public void testfindOrdersList()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询订单信息
List<UserOrder> list = userMapper.findOrdersList();
System.out.println(list);
//关闭session
session.close();
}
总结:

定义专门的po类作为输出类型,其中定义了sql查询结果集所有的字段。此方法较为简单,企业中使用普遍。

 

方法二:

 

使用resultMap,定义专门的resultMap用于映射一对一查询结果。

 

Sql语句:

SELECT

  orders.*,

  user.username,

  user.address

FROM

  orders,

  USER

WHERE orders.user_id = user.id

定义po类

在Orders类中加入User属性。

Mapper.xml
<select id="findOrdersList2" resultMap="userordermap">
SELECT
orders.*,
user.username,
user.address
FROM
orders,    USER
WHERE orders.user_id = user.id
</select>

这里resultMap指定userordermap。

定义resultMap
<!-- 订单信息resultmap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="userordermap">
<!-- 这里的id,是mybatis在进行一对一查询时将user字段映射为user对象时要使用,必须写 -->
<id property="id" column="id" />
<result property="user_id" column="user_id" />
<result property="order_number" column="order_number" />
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!-- 这里的id为user的id,如果写上表示给user的id属性赋值 -->
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
</association>
</resultMap>

association:表示进行关联查询单条记录

property:表示关联查询的结果存储在cn.itcast.mybatis.po.Orders的user属性中

javaType:表示关联查询的结果类型

<id property="id" column="user_id" />:查询结果的user_id列对应关联对象的id属性,这里是<id />表示user_id是关联查询对象的唯一标识。

<result property="username" column="username" />:查询结果的username列对应关联对象的username属性。

Mapper接口:
public List<Orders> findOrdersList2() throws Exception;
测试:
public void testfindOrdersList2()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询订单信息
List<Orders> list = userMapper.findOrdersList2();
System.out.println(list);
//关闭session
session.close();
}
总结:

此种方法使用了mybatis的association标签用于一对一关联查询,将查询结果映射至对象中。

 

一对多查询

案例:查询所有订单信息及订单下的订单明细信息。

订单信息与订单明细为一对多关系,一个订单包括多个商品信息。

使用resultMap实现如下:

 

ql语句:

 

SELECT

 

  orders.*,

 

  user.username,

 

  user.address,

 

  orderdetail.id orderdetail_id,

 

  orderdetail.item_id,

 

  orderdetail.item_num,

 

  orderdetail.item_price

 

FROM

 

  orders,USER ,orderdetail

 

WHERE orders.user_id = user.id

 

AND orders.id = orderdetail.orders_id

定义po类

在Orders类中加入User属性。

在Orders类中加入List<Orderdetail> orderdetails 属性

 

Mapper.xml
<select id="findOrdersDetailList" resultMap="userorderdetailmap">
SELECT
orders.*,
user.username,
user.address,
orderdetail.id orderdetail_id,
orderdetail.item_id,
orderdetail.item_num,
orderdetail.item_price
FROM orders,USER ,orderdetail
WHERE orders.user_id = user.id
AND orders.id = orderdetail.orders_id
</select>

定义resultMap

<!-- 订单信息resultmap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="userorderdetailmap">
<id property="id" column="id" />
<result property="user_id" column="user_id" />
<result property="order_number" column="order_number" />
<association property="user" javaType="cn.itcast.mybatis.po.User">
<id property="id" column="user_id" />
<result property="username" column="username" />
<result property="address" column="address" />
</association>
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<id property="id" column="orderdetail_id" />
<result property="item_id" column="item_id" />
<result property="item_num" column="item_num" />
<result property="item_price" column="item_price" />
</collection>
</resultMap>

collection部分定义了查询订单明细信息。

collection:表示关联查询结果集

property="orderdetails":关联查询的结果集存储在cn.itcast.mybatis.po.Orders上哪个属性。

ofType="cn.itcast.mybatis.po.Orderdetail":指定关联查询的结果集中的对象类型即List中的对象类型。

<id />及<result/>的意义同一对一查询。

 

Mapper接口:
public List<Orders> findOrdersDetailList () throws Exception;
测试:
public void testfindOrdersDetailList()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询订单信息
List<Orders> list = userMapper.findOrdersDetailList();
System.out.println(list);
//关闭session
session.close();
}
总结:

此种方法使用了mybatis的collection标签用于一对多关联查询,将查询结果映射至集合对象中。

resultMap使用继承

 

上边定义的resultMap中user部分和一对一查询订单信息的resultMap相同,这里使用继承可以不再填写重复的内容,如下:

 

<resultMap type="cn.itcast.mybatis.po.Orders" id="userorderdetailmap2" extends="userordermap">
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<id property="id" column="orderdetail_id" />
<result property="item_id" column="item_id" />
<result property="item_num" column="item_num" />
<result property="item_price" column="item_price" />
</collection>
</resultMap>

 

使用extends继承订单信息userordermap。

多对多查询

案例:查询所有订单信息及订单明细的商品信息。

订单信息与商品信息为多对多关系,因为一个订单包括多个商品信息,一个商品可以在多个订单中存在,订单信息与商品信息的多对多关系是通过订单明细表进行关联。

Sql语句:

SELECT

  orders.*,

  user.username,

  user.address,

  orderdetail.id orderdetail_id,

  orderdetail.item_id,

  orderdetail.item_num,

  orderdetail.item_price,

  items.item_name,

  items.item_detail

FROM

  orders,USER ,orderdetail,items   

WHERE orders.user_id = user.id

AND orders.id = orderdetail.orders_id

AND orderdetail.item_id = items.id

定义po类

在Orders类中加入User属性。

在Orders类中加入List<Orderdetail> orderdetails 属性,存储订单明细信息

在Orderdetail类中加入Items items 属性存储商品信息

 

Mapper.xml
<select id="findOrdersItemsList" resultMap="userorderitemsmap">
SELECT
orders.*,
user.username,
user.address,
orderdetail.id orderdetail_id,
orderdetail.item_id,
orderdetail.item_num,
orderdetail.item_price,
items.item_name,
items.item_detail
FROM
orders,USER ,orderdetail,items

WHERE orders.user_id = user.id
AND orders.id = orderdetail.orders_id
AND orderdetail.item_id = items.id
</select>
定义resultMap
<!-- 订单商品信息resultmap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="userorderitemsmap"
extends="userordermap">
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<id property="id" column="orderdetail_id" />
<result property="item_id" column="item_id" />
<result property="item_num" column="item_num" />
<result property="item_price" column="item_price" />
<!-- 商品信息 -->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<id property="id" column="item_id" />
<result property="item_name" column="item_name" />
<result property="item_detail" column="item_detail" />
</association>
</collection>
</resultMap>

在collection中加入association通过订单明细表关联查询商品信息

Mapper接口:
public List<Orders> findOrdersItemsList () throws Exception;
测试:
public void findOrdersItemsList()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询订单信息
List<Orders> list = userMapper.findOrdersItemsList();
System.out.println(list);
//关闭session
session.close();
}
总结:

所谓一对多查询、多对多查询都对于具体的业务分析来说,使用mybatis提交的collection和association可以完成不同的关联查询需求,通常在实际应用时association用自定义pojo方式代替,关联查询结果集使用collection完成。

延迟加载

需要查询关联信息时,使用mybatis延迟加载特性可有效的减少数据库压力,首次查询只查询主要信息,关联信息等用户获取时再加载。

 

打开延迟加载开关

 

在mybatis核心配置文件中配置:

 

lazyLoadingEnabled、aggressiveLazyLoading

设置项

描述

允许值

默认值

lazyLoadingEnabled

全局性设置懒加载。如果设为‘false’,则所有相关联的都会被初始化加载。

true | false

false

aggressiveLazyLoading

当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每个属性都按需加载。

true | false

true

<settings>
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>
</settings>

一对一查询延迟加载

Sql语句: 

SELECT

  orders.*

FROM

  orders 

定义po类

在Orders类中加入User属性。

 

定义resultMap
<!-- 订单信息resultmap -->
<resultMap type="cn.itcast.mybatis.po.Orders" id="userordermap2">
<id property="id" column="id" />
<result property="user_id" column="user_id" />
<result property="order_number" column="order_number" />
<association property="user" javaType="cn.itcast.mybatis.po.User" select="selectUserById" column="user_id" />
</resultMap>

association:

select="selectUserById":指定关联查询sql为selectUserById

column="user_id":关联查询时将user_id列的值传入selectUserById

最后将关联查询结果映射至cn.itcast.mybatis.po.User。

Mapper.xml

 

<select id="findOrdersList3" resultMap="userordermap2">
SELECT
orders.*
FROM
orders
</select>
Mapper接口:
public List<Orders> findOrdersList3() throws Exception;

测试:

public void testfindOrdersList3()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//查询订单信息
List<Orders> list = userMapper.findOrdersList3();
System.out.println(list);
//开始加载,通过orders.getUser方法进行加载
for(Orders orders:list){
System.out.println(orders.getUser());
}
//关闭session
session.close();
}
总结:

使用延迟加载提高数据库查询性能,默认不查询关联数据,按需要发出sql请求关联查询信息。

 

一级缓存

Mybatis一级缓存的作用域是同一个SqlSession。

 

第一个例子:

//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//第一次查询
User user1 = userMapper.selectUserById(1);
System.out.println(user1);
//第二次查询,由于是同一个session则不再向数据发出语句直接从缓存取出
User user2 = userMapper.selectUserById(1);
System.out.println(user2);
原理:

Mybatis首先去缓存中查询结果集,如果没有则查询数据库,如果有则从缓存取出返回结果集就不走数据库。

Mybatis内部存储缓存使用一个HashMap,key为hashCode+sqlId+Sql语句。value为从查询出来映射生成的java对象

 

第二个例子:

//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//第一次查询
User user1 = userMapper.selectUserById(1);
System.out.println(user1);
//在同一个session执行更新
User user_update = new User();
user_update.setId(1);
user_update.setUsername("李奎");
userMapper.updateUser(user_update);
session.commit();
//第二次查询,虽然是同一个session但是由于执行了更新操作session的缓存被清空,这里重新发出sql操作
User user2 = userMapper.selectUserById(1);
System.out.println(user2);
原理

该例子与第一个例子不同的是在两次查询中间加入了更新,更新操作执行后mybatis执行了清除缓存即清空HashMap。

二级缓存

Mybatis的二级缓存即查询缓存,它的作用域是一个mapper的namespace,即在同一个namespace中查询sql可以从缓存中获取数据。

二级缓存是可以跨SqlSession的。

启二级缓存:

  1. 在核心配置文件SqlMapConfig.xml中加入

<setting name="cacheEnabled" value="true"/>

 

 

 

描述

允许值

默认值

cacheEnabled

对在此配置文件下的所有cache 进行全局性开/关设置。

true false

true

 

  1. 要在你的Mapper映射文件中添加一行:  <cache /> 
  2. 在select语句中useCache=false可以禁用当前的语句的二级缓存,即每次查询夸session 的查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。

实现序列化:

 

注意:将查询结果的pojo对象进行序列化实现 java.io.Serializable接口

 

例子:

//获取session1
SqlSession session1 = sqlSessionFactory.openSession();
UserMapper userMapper = session1.getMapper(UserMapper.class);
//使用session1执行第一次查询
User user1 = userMapper.selectUserById(1);
System.out.println(user1);
//关闭session1
session1.close();
//获取session2
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper userMapper2 = session2.getMapper(UserMapper.class);
//使用session2执行第二次查询,由于开启了二级缓存这里从缓存中获取数据不再向数据库发出sql
User user2 = userMapper2.selectUserById(1);
System.out.println(user2);
//关闭session2
session2.close();

刷新缓存

在mapper的同一个namespace中,如果有其它insert、update、delete操作数据后需要刷新缓存,如果不执行刷新缓存会出现脏读。

sql中的 flushCache="true" 属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。使用缓存时如果手动修改数据库表中的查询数据会出现脏读。 

如下:

<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">

ache  的其它参数:

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 – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。

 

应用场景:

1、针对复杂的查询或统计的功能,用户不要求每次都查询到最新信息,使用二级缓存,通过刷新间隔flushInterval设置刷新间隔时间,由mybatis自动刷新。

比如:实现用户分类统计sql,该查询非常耗费时间。

将用户分类统计sql查询结果使用二级缓存,同时设置刷新间隔时间:flushInterval(一般设置时间较长,比如30分钟,60分钟,24小时,根据需求而定)

 

2、针对信息变化频率高,需要显示最新的信息,使用二级缓存。

将信息查询的statement与信息的增、删、改定义在一个mapper.xml中,此mapper实现二级缓存,当执行增、删、修改时,由mybatis及时刷新缓存,满足用户从缓存查询到最新的数据。

比如:新闻列表显示前10条,该查询非常快,但并发大对数据也有压力。

将新闻列表查询前10条的sql进行二级缓存,这里不用刷新间隔时间,当执行新闻添加、删除、修改时及时刷新缓存。

 

二级缓存使用Ehcache

Mybatis与缓存框架ehcache进行了整合,采用ehcache框架管理缓存数据。

第一步:引入缓存的依赖包

第二步:引入缓存配置文件

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>

 

defaultCache配置说明:

maxElementsInMemory 内存中最大缓存对象数.当超过最大对象数的时候,ehcache会按指定的策略去清理内存
eternal 缓存对象是否永久有效,一但设置了,timeout将不起作用.
timeToIdleSeconds 设置Element在失效前的允许闲置时间.仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大.
timeToLiveSeconds:设置Element在失效前允许存活时间.最大时间介于创建时间和失效时间之间.仅当element是永久有效时使用,默认是0.,也就是element存活时间无穷大.
overflowToDisk 配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中.
diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
maxElementsOnDisk 磁盘中最大缓存对象数,若是0表示无穷大.
diskPersistent 是否在重启服务的时候清楚磁盘上的缓存数据.true不清除.
diskExpiryThreadIntervalSeconds 磁盘失效线程运行时间间隔.
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存.默认策略是LRU(最近最少使用).你可以设置为FIFO(先进先出)或是LFU(较少使用).

第三步:修改mapper文件中缓存类型

在cache中指定type。

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: