数据库级别
表与表的关系(即:明确数据库中表与表之间的外键关系)
业务关系
(即:明确业务中表与表的关系(创建在具体的业务上))
sql语句以下:php
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex
FROM
orders,
user
WHERE orders.user_id = user.id;
(1)建立扩展PO类
通常User.java类要和数据表表字段一致,最好不要在这里面添加其余字段,今天学习mybatis的逆向工程时,会根据表结构,生成po类,若是在po类中扩展字段,此时会被覆盖掉。
因此针对要扩展的po类,咱们须要建立一个扩展类,来继承它。html
/**
* 经过此类映射订单和用户查询的结果,让此类继承包括字段较多的pojo类
* @author Bruce
*
*/
public class OrdersExt extends Orders {
// 添加用户属性
// user.username
// user.sex
private String username;
private String sex;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
(2)编写mapper接口
建立OrdersMapper接口类,在类中添加如下内容:前端
public interface OrdersMapper {
// 一对一映射之 resultType
// 查询订单信息,关联查询建立订单的用户信息(用户名称和性别)
public List<OrdersExt> findOrdersAndUser();
}
(3)编写映射文件
建立OrdersMapper.xml映射文件,在映射文件中添加如下内容:java
<mapper namespace="com.itheima.mybatis.mapper.OrdersMapper">
<!-- 一对一映射之 resultType -->
<!-- 查询订单信息,关联查询建立订单的用户信息(用户名称和性别) -->
<select id="findOrdersAndUser" resultType="com.itheima.mybatis.po.OrdersExt">
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex
FROM
orders,
user
WHERE orders.user_id = user.id
</select>
</mapper>
(4)加载映射文件
在config/SqlMapConfig.xml中,添加如下内容:mysql
<!-- 加载mapper,即加载映射文件 -->
<mappers>
<!-- 使用相对于类路径的资源,加载配置文件 -->
<!--
<mapper resource="sqlmap/User.xml"/>
<mapper resource="mapper/UserMapper.xml"/>
<mapper resource="mapper/OrdersMapper.xml"/>
-->
<!-- 推荐使用:批量加载mapper文件,须要mapper接口文件和mapper映射文件名称相同且在同一个包下 -->
<package name="com.itheima.mybatis.mapper"/>
</mappers>
(5)编写测试代码git
@Test
public void testFindUserById() {
// 根据SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper对象
// 由Mybatis经过sqlSession来建立动态代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndUser();
System.out.println(list);
sqlSession.close();
}
(6)小结github
平铺式
的映射,即:数据库查询出多少条记录,则映射成多少个对象。对象嵌套对象
的一种映射方式。(1)修改扩展PO类
在OrdersExt类中,添加User对象web
/**
* 经过此类映射订单和用户查询的结果,让此类继承包括字段较多的pojo类
* 在OrdersExt类中,添加User对象
* @author Bruce
*
*/
public class OrdersExt extends Orders {
// 添加用户属性
// user.username
// user.sex
private String username;
private String sex;
// 添加用户对象(用户信息)
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
(2)编写mapper接口redis
// 一对一映射之 resultMap
// 查询订单信息,关联查询建立订单的用户信息(用户名称和性别)
public List<OrdersExt> findOrdersAndUserResultMap();
(3)编写映射文件spring
<!-- 声明/定义一个resultMap -->
<resultMap type="com.itheima.mybatis.po.OrdersExt" id="OrdersAndUserResultMap">
<!-- 订单信息映射 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<!-- 用户信息映射(一对一) -->
<!--
association标签:定义一个一对一关系
property:指定关联对象要映射到OrdersExt的哪一个属性上
javaType:指定关联对象所要映射的java类型
id标签:指定关联对象结果集的惟一标识,很重要,建议在关联查询时必须写上,不写不会报错,可是会影响性能
-->
<association property="user" javaType="com.itheima.mybatis.po.User">
<id column="user_id" property="id"/>
<result column="username" property="username"/>
<result column="sex" property="sex"/>
</association>
</resultMap>
<!-- 一对一映射之 resultMap -->
<!-- 查询订单信息,关联查询建立订单的用户信息(用户名称和性别) -->
<select id="findOrdersAndUserResultMap" resultMap="OrdersAndUserResultMap">
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex
FROM
orders,
user
WHERE orders.user_id = user.id
</select>
(4)加载映射文件
已配置,此处无需再次配置。
(5)编写测试代码
@Test
public void testFindOrdersAndUserResultMap() {
// 根据SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper对象
// 由Mybatis经过sqlSession来建立动态代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndUserResultMap();
System.out.println(list);
sqlSession.close();
}
(6)小结
对象嵌套对象
)时,须要使用resultMap进行映射,好比:查询订单列表,而后在点击列表中的查看订单明细按钮,这个时候就须要使用resultMap进行结果映射。而resultType更适应于查询订单明细信息,好比,查询订单明细列表。实现一对一查询:
若是使用resultMap的话,映射一对多关联关系要使用collection标签
。sql语句以下:
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num
FROM
orders,
user,
orderdetail
WHERE orders.user_id = user.id
AND orders.id = orderdetail.orders_id;
(1)修改扩展PO类
在OrdersExt类中添加如下属性,并提供get/set方法:
// 订单明细信息
private List<Orderdetail> detailList;
public List<Orderdetail> getDetailList() {
return detailList;
}
public void setDetailList(List<Orderdetail> detailList) {
this.detailList = detailList;
}
(2)编写mapper接口
// 一对多映射之 resultMap
// 查询订单信息,关联查询订单明细信息及用户信息
public List<OrdersExt> findOrdersAndOrderdetailResultMap();
(3)编写映射文件
<!-- 声明/定义一个resultMap -->
<!-- extends:继承已有的ResultMap,值为继承的ResultMap的惟一标示 -->
<resultMap type="com.itheima.mybatis.po.OrdersExt" id="OrdersAndOrderdetailResultMap" extends="OrdersAndUserResultMap">
<!-- 订单信息映射 -->
<!-- 用户信息映射(一对一) -->
<!-- 订单明细信息映射(一对多) -->
<!-- collection标签:定义一个一对多关系
ofType:指定该集合参数所映射的类型
-->
<collection property="detailList" ofType="com.itheima.mybatis.po.Orderdetail">
<id column="detail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
</collection>
</resultMap>
<!-- 一对多映射之 resultMap -->
<!-- 查询订单信息,关联查询订单明细信息及用户信息 -->
<select id="findOrdersAndOrderdetailResultMap" resultMap="OrdersAndOrderdetailResultMap">
SELECT
orders.id,
orders.user_id,
orders.number,
user.username,
user.sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num
FROM
orders,
user,
orderdetail
WHERE orders.user_id = user.id
AND orders.id = orderdetail.orders_id
</select>
resultMap的extends属性:能够用此属性来继承一个已有的resultmap。可是它继承的resultMap的type和它自己的type要保持一致。
(4)编写测试代码
@Test
public void testFindOrdersAndOrderdetailResultMap() {
// 根据SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper对象
// 由Mybatis经过sqlSession来建立动态代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndOrderdetailResultMap();
System.out.println(list);
sqlSession.close();
}
sql语句以下:
SELECT
orders.id orders_id,
orders.user_id,
orders.number orders_number,
user.username user_username,
user.sex user_sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num,
items.name items_name,
items.price items_price
FROM
orders,
user,
orderdetail,
items
WHERE user.id = orders.user_id
AND orders.id = orderdetail.orders_id
AND orderdetail.items_id = items.id;
(1)修改扩展PO类
在UserExt类中添加List<Orders>属性
// 添加订单列表
private List<Orders> ordersList;
在OrdersExt类中添加List<Orderdetail>属性
// 订单明细信息
private List<Orderdetail> detailList;
在OrderdetailExt类中添加Items属性
// 添加商品信息
private Items items;
(2)编写mapper接口
在UserMapper.java中,添加如下内容:
// 多对多映射之 resultMap
// 查询用户信息,关联查询该用户购买的商品信息
public List<UserExt> findUserAndItemsResultMap();
(3)编写映射文件
在UserMapper.xml中,添加如下内容:
<!-- 声明/定义一个resultMap -->
<resultMap type="com.itheima.mybatis.po.UserExt" id="UserAndItemsResultMap">
<!-- 用户信息映射-->
<id column="user_id" property="id"/>
<result column="user_username" property="username"/>
<result column="user_sex" property="sex"/>
<!-- 订单信息映射(一对多) -->
<collection property="ordersList" ofType="com.itheima.mybatis.po.OrdersExt">
<id column="orders_id" property="id"/>
<result column="user_id" property="userId"/>
<result column="orders_number" property="number"/>
<!-- 订单明细信息映射(一对多) -->
<collection property="detailList" ofType="com.itheima.mybatis.po.OrderdetailExt">
<id column="detail_id" property="id"/>
<result column="items_id" property="itemsId"/>
<result column="items_num" property="itemsNum"/>
<!-- 商品信息映射(一对一) -->
<association property="items" javaType="com.itheima.mybatis.po.Items">
<id column="items_id" property="id"/>
<result column="items_name" property="name"/>
<result column="items_price" property="price"/>
</association>
</collection>
</collection>
</resultMap>
<!-- 多对多映射之 resultMap -->
<!-- 查询用户信息,关联查询该用户购买的商品信息 -->
<select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
SELECT
orders.id orders_id,
orders.user_id,
orders.number orders_number,
user.username user_username,
user.sex user_sex,
orderdetail.id detail_id,
orderdetail.items_id,
orderdetail.items_num,
items.name items_name,
items.price items_price
FROM
orders,
user,
orderdetail,
items
WHERE user.id = orders.user_id
AND orders.id = orderdetail.orders_id
AND orderdetail.items_id = items.id
</select>
(4)编写测试代码
在UserMapperTest.java中,添加如下内容:
@Test
public void testFindUserAndItemsResultMap() {
// 根据SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立UserMapper对象
// 由Mybatis经过sqlSession来建立动态代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<UserExt> list = mapper.findUserAndItemsResultMap();
System.out.println(list);
sqlSession.close();
}
resultType:
做用:
将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:
常见一些明细记录的展现,好比用户购买商品明细,将关联查询信息所有展现在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)便可。
------------------------------------------------------------
resultMap:
使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。
------------------------------------------------------------
association:
做用:
将关联查询信息映射到一个pojo对象中。
场合:
为了方便查询关联信息可使用association将关联订单信息映射为用户对象的pojo属性中,好比:查询订单及关联用户信息。
使用resultType没法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的须要选择使用resultType仍是resultMap。
------------------------------------------------------------
collection:
做用:
将关联查询信息映射到一个list集合中。
场合:
为了方便查询遍历关联信息可使用collection将关联信息映射到list集合中,好比:查询用户权限范围模块及模块下的菜单,可以使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。
若是使用resultType没法将查询结果映射到list集合中。
按需加载
关联信息。这样会大大提升数据库性能,由于查询单表要比关联查询多张表速度要快。标签中开启延迟加载
功能。配置图以下:
查询订单而且关联查询用户信息(对用户信息的加载要求是按需加载)
(1)编写mapper接口
在OrdersMapper.xml文件中,添加如下内容:
// 延时加载
public List<OrdersExt> findOrderAndUserLazyLoading();
(2)编写映射文件
编写查询订单信息的映射文件
<!-- 定义一个 resultMap-->
<resultMap type="com.itheima.mybatis.po.OrdersExt" id="OrderAndUserLazyLoading">
<!-- 订单信息映射 -->
<id column="id" property="id"/>
<result column="user_id" property="userId"/>
<result column="number" property="number"/>
<!-- 用户信息映射(一对一) -->
<!-- select:指定关联查询的查询statement(即查询用户的statement的id),而后将查询结果,封装到property属性指定的变量中 -->
<!-- column:经过column指定的列所查询出的结果,做为select指的statement的入参
注意:若是select指定的statement,入参须要多个值,须要在column中{col1=prop1,col2=prop2}
-->
<association property="com.itheima.mybatis.po.User"
select="com.itheima.mybatis.mapper.UserMapper.findUserById"
column="user_id">
</association>
</resultMap>
<!-- 延时加载 -->
<select id="findOrderAndUserLazyLoading" resultMap="OrderAndUserLazyLoading">
SELECT * FROM orders
</select>
编写查询用户信息的映射文件
<!-- 根据用户ID,查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="com.itheima.mybatis.po.User">
SELECT * FROM USER WHERE id = #{id}
</select>
(3)编写测试代码
@Test
public void testFindOrdersAndUserLazyLoading() {
// 根据SqlSessionFactory建立SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 建立OrdersMapper对象
// 由Mybatis经过sqlSession来建立动态代理对象
OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
List<OrdersExt> list = mapper.findOrdersAndUserLazyLoading(); // n+1现象,是因为没有使用延时加载而致使的
for (OrdersExt order : list) {
System.out.println(order.getUser()); // 按需加载时,须要的时候再去查询数据库
}
sqlSession.close();
}
(4)设置延迟加载
在SqlMapConfig.xml中,配置settings标签,注意该标签的位置
<settings>
<!-- 开启延迟加载,默认值为true,即默认是当即加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 设置积极的懒加载,默认值是true,false的是按需加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
第一次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,若是没有,从数据库查询用户信息。
获得用户信息,将用户信息存储到一级缓存中。
若是SqlSession去执行commit操做(执行插入、更新、删除),会清空SqlSession中的一级缓存,
这样作的目的为了让缓存中存储的是最新的信息,避免脏读。
第二次发起查询用户id为1的用户信息,先去找缓存中是否有id为1的用户信息,缓存中有,直接从缓存中获取用户信息。
Mybatis默认支持一级缓存。
@Test
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper.findUserById(1);
System.out.println(user1);
// 第二次查询ID为1的用户
User user2 = mapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
只输出一次SQL,以下图所示:
@Test
public void testOneLevelCache() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper.findUserById(1);
System.out.println(user1);
User user = new User();
user.setUsername("晓艺");
user.setAddress("物资学院");
// 执行增删改操做,清空缓存
mapper.insertUser(user);
sqlSession.commit();
// 第二次查询ID为1的用户
User user2 = mapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
中间执行了commit操做,一样的查询SQL输出两次,以下图所示:
例如:
service {
// 开始执行时,开启事务,建立SqlSession对象
// 第一次调用mapper的方法findUserById(1)
// 第二次调用mapper的方法findUserById(1),从一级缓存中取数据
// 方法结束,sqlSession关闭
}
若是是执行两次service调用查询相同的用户信息,不走一级缓存,由于session方法结束,SqlSession就关闭,一级缓存就清空了。
上图详解以下:
二级缓存是mapper级别的。
第一次调用mapper下的SQL去查询用户信息。查询到的信息会存到该mapper对应的二级缓存区域内。
第二次调用相同namespace下的mapper映射文件中相同的SQL去查询用户信息。会去对应的二级缓存内取结果。
若是调用相同namespace下的mapper映射文件中的增删改SQL,并执行了commit操做。此时会清空该namespace下的二级缓存。
Mybatis默认是没有开启二级缓存的。
一、在核心配置文件SqlMapConfig.xml中加入如下内容(开启二级缓存总开关):
在settings标签中添加如下内容:
<!-- 开启二级缓存总开关 -->
<setting name="cacheEnabled" value="true"/>
二、在UserMapper映射文件中,加入如下内容,开启二级缓存:
<!-- 开启本mapper下的namespace的二级缓存,默认使用的是mybatis提供的PerpetualCache -->
<cache></cache>
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper1.findUserById(1);
System.out.println(user1);
// 关闭SqlSession1,在close的时候,才会将数据写入到二级缓存中
sqlSession1.close();
// 第二次查询ID为1的用户
User user2 = mapper2.findUserById(1);
System.out.println(user2);
// 关闭SqlSession2
sqlSession2.close();
// 关闭SqlSession3
sqlSession3.close();
}
SQL输出结果,以下图所示:
@Test
public void testTwoLevelCache() {
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
SqlSession sqlSession3 = sqlSessionFactory.openSession();
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
// 第一次查询ID为1的用户,去缓存找,找不到就去查找数据库
User user1 = mapper1.findUserById(1);
System.out.println(user1);
// 关闭SqlSession1,在close的时候,才会将数据写入到二级缓存中
sqlSession1.close();
User user = new User();
user.setUsername("晓艺");
user.setAddress("物资学院");
// 执行增删改操做,清空缓存
mapper3.insertUser(user);
sqlSession3.commit();
// 第二次查询ID为1的用户
User user2 = mapper2.findUserById(1);
System.out.println(user2);
// 关闭SqlSession2
sqlSession2.close();
// 关闭SqlSession3
sqlSession3.close();
}
SQL输出结果,以下图所示:
根据SQL分析,确实是清空了二级缓存了。
userCache=false
,能够禁用当前select语句的二级缓存,即每次查询都是去数据库中查询,默认状况下是true,即该statement使用二级缓存。以下代码所示: <select id="findUserById" parameterType="int" resultType="com.itheima.mybatis.po.User" useCache="true">
SELECT * FROM USER WHERE id = #{id}
</select>
flushCache=true
能够刷新当前的二级缓存,默认状况下:flushCache设置以下:
<select id="findUserById" parameterType="int" resultType="com.itheima.mybatis.po.User" useCache="true" flushCache="false">
SELECT * FROM USER WHERE id = #{id}
</select>
(1)什么是分布式缓存?
(2)整合思路(重点)
Mybatis提供了一个Cache接口,同时它本身有一个默认的实现类PerpetualCache
。mybatis的特长是sql
,缓存数据管理不是mybatis的特长,为了提升mybatis的性能,因此须要mybatis和第三方缓存数据库整合,好比ehcache、memcache、redis等。(3)整合ehcache的步骤
第一步:引入ehcache的jar包,并添加至构建路径
<!-- 开启本mapper下的namespace的二级缓存,默认使用的是mybatis提供的PerpetualCache -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
第三步:添加ehcache的配置文件
在classpath下的config目录下,添加ehcache.xml,内容以下:
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<!-- 缓存数据要存放的磁盘地址 -->
<diskStore path="e:\others\develop\ehcache" />
<!-- diskStore:指定数据在磁盘中的存储位置。
defaultCache:当借助CacheManager.add("demoCache")建立Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
如下属性是必须的:
maxElementsInMemory - 在内存中缓存的element的最大数目
maxElementsOnDisk - 在磁盘上缓存的element的最大数目,如果0表示无穷大
eternal - 设定缓存的elements是否永远不过时。若是为true,则缓存的数据始终有效,若是为false,那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
overflowToDisk - 设定当内存缓存溢出的时候是否将过时的element缓存到磁盘上 如下属性是可选的:
timeToIdleSeconds - 当缓存在EhCache中的数据先后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds - 缓存element的有效生命期,默认是0,也就是element存活时间无穷大
diskSpoolBufferSizeMB - 这个参数设置DiskStore(磁盘缓存)的缓存区大小,默认是30MB。每一个Cache都应该有本身的一个缓冲区
diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false
diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每隔120s,相应的线程会进行一次EhCache中数据的清理工做
memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
-->
<defaultCache maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache>
第四步:测试ehcache的二级缓存,经过查看缓存命中率
对于访问响应速度要求高,可是实时性不高的查询,能够采用二级缓存技术
。细粒度的数据级别
的缓存实现很差。由于二级缓存是mapper级别的,当一个商品的信息发送更新,全部的商品信息缓存数据都会清空
。能够对常常变化的数据操做单独放到另外一个namespace的mapper中
。Jar包以下(一共28个):
Mybatis3.2.7 的jar包(mybatis核心包、依赖包)
在config下,建立mybatis目录,而后建立SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 自定义别名 -->
<typeAliases>
<!-- 单个定义别名 -->
<!-- <typeAlias type="com.itheima.mybatis.po.User" alias="user"/> -->
<!-- 批量定义别名(推荐) -->
<!-- name:指定批量定义别名的类包,别名为类名(首字母大小写均可) -->
<package name="com.itheima.ms.po"/>
</typeAliases>
<!-- 注意:与spring集成后,数据源和事务交给spring来管理 -->
<!-- 加载mapper,即加载映射文件 -->
<mappers>
<!-- 使用相对于类路径的资源,加载配置文件,后面讲课用:为了验证原始dao的实现方式 -->
<mapper resource="mybatis/sqlmap/User.xml"/>
<!-- 推荐使用:批量加载mapper文件,须要mapper接口文件和mapper映射文件名称相同且在同一个包下 -->
<!-- 由spring来管理原始dao的实现类或者mapper代理的代理类,spring代理的时候,会自动将映射文件加载进去 -->
<package name="com.itheima.ms.mapper"/>
</mappers>
</configuration>
将db.properties和log4j.properties拷贝到config目录下。
在config下,建立spring目录,而后建立applicationContext.xml,内容以下:
<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 ">
<!-- 引用/加载java配置文件 -->
<context:property-placeholder location="db.properties"/> <!-- java工程不须要指定classpath,web工程须要指定 classpath-->
<!-- 配置数据源,使用dbcp数据库链接池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${db.driver}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
<property name="maxActive" value="10"/>
<property name="maxIdle" value="5"/>
</bean>
<!-- 配置spring对SqlSessionFactory进行管理 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 指定mybatis的全局配置文件的路径 -->
<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
<!-- SqlSessionFactory须要数据源信息,以前是写在sqlmapconfig.xml,如今须要从新指定 -->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
(1)编写dao接口
public interface UserDao {
// 根据用户ID来查询用户信息
public User findUserById(int id);
}
(2)编写dao实现类(继承SqlSessionDaoSupport)
经过this.getSqlSession()获取sqlsession。
public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
@Override
public User findUserById(int id) {
return this.getSqlSession().selectOne("test.findUserById", id);
}
}
(3)编写Mapper映射文件
在config/mybatis下建立sqlmap目录,而后建立User.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="test">
<!-- 根据用户ID,查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>
(4)在spring配置文件中配置UserDao实现类
在applicationContext.xml中配置UserDao的实现类
<!-- 配置spring管理原始dao的实现 -->
<bean id="userDao" class="com.itheima.ms.dao.UserDaoImpl">
<!-- 依赖注入sqlSessionFactory,由于UserDao的实现类继承 了SqlSessionDaoSupport-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
(5)编写测试代码
package com.itheima.ms.dao;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.ms.po.User;
public class UserDaoTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 读取spring的上下文,而后封装到ctx
ctx = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
// 建立UserDao对象
UserDao userDao = (UserDao) ctx.getBean("userDao");
// 调用UserDao对象的方法
User user = userDao.findUserById(30);
System.out.println(user);
}
}
(1)编写mapper接口
public interface UserMapper {
// 根据用户ID来查询用户信息
public User findUserById(int id);
}
(2)编写mapper映射文件
将映射文件放到UserMapper接口的同包下
UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.itheima.ms.mapper.UserMapper">
<!-- 根据用户ID,查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="user">
SELECT * FROM USER WHERE id = #{id}
</select>
</mapper>
(3)配置mapper代理类
在spring中定义bean,Mapper代理开发方式有两种bean的定义方法,一种是MapperFactoryBean
,一种是MapperScannerConfigurer(推荐)
。
<!-- mapper代理开发方式之单个mapper配置 -->
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<!-- 设置代理类的接口 -->
<property name="mapperInterface" value="com.itheima.ms.mapper.UserMapper"></property>
<!-- 依赖注入sqlSessionFactory,由于 MapperFactoryBean也继承了SqlSessionDaoSupport-->
<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
</bean>
<!-- mapper代理开发方式之批量mapper配置,默认bean的id为类名首字母小写 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 指定批量mapper配置的包名 -->
<property name="basePackage" value="com.itheima.ms.mapper"></property>
<!-- 当只有一个SqlSessionFactory时,默认是不须要配置SqlSessionFactory的 -->
<!-- 当有多个SqlSessionFactory时,能够指定使用的SqlSessionFactory -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
(4)编写测试代码
package com.itheima.ms.mapper;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.itheima.ms.po.User;
public class UserMapperTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 读取spring的上下文,而后封装到ctx
ctx = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
}
@Test
public void testFindUserById() {
// 建立UserMapper对象
UserMapper userMapper = (UserMapper) ctx.getBean("userMapper");
// 调用UserMapper对象的方法
User user = userMapper.findUserById(30);
System.out.println(user);
}
}
单表
,自动生成java代码。 在config下,建立generatorConfig.xml配置文件:
文件内容能够从逆向工程的jar包中docs目录下的index.html中找到相关代码
文件内容位置:mybatis-generator-core-1.3.2/docs/configreference/xmlconfig.html
<?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>
<!--MySql数据库链接的信息:驱动类、链接地址、用户名、密码 -->
<jdbcConnection
driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mybatis"
userId="root"
password="root">
</jdbcConnection>
<!-- Oracle数据库链接的信息:驱动类、链接地址、用户名、密码 -->
<!--
<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="com.itheima.ms.po" targetProject=".\src">
<!-- enableSubPackages:是否让schema做为包的后缀 -->
<property name="enableSubPackages" value="false" />
<!-- 从数据库返回的值被清理先后的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper映射文件生成的位置 -->
<sqlMapGenerator targetPackage="com.itheima.ms.mapper" targetProject=".\src">
<!-- enableSubPackages:是否让schema做为包的后缀 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper接口生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.itheima.ms.mapper" targetProject=".\src">
<!-- enableSubPackages:是否让schema做为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定要生成mybatis代码的数据库表 -->
<table tableName="items"></table>
<table tableName="orders"></table>
<table tableName="orderdetail"></table>
<table tableName="user"></table>
</context>
</generatorConfiguration>
文件内容位置:mybatis-generator-core-1.3.2/docs/running/runningWithJava.html
Generator.java
public class Generator {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<String>();
boolean overwrite = true;
File configFile = new File("config/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
小问题:经过逆向工程生成的代码会有一个报错,是由于缺乏mybatis的jar包致使的,虽然不影响咱们使用,可是为了好看,咱们导入mybatis-3.2.7.jar,并添加至构建路径,便可解决问题。
小需求:根据商品名称查询商品记录
public class ItemsMapperTest {
// spring上下文
private ApplicationContext ctx;
@Before
public void setUp() throws Exception {
// 读取spring的上下文,而后封装到ctx
ctx = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
}
@Test
public void testSelectByExample() {
// 建立ItemsMapper对象
ItemsMapper itemsMapper = (ItemsMapper) ctx.getBean("itemsMapper");
ItemsExample example = new ItemsExample();
// 使用ItemsExample对象建立离线查询对象
Criteria criteria = example.createCriteria();
// 使用离线查询对象Criteria来封装查询条件
criteria.andNameLike("%包%"); // 由于模糊查询的实现和等值查询的实现式同样的,用到的都是#{xxx},因此须要咱们手动添加%
// 调用ItemsMapper对象的方法
List<Items> list = itemsMapper.selectByExample(example);
System.out.println(list);
}
}
SQL输出结果,以下图所示:
删除原来已经生成的mapper.xml文件再进行生成。