mybatis框架--学习笔记(下)

上篇:mybatis框架--学习笔记(上):https://blog.csdn.net/a745233700/article/details/81034021


8、高级映射:

(1)一对一查询:

①使用resultType:

<!-- 一对一查询:resultType -->
<select id="findOrdersUser" resultType="com.zwp.po.OrdersCustom">
	select orders.*,
		user.username,
		user.sex,
		user.address
 	from orders,user
	where orders.user_id=user.id
</select>
//Orders的扩展类
public class OrdersCustom extends Orders{
	//添加用属性
	private String username;
	private String sex;
	private String address;
	//下面省略get和set方法..
}

②使用resultMap:(association)

使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,将关联查询出来的用户信息映射到orders对象中的user属性中。

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    
    private User user;//在Orders中添加User属性,一对一
    
    //下面省略get和set方法
}
	<!-- 一对一查询:resultMap
		使用resultMap将查询结果中的订单信息映射到Orders对象中,在orders类中添加User属性,
	 	将关联查询出来的用户信息添加到orders对象的user属性中-->
	 <resultMap type="com.zwp.po.Orders" id="OrdersUserResultMap">
	 	<!-- 配置订单信息的映射 -->
	 	<!-- id:指定查询列中的唯一标识,即订单信息的唯一标识,如果有多个列组成唯一标识,则配置多个id
	 		column:查询出来的列名; property:映射到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="com.zwp.po.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> 
	 </resultMap>	
	 <select id="findOrdersUserResultMap" resultMap="OrdersUserResultMap">
		 select orders.*,
				user.username,
				user.sex,
				user.address
	 	from orders,user
		where orders.user_id=user.id
	 </select>

小结:实现一对一查询:

resultyType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求,建议使用resultyType。

resultMap:需要 单独定义resultMap,实现有点麻烦,如果有对查询结果有特殊要求,使用resultMap可以完成将关联查询映射到pojo的属性中。

resultMap可以实现延时加载,resultyType无法实现延时加载。


(2)一对多查询:(collection)

要求:对orders映射不能出现重复记录。

思路:在order.java类中添加List<OrderDetail>orderDetails属性,最终会将订单信息映射到orders中,订单所对应的订单明细映射到orders中的orderDetails属性中。

public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    
    private User user;//用户信息,一对一
    
    //订单明细:一对多
    private List<Orderdetail> orderdetail;

    //省略get和set方法
}
         <!-- 一对多查询: -->
	  <resultMap type="com.zwp.po.Orders" id="OrdersAndOrderdetailResultMap" extends="OrdersUserResultMap">
	 	<!-- 订单信息 -->
	 	<!-- 用户信息 -->
	 	<!-- extends继承:可以不用再配置订单信息和用户信息的映射 -->
	 	
	 	<!-- 订单明细信息:
	 	一个订单关联查询出了多条明细,要使用collection进行映射
	 	collection:对关联查询多条映射到集合对象中;
	 	property:将关联查询多条映射到pojo的哪个属性中;
	 	ofType:指定映射到list集合属性中pojo的类型。
	 	 -->
	 	<collection property="orderdetail" ofType="com.zwp.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>
	 
	 <select id="findOrdersAndOrderdetailResultMap" resultMap="OrdersAndOrderdetailResultMap">
		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
	 </select>

小结:mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。

如果使用resultType实现:将订单明细映射到orders中的ordertails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在ordertails中。


(3)多对多查询:

映射思路:将用户信息映射到user中。

在user类中添加订单列表属性List<Orders>orderslist,将用户创建的订单映射到orderlist;

在Orders中添加订单明细列表属性List<OrderDetail>orderdetails,将订单的明细映射到orderdetails;

在OrderDetail中添加items属性,将订单明细所对应的商品映射到items。

	 <!-- 多对多查询 -->
	 <resultMap type="com.zwp.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"/>
	 	<!-- 配置订单信息:用户对订单:一对多关系:collection -->
	 	<collection property="orders" ofType="com.zwp.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" />
		 	<!-- 配置订单详情信息:订单对订单详情:一对多关系:collection -->
		 	<collection property="orderdetail" ofType="com.zwp.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"/>
		 		<!-- 配置商品信息:订单详情对商品:一对一:association -->
		 		<association property="items" javaType="com.zwp.po.Items">
		 			<id column="itemsid" property="id"/>
			 		<result column="name" property="name"/>
			 		<result column="price" property="price"/>
			 		<result column="detail" property="detail"/>
			 		<result column="items_creatime" property="creatime"/>
		 		</association>
		 	</collection>
	 	</collection>
	 </resultMap>
	
	 <select id="findUserAndItemsResultMap" resultMap="UserAndItemsResultMap">
		select orders.*,
			user.username,
			user.sex,
			user.address,
			orderdetail.id orderdetail_id,
			orderdetail.items_id,
			orderdetail.items_num,
			orderdetail.orders_id,
			items.id itemsid,
			items.name,
			items.price,
			items.detail,
			items.creatime items_creatime
		from orders,user,orderdetail,items
		where orders.user_id=user.id and orderdetail.orders_id=orders.id and items_id=items.id
	 </select>
