mybatis框架–学习笔记(下)

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默认支持一级缓存)

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

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

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


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

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

(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接口的实现类。

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

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

(3)加入jar包依赖:

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

(4)整合ehcache:

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

<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:

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

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>

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/114728.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号