文档版本 | 开发工具 | 测试平台 | 工程名字 | 日期 | 作者 | 备注 |
---|---|---|---|---|---|---|
V1.0 | 2016.06.28 | lutianfei | none |
mybatis框架履行进程:
mapper代理开发方法(建议使用)
本文内容:
商品表:items
表与表之间的业务关系:
在分析表与表之间的业务关系时需要建立在某个业务意义基础上去分析。
先分析数据级别之间有关系的表之间的业务关系:
usre和orders:
orders和orderdetail:
orderdetail和itesm:
再分析数据库级别没有关系的表之间是不是有业务关系:
SELECT
orders.*,
USER.username,
USER.sex,
USER.address
FROM
orders,
USER
WHERE orders.user_id = user.id
OrdersMapperCustom.java
编写测试类
public class OrdersMapperCustomTest {
private SqlSessionFactory sqlSessionFactory;
// 此方法是在履行testFindUserById之前履行
@Before
public void setUp() throws Exception {
// 创建sqlSessionFactory
// mybatis配置文件
String resource = "SqlMapConfig.xml";
// 得到配置文件流
InputStream inputStream = Resources.getResourceAsStream(resource);
// 创建会话工厂,传入mybatis的配置文件信息
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
}
@Test
public void testFindOrdersUser() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<OrdersCustom> list = ordersMapperCustom.findOrdersUser();
System.out.println(list);
sqlSession.close();
}
sql语句 : 同resultType实现的sql
使用resultMap映照的思路
Orders类中添加user属性
OrdersMapperCustom.xml
<!-- 定单查询关联用户的resultMap
将全部查询的结果映照到cn.itcast.mybatis.po.Orders中
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersUserResultMap">
<!-- 配置映照的定单信息 -->
<!-- id:指定查询列中的唯 1标识,定单信息的中的唯 1标识,如果有多个列组成唯1标识,配置多个id
column:定单信息的唯 1标识 列
property:定单信息的唯 1标识 列所映照到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/>
<!-- 配置映照的关联的用户信息 -->
<!-- association:用于映照关联查询单个对象的信息
property:要将关联查询的用户信息映照到Orders中哪一个属性
-->
<association property="user" javaType="cn.itcast.mybatis.po.User">
<!-- id:关联查询用户的唯1标识
column:指定唯 1标识用户信息的列
javaType:映照到user的哪一个属性
-->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
</association>
</resultMap>
OrdersMapperCustom.java
测试代码
@Test
public void testFindOrdersUserResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<Orders> list = ordersMapperCustom.findOrdersUserResultMap();
System.out.println(list);
sqlSession.close();
}
如果没有查询结果的特殊要求建议使用resultType。
resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映照pojo的属性中。
需求 : 查询定单及定单明细的信息。
sql语句
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 orderdetail.orders_id=orders.id
分析 : 使用resultType将上边的 查询结果映照到pojo中,定单信息的就是重复。
要求:对orders映照不能出现重复记录。
List<orderDetail>
orderDetails属性。在Orders.java中添加list定单明细属性
OrdersMapperCustom.xml
<!-- 定单及定单明细的resultMap
使用extends继承,不用在中配置定单信息和用户信息的映照
-->
<resultMap type="cn.itcast.mybatis.po.Orders" id="OrdersAndOrderDetailResultMap" extends="OrdersUserResultMap">
<!-- 定单信息 -->
<!-- 用户信息 -->
<!-- 使用extends继承,不用在中配置定单信息和用户信息的映照 -->
<!-- 定单明细信息
1个定单关联查询出了多条明细,要使用collection进行映照
collection:对关联查询到多条记录映照到集合对象中
property:将关联查询到多条记录映照到cn.itcast.mybatis.po.Orders哪一个属性
ofType:指定映照到list集合属性中pojo的类型
-->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<!-- id:定单明细唯 1标识
property:要将定单明细的唯1标识映照到cn.itcast.mybatis.po.Orderdetail的哪一个属性
-->
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
</collection>
</resultMap>
OrdersMapperCustom.java
测试代码:
@Test
public void testFindOrdersAndOrderDetailResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<Orders> list = ordersMapperCustom
.findOrdersAndOrderDetailResultMap();
System.out.println(list);
sqlSession.close();
}
需求 : 查询用户及用户购买商品信息。
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
映照思路
List<Orders>
orderslist,将用户创建的定单映照到orderslistList<OrderDetail>
orderdetials,将定单的明细映照到orderdetialsOrdersMapperCustom.xml
<!-- 查询用户及购买的商品 -->
<resultMap type="cn.itcast.mybatis.po.User" id="UserAndItemsResultMap">
<!-- 用户信息 -->
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
<result column="address" property="address"/>
<!-- 定单信息 1个用户对应多个定单,使用collection映照-->
<collection property="ordersList" ofType="cn.itcast.mybatis.po.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"/>
<!-- 定单明细 1个定单包括 多个明细-->
<collection property="orderdetails" ofType="cn.itcast.mybatis.po.Orderdetail">
<id column="orderdetail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<result column="orders_id" property="ordersId"/>
<!-- 商品信息1个定单明细对应1个商品-->
<association property="items" javaType="cn.itcast.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_detail" property="detail"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
OrdersMapperCustom.java
测试代码:
@Test
public void testFindUserAndItemsResultMap() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 创建代理对象
OrdersMapperCustom ordersMapperCustom = sqlSession
.getMapper(OrdersMapperCustom.class);
// 调用maper的方法
List<User> list = ordersMapperCustom.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
}
1对多是多对多的特例,以下需求:
总结:
场合:
resultMap:
association:
场合:
collection:
resultMap可以实现高级映照(使用association、collection实现1对1及1对多映照),association、collection具有延迟加载功能。
需求:
延迟加载:先从单表查询、需要时再从关联表去关联查询,大大提高数据库性能,由于查询单表要比关联查询多张表速度要快。
需求 : 查询定单并且关联查询用户信息
OrdresMapperCustom.xml
需要定义两个mapper的方法对应的statement。
1、只查询定单信息
SELECT * FROM orders
在查询定单的statement中使用association去延迟加载(履行)下边的satatement(关联查询用户信息)
2、关联查询用户信息
上边先去履行findOrdersUserLazyLoading,当需要去查询用户的时候再去履行findUserById,通过resultMap的定义将延迟加载履行配置起来。
延迟加载resultMap
<!-- 延迟加载的resultMap -->
<resultMap type="cn.itcast.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"/>
<!-- 实现对用户信息进行延迟加载
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.mybatis.po.User"
select="cn.itcast.mybatis.mapper.UserMapper.findUserById" column="user_id">
<!-- 实现对用户信息进行延迟加载 -->
</association>
</resultMap>
OrderesMapperCustom.java
测试思路:
List<Orders>
,当我们调用Orders中的getUser方法时,开始进行延迟加载。mybatis默许没有开启延迟加载,需要在SqlMapConfig.xml中setting
配置。
在mybatis核心配置文件中配置:
设置项 | 描写 | 允许值 | 默许值 |
---|---|---|---|
lazyLoadingEnabled | 全局性设置懒加载。如果设为‘false’,则所有相干联的都会被初始化加载。 | true or false | false |
aggressiveLazyLoading | 当设置为‘true’的时候,懒加载的对象可能被任何懒属性全部加载。否则,每一个属性都按需加载。 | true or false | true |
在SqlMapConfig.xml中配置:
测试代码
延迟加载思考
实现方法以下:
总之:使用延迟加载方法,先去查询简单的sql(最好单表,也能够关联查询),再去按需要加载关联查询的其它信息。
1级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有1个数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是相互不影响的。
2级缓存是mapper级别的缓存,多个SqlSession去操作同1个Mapper的sql语句,多个SqlSession可以共用2级缓存,2级缓存是跨SqlSession的。
为何要用缓存?
1级缓存工作原理
第1次发起查询用户id为1的用户信息,先去找缓存中是不是有id为1的用户信息,如果没有,从数据库查询用户信息。
//OrdersMapperCusntomTest.java
@Test
public void testCache1() throws Exception{
SqlSession sqlSession = sqlSessionFactory.openSession();//创建代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//下边查询使用1个SqlSession
//第1次发起要求,查询id为1的用户
User user1 = userMapper.findUserById(1);
System.out.println(user1);
// 如果sqlSession去履行commit操作(履行插入、更新、删除),清空SqlSession中的1级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。
//更新user1的信息
user1.setUsername("测试用户22");
userMapper.updateUser(user1);
//履行commit操作去清空缓存
sqlSession.commit();
//第2次发起要求,查询id为1的用户
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
service{
//开始履行时,开启事务,创建SqlSession对象
//第1次调用mapper的方法findUserById(1)
//第2次调用mapper的方法findUserById(1),从1级缓存中取数据
//方法结束,sqlSession关闭
}
首先开启mybatis的2级缓存。
sqlSession1去查询用户id为1的用户信息,查询到用户信息会将查询数据存储到2级缓存中。
如果SqlSession3去履行相同 mapper下sql,履行commit提交,清空该 mapper下的2级缓存区域的数据。
sqlSession2去查询用户id为1的用户信息,去缓存中找是不是存在数据,如果存在直接从缓存中取出数据。
2级缓存与1级缓存区分,2级缓存的范围更大,多个sqlSession可以同享1个UserMapper的2级缓存区域。
<setting name="cacheEnabled" value="true"/>
描写 | 允许值 | 默许值 |
---|---|---|
cacheEnabled | 对在此配置文件下的所有cache 进行全局性开/关设置。 | true or false |
调用pojo类实现序列化接口
2级缓存测试
@Test
public void testCache2() throws Exception {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
// 创建代理对象
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
// 第1次发起要求,查询id为1的用户
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//这里履行关闭操作,将sqlsession中的数据写到2级缓存区域
sqlSession1.close();
//使用sqlSession3履行commit()操作
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user = userMapper3.findUserById(1);
user.setUsername("张明明");
userMapper3.updateUser(user);
//履行提交,清空UserMapper下边的2级缓存
sqlSession3.commit();
sqlSession3.close();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
// 第2次发起要求,查询id为1的用户
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">
<insert id="insertUser" parameterType="cn.itcast.mybatis.po.User" flushCache="true">
ehcache是1个散布式缓存框架。
散布缓存
mybatis和ehcache整合,mybatis和ehcache整合包中提供了1个cache接口的实现类。
mybatis默许实现cache类是:
加入ehcache包
整合ehcache
加入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>
<defalutCache/>
指定的的管理策略上一篇 识别喜欢开发的程序员
下一篇 HDU 3572 网络流