public class User {
    private Integer id;
    private String username;
    private String birthday;
    private String sex;
    private String address;
    
    private List<Orders> orders;
}
public class Orders {
    private Integer id;
    private Integer userId;
    private String number;
    private Date createtime;
    private String note;
    
    private User user;
 
    private List<Orderdetail> orderdetail;
}
public class Orderdetail {
    private Integer id;
    private Integer ordersId;
    private Integer itemsId;
    private Integer itemsNum;
    
    private Items items;
}
public class Items {
    private Integer id;
    private String name;
    private Float price;
    private String pic;
    private Date creatime;
    private String detail;
}

(4)总结:

①resultMap:使用association和collection完成一对一和一对多高级映射,用于对结果有特殊的映射要求。

②association:

    作用:将关联查询信息映射到一个pojo对象中。

    场合:为了方便查询关联信息,可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。

    使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对结果集查询遍历的需要选择使用resultType还是resultMap。

③collection:

    作用:将关联查询信息映射到一个list集合中。

    场合:为了方便查询遍历关联信息可以使用collection,将关联信息映射到list集合中,比如:查询用户权限范围模块下及模块下的菜单,可以使用collection将其权限模块映射到权限模块list中,将菜单列表映射到权限模块对象的菜单list属性中,这样做的目的也是方便对查询结果进行遍历查询。

    如果使用resultType无法将查询结果映射到List集合中。



9、延时加载:

resultMap的association和collection具备延时加载功能。

延时加载:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多表速度要快。

(1)使用association中的select指定延迟加载去执行的statement的id

	<!-- 延迟加载:
		查询用户订单信息:用户信息要求延迟加载 -->
	<resultMap type="com.zwp.po.Orders" id="OrderUserLazyLoading">
		<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,如果不在同一个namespace,需要加上namespace
	 		column:表示关联的字段-->
	 	<association property="user" javaType="com.zwp.po.User" select="findUserById" column="user_id">
	 		<id column="user_id" property="id" />
		 	<result column="username" property="username" />
		 	<result column="sex" property="sex" />
		 	<result column="address" property="address" />
		 	<result column="birthday" property="birthday" />
	 	</association>
	</resultMap>	
		
	<!-- 不可以使用resultType,因为resultType没有延迟加载功能 -->
	<select id="findOrderUserLazyLoading" resultMap="OrderUserLazyLoading">
		select * from orders
	</select>
	
	<!-- 查询订单关联查询用户,用户信息需要延时加载 -->
	<select id="findUserById" parameterType="int" resultType="com.zwp.po.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>

(2)延迟加载配置:

Mybatis默认没有开启延时加载,需要在SqlMapperConfig.xml中的setting配置。

	<!-- settings:配置全局变量 -->
	<settings>
		<!-- 开启延迟加载开关 -->
		<setting name="lazyLoadingEnabled" value="true"/>
		<!-- 将积极加载改为消极加载,即按需加载 -->
		<setting name="aggressiveLazyLoading" value="false"/>
	</settings>

(3)总结:

使用延时加载方法,先去查询简单的sql(最好是单表,也可以关联查询),再去按需要加载关联查询的其他信息。



10、一级缓存:(mybatis默认支持一级缓存)

缓存:提高系统的性能,减少数据库的压力。




11、二级缓存:(默认不开启)


(1)开启二级缓存:

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

	<!-- settings:配置全局变量 -->
	<settings>
		<!-- 开启二级缓存 -->
		<setting name="cacheEnabled" value="true"/>
	</settings>

②在xxxMapper.xml文件中开启二级缓存,xxxMapper.xml下的sql执行完会存储到他的缓存区域(HashMap)

<mapper namespace="com.zwp.mapper.OrdersMapperCustom">
	<!-- 开启本mapper下的二级缓存
	<cache/>
</mapper>	

(2)useCache配置:禁用二级缓存:

在statement中设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认是true,即改sql使用二级缓存。

<select id="findOrderListResultMap" resultMap="ordersUserMap" useCache="false">

场景:针对每次查询都需要更新的数据sql,要设置成useCache=false,禁用二级缓存。

(3)刷新缓存(清空缓存):

设置statement配置中的flushCache="true"属性,默认情况下为true即刷新缓存,如果改成false则不会刷新。

<insert id="insertUser" parameterType="com.zwp.domain.User" flushCache="true">

场景:一般情况下执行完commit操作都需要刷新缓存,flushCache=true表示刷新缓存,这样可以避免数据库脏读。



12、分布缓存:mybatis整合ehcache:

分布缓存:可以实现对缓存数据进行集中管理。

(1)Mybatis无法实现分布式缓存,需要和其他分布式缓存框架进行整合。

(2)整合方法:

        mybatis提供了一个cache接口,如果要实现自己的缓存逻辑,实现cache接口开发即可。

       mybatis和ehcache整合,mybatis和ehcache整合包中提供了一个Cache接口的实现类。



