mybatis实现对象之间的关系(一对一、一对多、多对多)以及mybatis的缓存机制
2018-01-18 17:25
555 查看
一、业务需求中对象之间的关系
在实际的开发当中,不仅要对表与表之间的关系进行的详细分析,也要针对在业务意义上对象之间的关系,通常的关系为:一对一、一对多、多对多;
二、针对使用mybatis处理这三种关系
1、业务模型说明
这里用用用户表、订单表、订单详情表、商品表着四张表之间,说明对象这三种之间的关系:
2、一对一的关系
2.1、用查询订单表的详情orders表,来说明一对一的关系(一个订单信息对应一个用户)
2.2、使用resultType和resultMap都可以实现一对一的关系的
2.21、使用resultType实现一对一的关系
resultType标签对应的结果映射到一个包装类上面,这个包装类包含着order表和user表的所有的属性信息;(很好理解啊,就是sql查询返回的数据要对应到java对象中,如果使用包装类型的设计方法就是用resultTpye,如果使用在两者中插入某一类的对象作为属性,就是用resultMap)
包装类:
public class OrdersCustom extends Orders {
//用户名称
private String username;
//用户地址
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}映射文件.xml<!-- 使用resultType实现订单查询,关联查询用户信息 -->
<select id="findOrdersUserList" resultType="cn.itcast.mybatis.po.OrdersCustom">
SELECT
orders.*,
user.username,
user.address
FROM
orders,
USER
WHERE orders.user_id =
user.id
</select>
对用的mapper接口// 查询订单及用户信息
public List<OrdersCustom> findOrdersUserList() throws Exception;
2.22、使用resultMap来说明一对一的关系(这里resultMap映射到orders对象后,但是里面又有user要映射,所以,相当于在orders对象映射之后又映射到user一次,相当于连续两次的映射,所以在是一对一的情况下,使用resultType)
映射到java对象
public class Orders {
private int id;//订单id
private int user_id;//用户id
private String order_number;//订单号
//用户信息
private User user;映射文件.xml
<!-- 定义订单信息及用户信息的resultMap -->
<resultMap type="orders" id="ordersUserResultMap">
<!-- id:订单信息的唯 一约束 如果由多个字段决定一条唯 一记录,id标签需要定义多个 -->
<id column="id" property="id" />
<result column="order_number" property="order_number" />
<result column="user_id" property="user_id" />
<!-- 配置用户映射信息 将sql查询的用户信息映射到orders中的user属性中 association:用于单个关联对象的映射 property:将关联信息映射到orders的哪个属性
javaType:映射属性的类型 -->
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!-- id:关联的用户信息的唯 一约束 property:id指定 的列映射到关联cn.itcast.mybatis.po.User类的哪个属性 -->
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="address" property="address" />
</association>
</resultMap>
对用的mapper接口
// 查询订单及用户信息使用resultMap
public List<Orders> findOrdersUserListResultMap() throws Exception;
3、一对多的关系
完成的需求:根据订单orders查询到订单的明细orderdetail
resultMap将订单明细信息映射到Orders.java的属性中;
(实际上就是在orders的对象当中把orderdetail集合又映射了一遍)
映射的java对象中;public class Orders {
private int id;//订单id
private int user_id;//用户id
private String order_number;//订单号
//用户信息
private User user;
//订单明细
private List<Orderdetail> orderdetails;
映射文件.xml注意,为了防止代码的可重用性,mybatis不止提供了sql片段,还提供了继承:
<!-- 定义订单及订单明细的resultMap extends:继承哪个resultMap,如果 是跨namespace前边加namespace是 -->
<resultMap type="orders" id="ordersUserDetailResultMap"
extends="ordersUserResultMap">
<!-- 订单及用户信息,继承于ordersUserResultMap -->
<!-- 映射订单明细信息 collection:映射集合对象 property:将明细信息映射到哪个集合属性中。 ofType:集合中对象的类型 -->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:订单明细的唯 一约束 property:ofType指定 类型的属性 -->
<id column="orderdetail_id" property="id" />
<result column="item_id" property="item_id" />
<result column="item_num" property="item_num" />
<result column="item_price" property="item_price" />
</collection>
public List<Orders> findOrdersUserDetailList() throws Exception;
3、多对多关系需求:查询所有订单信息及订单明细的商品信息
映射到的java对象:
public class Orders {
private int id;//订单id
private int user_id;//用户id
private String order_number;//订单号
//用户信息
private User user;
//订单明细
private List<Orderdetail> orderdetails;因为在 //订单明细 private List<Orderdetail> orderdetails;中有外键关联的item信息,所以这里可以使用在Orderdetail对象中设置Items的属性:public class Orderdetail {
private int id;//主键
private int orders_id;//订单id
private int item_id;//商品id
private int item_num;//商品数量
private Float item_price;//商品价格
//商品信息
private Items items;//明细对应的商品信息 对应的mapper.xml
<!-- 定义订单及明细和商品信息 -->
<resultMap type="orders" id="ordersUserDetailItemResultMap"
extends="ordersUserResultMap">
<!-- 订单及用户信息,继承于ordersUserResultMap -->
<!-- 映射订单明细信息 collection:映射集合对象 property:将明细信息映射到哪个集合属性中。 ofType:集合中对象的类型 -->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:订单明细的唯 一约束 property:ofType指定 类型的属性 -->
<id column="orderdetail_id" property="id" />
<result column="item_id" property="item_id" />
<result column="item_num" property="item_num" />
<result column="item_price" property="item_price" />
<!-- 映射商品信息 property:将商品信息映射到cn.itcast.mybatis.po.Orderdetail的items属性中 -->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<!-- id:商品信息的唯 一标识 -->
<id column="item_id" property="id" />
<result column="item_detail" property="item_detail" />
<result column="item_name" property="item_name" />
<result column="item_price_price" property="item_price" />
</association>
</collection>
</resultMap>
对应的mapper接口://查询订单及明细和商品信息
public List<Orders> findOrdersUserDetailItemList()throws Exception;
三、mybatis的缓存机制
将从数据库中查询出来的数据缓存起来,缓存介质:内存、磁盘,从缓存中取数据,而不从数据库查询,减少了数据库的操作,提高了数据处理性能。
1、mybatis的延迟加载
延迟加载意义:在需求允许的情况下,先查询单表,当需要关联其它表查询时,进行延迟加载,去关联查询;
达到目标:不需要关联信息时不查询,需要时再查询。好处:提高数据库的性能。
1.1、mybatis延迟加载的配置:
在SqlMapConfig.xml中配置setting全局参数:
lazyLoadingEnabled:延迟加载的总开关,设置为true
aggressiveLazyLoading:设置为false,实现按需加载(将积极变为消极)<!-- 全局配置参数 -->
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
</settings>
在mapper.xml的配置文件里配置延迟加载:(
需求:
查询订单信息,关联查询用户信息。
延迟加载需求:首次只查询订单信息,当需要关联查询用户信息时,再查询用户信息。
)<!-- 订单及用户的resultMap,实现延迟加载 -->
<resultMap type="orders" id="ordersResultMap">
<!-- 配置订单信息的映射 -->
<id column="id" property="id" />
<result column="user_id" property="user_id" />
<result column="order_number" property="order_number" />
<!-- 配置延迟加载 用户信息
select:延迟加载 时调用 的statement,如果跨命名空间,需要加上namespace
column:将哪一列的值作为参数 传到延迟加载 的statement -->
<association property="user" javaType="cn.itcast.mybatis.po.User"
select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">
</association>
</resultMap>
<!-- 订单信息查询,使用延迟加载 -->
<select id="findOrdersList" resultMap="ordersResultMap">
select * from orders
</select>
2、mybatis的一级缓存
Mybatis默认提供一级缓存,缓存范围是一个sqlSession。(也就是指的一条sql语句)
在同一个SqlSession中,两次执行相同的sql查询,第二次不再从数据库查询。
执行提交清除缓存测试:
如果第一次查询后,执行commit提交,mybatis会清除缓存,第二次查询从数据库查询。
如果该SqlSession执行commit()提交,清除缓存。
3、mybatis的二级缓存
缓存范围是跨SqlSession的,范围是mapper的namespace,相同的namespace使用一个二级缓存结构。
需要进行参数配置让mybatis支持二级缓存
3.1、二级缓存的配置在全局的配置文件sqlMapConfig.xml中配置:
<!-- 全局配置参数 -->
<settings>
<!-- 打开二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
在mapper.xml中的配置:<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<!-- 开启二级缓存 -->
<cache />
3.11、使用二级缓存注意的事项
l实现序列化:
注意:将查询映射对象结果的pojo对象进行序列化实现 java.io.Serializable接口
l 如何清除缓存:
执行相同的statement,如果执行提交操作需要清除二级缓存。
如果想让statement执行后刷新缓存(清除缓存),在statement中设置flushCache="true" (默认值是true)
l 设置statement是否开启二级缓存
如果让某个statement启用二级缓存,设置useCache=true(默认值为true)
3.2、二级缓存原理
如果二缓存开启,首先从二级缓存查询数据,如果二级缓存有则从二级缓存中获取数据,如果二级缓存没有,从一级缓存找是否有缓存数据,如果一级缓存没有,查询数据库。
4、使用Ehcache进行二级缓存
Mybatis控制二级缓存策略,二级缓存缓存介质使用Ehcache。
让Ehcache和mybatis进行整合。
实际上还是mybatis进行控制Ehcache,把缓存的数据存储在内存当中!
示例代码:https://github.com/libolibolibo/mybatis1217_22.git
这里附上mybatis的逆向工程(开发时可以使用该工程):https://github.com/libolibolibo/generatorSqlmapCustom
在实际的开发当中,不仅要对表与表之间的关系进行的详细分析,也要针对在业务意义上对象之间的关系,通常的关系为:一对一、一对多、多对多;
二、针对使用mybatis处理这三种关系
1、业务模型说明
这里用用用户表、订单表、订单详情表、商品表着四张表之间,说明对象这三种之间的关系:
2、一对一的关系
2.1、用查询订单表的详情orders表,来说明一对一的关系(一个订单信息对应一个用户)
2.2、使用resultType和resultMap都可以实现一对一的关系的
2.21、使用resultType实现一对一的关系
resultType标签对应的结果映射到一个包装类上面,这个包装类包含着order表和user表的所有的属性信息;(很好理解啊,就是sql查询返回的数据要对应到java对象中,如果使用包装类型的设计方法就是用resultTpye,如果使用在两者中插入某一类的对象作为属性,就是用resultMap)
包装类:
public class OrdersCustom extends Orders {
//用户名称
private String username;
//用户地址
private String address;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}映射文件.xml<!-- 使用resultType实现订单查询,关联查询用户信息 -->
<select id="findOrdersUserList" resultType="cn.itcast.mybatis.po.OrdersCustom">
SELECT
orders.*,
user.username,
user.address
FROM
orders,
USER
WHERE orders.user_id =
user.id
</select>
对用的mapper接口// 查询订单及用户信息
public List<OrdersCustom> findOrdersUserList() throws Exception;
2.22、使用resultMap来说明一对一的关系(这里resultMap映射到orders对象后,但是里面又有user要映射,所以,相当于在orders对象映射之后又映射到user一次,相当于连续两次的映射,所以在是一对一的情况下,使用resultType)
映射到java对象
public class Orders {
private int id;//订单id
private int user_id;//用户id
private String order_number;//订单号
//用户信息
private User user;映射文件.xml
<!-- 定义订单信息及用户信息的resultMap -->
<resultMap type="orders" id="ordersUserResultMap">
<!-- id:订单信息的唯 一约束 如果由多个字段决定一条唯 一记录,id标签需要定义多个 -->
<id column="id" property="id" />
<result column="order_number" property="order_number" />
<result column="user_id" property="user_id" />
<!-- 配置用户映射信息 将sql查询的用户信息映射到orders中的user属性中 association:用于单个关联对象的映射 property:将关联信息映射到orders的哪个属性
javaType:映射属性的类型 -->
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!-- id:关联的用户信息的唯 一约束 property:id指定 的列映射到关联cn.itcast.mybatis.po.User类的哪个属性 -->
<id column="user_id" property="id" />
<result column="username" property="username" />
<result column="address" property="address" />
</association>
</resultMap>
<!-- 使用resultMap实现订单查询,关联查询用户信息 --> <select id="findOrdersUserListResultMap" resultMap="ordersUserResultMap"> SELECT orders.*, user.username, user.address FROM orders, USER WHERE orders.user_id = user.id </select>
对用的mapper接口
// 查询订单及用户信息使用resultMap
public List<Orders> findOrdersUserListResultMap() throws Exception;
3、一对多的关系
完成的需求:根据订单orders查询到订单的明细orderdetail
resultMap将订单明细信息映射到Orders.java的属性中;
(实际上就是在orders的对象当中把orderdetail集合又映射了一遍)
映射的java对象中;public class Orders {
private int id;//订单id
private int user_id;//用户id
private String order_number;//订单号
//用户信息
private User user;
//订单明细
private List<Orderdetail> orderdetails;
映射文件.xml注意,为了防止代码的可重用性,mybatis不止提供了sql片段,还提供了继承:
<!-- 定义订单及订单明细的resultMap extends:继承哪个resultMap,如果 是跨namespace前边加namespace是 -->
<resultMap type="orders" id="ordersUserDetailResultMap"
extends="ordersUserResultMap">
<!-- 订单及用户信息,继承于ordersUserResultMap -->
<!-- 映射订单明细信息 collection:映射集合对象 property:将明细信息映射到哪个集合属性中。 ofType:集合中对象的类型 -->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:订单明细的唯 一约束 property:ofType指定 类型的属性 -->
<id column="orderdetail_id" property="id" />
<result column="item_id" property="item_id" />
<result column="item_num" property="item_num" />
<result column="item_price" property="item_price" />
</collection>
<!-- 查询订单及订单明细信息 --> <select id="findOrdersUserDetailList" resultMap="ordersUserDetailResultMap"> 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>对应的mapper接口:// 查询订单及订单明细信息
public List<Orders> findOrdersUserDetailList() throws Exception;
3、多对多关系需求:查询所有订单信息及订单明细的商品信息
映射到的java对象:
public class Orders {
private int id;//订单id
private int user_id;//用户id
private String order_number;//订单号
//用户信息
private User user;
//订单明细
private List<Orderdetail> orderdetails;因为在 //订单明细 private List<Orderdetail> orderdetails;中有外键关联的item信息,所以这里可以使用在Orderdetail对象中设置Items的属性:public class Orderdetail {
private int id;//主键
private int orders_id;//订单id
private int item_id;//商品id
private int item_num;//商品数量
private Float item_price;//商品价格
//商品信息
private Items items;//明细对应的商品信息 对应的mapper.xml
<!-- 定义订单及明细和商品信息 -->
<resultMap type="orders" id="ordersUserDetailItemResultMap"
extends="ordersUserResultMap">
<!-- 订单及用户信息,继承于ordersUserResultMap -->
<!-- 映射订单明细信息 collection:映射集合对象 property:将明细信息映射到哪个集合属性中。 ofType:集合中对象的类型 -->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:订单明细的唯 一约束 property:ofType指定 类型的属性 -->
<id column="orderdetail_id" property="id" />
<result column="item_id" property="item_id" />
<result column="item_num" property="item_num" />
<result column="item_price" property="item_price" />
<!-- 映射商品信息 property:将商品信息映射到cn.itcast.mybatis.po.Orderdetail的items属性中 -->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<!-- id:商品信息的唯 一标识 -->
<id column="item_id" property="id" />
<result column="item_detail" property="item_detail" />
<result column="item_name" property="item_name" />
<result column="item_price_price" property="item_price" />
</association>
</collection>
</resultMap>
<!-- 查询订单及订单明细信息及商品信息 --> <select id="findOrdersUserDetailItemList" resultMap="ordersUserDetailItemResultMap"> SELECT orders.*, user.username, user.address, orderdetail.id orderdetail_id, orderdetail.item_id, orderdetail.item_num, orderdetail.item_price , items.item_detail, items.item_name, items.item_price item_price_price FROM orders, USER, orderdetail, items WHERE orders.user_id = user.id AND orders.id = orderdetail.orders_id AND orderdetail.item_id = items.id </select>
对应的mapper接口://查询订单及明细和商品信息
public List<Orders> findOrdersUserDetailItemList()throws Exception;
三、mybatis的缓存机制
将从数据库中查询出来的数据缓存起来,缓存介质:内存、磁盘,从缓存中取数据,而不从数据库查询,减少了数据库的操作,提高了数据处理性能。
1、mybatis的延迟加载
延迟加载意义:在需求允许的情况下,先查询单表,当需要关联其它表查询时,进行延迟加载,去关联查询;
达到目标:不需要关联信息时不查询,需要时再查询。好处:提高数据库的性能。
1.1、mybatis延迟加载的配置:
在SqlMapConfig.xml中配置setting全局参数:
lazyLoadingEnabled:延迟加载的总开关,设置为true
aggressiveLazyLoading:设置为false,实现按需加载(将积极变为消极)<!-- 全局配置参数 -->
<settings>
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true" />
<setting name="aggressiveLazyLoading" value="false" />
</settings>
在mapper.xml的配置文件里配置延迟加载:(
需求:
查询订单信息,关联查询用户信息。
延迟加载需求:首次只查询订单信息,当需要关联查询用户信息时,再查询用户信息。
)<!-- 订单及用户的resultMap,实现延迟加载 -->
<resultMap type="orders" id="ordersResultMap">
<!-- 配置订单信息的映射 -->
<id column="id" property="id" />
<result column="user_id" property="user_id" />
<result column="order_number" property="order_number" />
<!-- 配置延迟加载 用户信息
select:延迟加载 时调用 的statement,如果跨命名空间,需要加上namespace
column:将哪一列的值作为参数 传到延迟加载 的statement -->
<association property="user" javaType="cn.itcast.mybatis.po.User"
select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">
</association>
</resultMap>
<!-- 订单信息查询,使用延迟加载 -->
<select id="findOrdersList" resultMap="ordersResultMap">
select * from orders
</select>
2、mybatis的一级缓存
Mybatis默认提供一级缓存,缓存范围是一个sqlSession。(也就是指的一条sql语句)
在同一个SqlSession中,两次执行相同的sql查询,第二次不再从数据库查询。
执行提交清除缓存测试:
如果第一次查询后,执行commit提交,mybatis会清除缓存,第二次查询从数据库查询。
一级缓存原理:
一级缓存采用Hashmap存储,mybatis执行查询时,从缓存中查询,如果缓存中没有从数据库查询。如果该SqlSession执行commit()提交,清除缓存。
3、mybatis的二级缓存
缓存范围是跨SqlSession的,范围是mapper的namespace,相同的namespace使用一个二级缓存结构。
需要进行参数配置让mybatis支持二级缓存
3.1、二级缓存的配置在全局的配置文件sqlMapConfig.xml中配置:
<!-- 全局配置参数 -->
<settings>
<!-- 打开二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
在mapper.xml中的配置:<mapper namespace="cn.itcast.mybatis.mapper.UserMapper">
<!-- 开启二级缓存 -->
<cache />
3.11、使用二级缓存注意的事项
l实现序列化:
注意:将查询映射对象结果的pojo对象进行序列化实现 java.io.Serializable接口
l 如何清除缓存:
执行相同的statement,如果执行提交操作需要清除二级缓存。
如果想让statement执行后刷新缓存(清除缓存),在statement中设置flushCache="true" (默认值是true)
l 设置statement是否开启二级缓存
如果让某个statement启用二级缓存,设置useCache=true(默认值为true)
3.2、二级缓存原理
如果二缓存开启,首先从二级缓存查询数据,如果二级缓存有则从二级缓存中获取数据,如果二级缓存没有,从一级缓存找是否有缓存数据,如果一级缓存没有,查询数据库。
4、使用Ehcache进行二级缓存
Mybatis控制二级缓存策略,二级缓存缓存介质使用Ehcache。
让Ehcache和mybatis进行整合。
实际上还是mybatis进行控制Ehcache,把缓存的数据存储在内存当中!
示例代码:https://github.com/libolibolibo/mybatis1217_22.git
这里附上mybatis的逆向工程(开发时可以使用该工程):https://github.com/libolibolibo/generatorSqlmapCustom
相关文章推荐
- maven搭建项目--实现mybatis增删改差、一对多及一对一关系
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- Mediar.Framework—业务的实现3 (控制UI控件的可视和可编辑属性、验证、以及一对一,一对多,多对多关系)
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加
- Hibernate中一对一以及一对多之间的关系
- mybatis对象之间映射关系以及数据库表建立的时候外键的添加