mybatis入门及初步使用(3)
一.自定义结果映射:
当我们数据库表的字段和pojo的属性不一致时,有两种解决方案:
1.给sql语句的对应字段起别名,别名就是pojo的属性名(简单不演示)
2.自定义结果映射
自定义结果映射:
这种情况就会出现名称不一致导致的查询之后自动映射不上
配置resultMap:
<!--手动映射结果集 id:当前resultMap的唯一标识 type:当前手动映射的是哪一个pojo类-->
<resultMap id="videoMap" type="Video">
<!--id:映射表的id和pojo类的id
column:表的列名
property:pojo类的属性名-->
<id column="id" property="id" />
<!--result映射除了id的其他属性-->
<result column="price1" property="price" />
</resultMap>
在对应的sql上把resultType替换为resultMap:
<select id="selectByVideoId" resultMap="videoMap">
select
id,title,summary,cover_img,price1,create_time,point
from
video
where
id = #{id}
</select>
这样结果就根据我们配置的手动映射来匹配
注意:当单个表操作时,不涉及多对一、一对多、一对一等操作时,可以只写名称不一致的那个映射,其他的不用写,还是会自动映射,只要涉及以上操作时,必须全部手动映射,自动映射不生效
二.一对多、多对一操作:
在实际业务中,会涉及很多的一对多、多对一操作,而这些对应关系在orm中也可以体现
数据库表示一对多、多对一关系:建立外键
实体类表示一堆都、多对一关系:多对一时,多的一方添加一的一方的对象存储数据。一对多时,一的一方添加List、Set集合存储多的数据
剩下的也就是映射文件中如何表示多对一、一对多关系:
- 一对多:一个用户有多个订单
数据库:
pojo类:
sql语句:
<!-- //查询用户并查询出该用户的所有订单
User selectByUserId(@Param("id")int id);-->
<select id="selectByUserId" resultMap="selectUserMap">
select
u.id,
u.name,
u.pwd,
u.head_img,
u.phone,
vo.id as voId,
vo.out_trade_no,
vo.state,
vo.total_fee,
vo.video_id,
vo.video_title,
vo.video_img
from
user u, video_order vo where u.id = vo.user_id and u.id = #{id}
</select>
手动映射:
<!--id:唯一表示
type:手动映射的是那个pojo-->
<resultMap id="selectUserMap" type="User">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="pwd" property="pwd" />
<result column="head_img" property="headImg" />
<result column="phone" property="phone" />
<!--映射一对多时,使用此标签
property:pojo类中的属性名
ofType:此集合中包含什么类型的 -->
<collection property="videoOrders" ofType="VideoOrder">
<!--里面内容同上边一致-->
<id column="voId" property="id" />
<result column="out_trade_no" property="outTradeNo" />
<result column="state" property="state" />
<result column="total_fee" property="totalFee" />
<result column="video_id" property="videoId" />
<result column="video_title" property="videoTitle" />
<result column="video_img" property="videoImg" />
</collection>
</resultMap>
注意:如果使用了任何的关联关系,则一定要全部手动映射,否则映射不上数据!
结果:
User{
id=6,
name='Wiggin',
pwd='df34rg3feqg',
headImg='http://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTIlPAtqFWzr6zQa33esvNNy1MsNw3Ik4O4nGzzcLSW9y9ia8xticev4RtT4JVK5USjUPQqfJarC3lOQ/132',
phone='null',
createTime=null,
//此处就是映射完毕的订单数据
videoOrders=[
VideoOrder{id=4,
outTradeNo='2342323',
state=1,
createTime=null,
totalFee=42,
videoId=17,
videoTitle='互联网架构多线程并发编程高级教程',
videoImg='null',
userId=0}, ...]
一对多映射完毕!
- 多对一映射:
数据库:
实体类:
sql语句:
<select id="selectByNo" resultMap="selectVideoOrderMap">
select
vo.id,
vo.out_trade_no,
vo.state,
vo.total_fee,
vo.video_id,
vo.video_title,
vo.video_img,
u.id as uId,
u.name,
u.pwd,
u.head_img,
u.phone
from
video_order vo, user u where vo.user_id = u.id and vo.out_trade_no = #{no}
</select>
resultMap:
<resultMap id="selectVideoOrderMap" type="VideoOrder">
<id column="voId" property="id" />
<result column="out_trade_no" property="outTradeNo" />
<result column="state" property="state" />
<result column="total_fee" property="totalFee" />
<result column="video_id" property="videoId" />
<result column="video_title" property="videoTitle" />
<result column="video_img" property="videoImg" />
<!--映射单个对象时使用
property:pojo类中的属性名
javaType:属性名对应的类型-->
<association property="user" javaType="User">
<id column="id" property="id" />
<result column="name" property="name" />
<result column="pwd" property="pwd" />
<result column="head_img" property="headImg" />
<result column="phone" property="phone" />
</association>
</resultMap>
总结:
association:处理多对一或者一对一关系,映射一个pojo类
collection:处理一对多关系,映射一个集合
模板:
<!-- column不做限制,可以为任意表的字段,而property须为type 定义的pojo属性-->
<resultMap id="唯一的标识" type="映射的pojo对象">
<id column="表的主键字段,或查询语句中的别名字段" jdbcType="字段类型" property="映射pojo对象的主键属性" />
<result column="表的一个字段" jdbcType="字段类型" property="映射到pojo对象的一个属性"/>
<association property="pojo的一个对象属性" javaType="pojo关联的pojo对象">
<id column="关联pojo对象对应表的主键字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
<result column="表的字段" jdbcType="字段类型" property="关联pojo对象的属性"/>
</association>
<!-- 集合中的property 需要为oftype定义的pojo对象的属性-->
<collection property="pojo的集合属性名称" ofType="集合中单个的pojo对象类型">
<id column="集合中pojo对象对应在表的主键字段" jdbcType="字段类型" property="集合中pojo对象的主键属性" />
<result column="任意表的字段" jdbcType="字段类型" property="集合中的pojo对象的属性" />
</collection>
</resultMap>
三.mybatis的缓存:
- 一级缓存:
sqlsession级别的,默认开启,在整个sqlsession中,只要sql语句完全相同,那么他就会去内存中找,而不直接去数据库查找,优化程序速度。底层采用的是map。
失效策略:
1.当执行相同查询sql中间执行任意操作而提交之后,会清楚该缓存
2.sqlSession关闭、清空缓存
- 二级缓存:
二级缓存是namespace级别的,多个SqlSession去操作同一个namespace下的Mapper的sql语句,多个SqlSession可以共用二级缓存,如果两个mapper的namespace相同,(即使是两个mapper,那么这两个mapper中执行sql查询到的数据也将存在相同的二级缓存区域中,但是最后是每个Mapper单独的名称空间)
底层也是采用的map
操作流程:第一次调用某个namespace下的SQL去查询信息,查询到的信息会存放该mapper对应的二级缓存区域。 第二次调用同个namespace下的mapper映射文件中,相同的sql去查询信息,会去对应的二级缓存内取结果
失效策略:执行同个namespace下的mapepr映射文件中增删改sql,并执行了commit操作,会清空该二级缓存
注意:实现二级缓存的时候,MyBatis建议返回的POJO是可序列化的, 也就是建议实现Serializable接口
缓存淘汰策略:会使用默认的 LRU 算法来收回(最近最少使用的)