(3)加入jar包依赖:


(4)整合ehcache:


<mapper namespace="com.zwp.mapper.OrdersMapperCustom">
	<!-- 开启本mapper下的二级缓存
	type:指定cache接口的实现的类型,mybatis默认使用PerpetualCache-->
	<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

(5)加入ehcache的配置文件:

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
<diskStore path="D:\develop\ehcache" />
<defaultCache
maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
</defaultCache>
</ehcache> 



13、mybatis和spring整合开发:

需要spring通过单例方式管理SqlSessionFactory。

spring和mybatis整合生成代理对象,使用SqlSessionFactory创建SqlSession,持久层的mapper都需要由spring进行管理。

步骤:

(1)导入jar包依赖:

(2)sqlSessionFactory配置:

在applicationContext.xml配置sqlSessionFatory,sqlSessionFatory在mybatis和spring的整合包下。

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	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.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd">
		
	<!-- 1.加载数据库配置文件 -->
	<context:property-placeholder location="classpath:db.properties"/>
		
	<!-- 2.配置连接池 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
		<property name="driverClass" value="${jdbc.driver}"></property>
		<property name="jdbcUrl" value="${jdbc.url}"></property>
		<property name="user" value="${jdbc.username}"></property>
		<property name="password" value="${jdbc.password}"></property>
	</bean>

	<!-- 3.创建会话工厂sqlSessionFactory -->		
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<!-- 加载mybatis的配置文件 -->
		<property name="configLocation" value="mybatis/SqlMapConfig.xml"></property>
		<!-- 配置数据源 -->
		<property name="dataSource" ref="dataSource"></property>
	</bean>
</beans>
		

(3)①原始dao开发:

--User.xml文件:

<mapper namespace="test">
	<select id="findUserById" parameterType="int" resultType="com.zwp.ssm.po.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>	 
</mapper>

在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>
	<!-- 加载映射文件 -->
	<mappers>
		<!-- 通过resource加载单个映射文件 -->
		<mapper resource="sqlmap/User.xml"></mapper>
	</mappers>
</configuration>
--Dao:(实现类继承SqlSessionDaoSupport
public interface UserDao {
	//根据id查询用户
        public User findUserById(int id) throws Exception;
}

DaoImpl接口实现类需要注入sqlSessionFactory,通过spring进行注入:

public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao{
	//继承SqlSessionDaoSupport
	//父类已经定义SqlSessionFactory对象和set方法,不需要重新写
	@Override
	public User findUserById(int id) throws Exception{
		
		SqlSession sqlSession=this.getSqlSession();//不需要手动关闭sqlSession
		System.out.println(sqlSession);
		User user=sqlSession.selectOne("test.findUserById",id);
		return user;
	}
}

通过spring创建接口的bean对象:

	<!--原始dao接口 -->
	<bean id="userDao" class="com.zwp.Dao.UserDaoImpl">
		<!-- sqlSessionFactory不能写错 -->
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>
(3)②mapper代理开发:

--mapper.xml和mapper.java:


public interface UserMapper {
	/*
	(1)mapper.java接口中方法名和mapper.xml中的statement的id一致
	(2)mapper.java接口中方法的输入参数类型和mapper.xml中statement的parameterType指定的类型一致
	(3)mapper.java接口中方法的返回值类型和mapper.xml中statement的resultment中resultType指定类型一致。
	 */
	
	//根据id查询用户
	public User findUserById(int id) throws IOException;
}
<?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.zwp.ssm.mapper.UserMapper">
	<select id="findUserById" parameterType="int" resultType="com.zwp.ssm.po.User">
		SELECT * FROM USER WHERE id=#{id}
	</select>	
</mapper>

----通过mapperFactoryBean创建代理对象(此方法存在问题):

<!-- mapper接口 -->
	<!-- MapperFactoryBean:根据mapper接口生成代理对象 -->
	<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
		<!-- mapperInterface指定mapper接口 -->
		<property name="mapperInterface" value="com.zwp.ssm.mapper.UserMapper"></property>
		<property name="sqlSessionFactory" ref="sqlSessionFactory"></property>
	</bean>

此方法的问题:如果有很多个mapper,需要针对每个mapper进行单独配置。

解决方法:通过MapperScannerConfigure进行mapper批量扫描。

	<!-- mapper批量扫描,从mapper包中扫描出mapper,自动创建代理对象并且在spring容器中注册
	遵循规范:需要mapper接口类名和mapper.xml映射文件名称一致,且在同一目录下 
	自动扫描出来的mapper的bean的id为类名(首字母小写)-->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 指定扫描的包名 -->
		<!-- 如果扫描多个包,每个包中间使用半角逗号隔开 -->
		<property name="basePackage" value="com.zwp.ssm.mapper"></property>
		<!-- sqlSessionFactoryBeanName不能写成sqlSessionFactory,不然会导致连接不上数据库 -->
		<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
	</bean>


猜你喜欢

转载自blog.csdn.net/a745233700/article/details/81035781