MyBatis简介(四)

映射器

由接口+XML/注解组成;可配置参数、各类SQL语句、存储过程、缓存、级联等,并通过简易的映射规则映射到指定POJO或者其他对象上,能有效消除JDBC底层代码;由于注解对于复杂SQL处理麻烦,自身可读性差,丢失了XML上下文相互引用的实际情况,一般推荐使用XML文件实现;

在这里插入图片描述
(1)select
常用元素配置:
在这里插入图片描述
–MyBatis自带映射:自动映射(POJO的属性名与SQL列名一致或查询时使用别名as使其一致)和驼峰映射(SQL是xxx_yyy,对应POJO是xxxYyy),由setting元素中的配置autoMappingBehavior和mapUnderscoreToCamelCase控制;一般推荐使用自动映射,因为驼峰映射要求会比较严苛;autoMappingBehavior取值有:
NONE:不进行自动映射;
PARTIAL:默认值,只对没有嵌套结果集进行自动映射;
FULL:对所有结果集进行自动映射;

resultMap:对于复杂的映射,如主从表格的级联,字段的转换等;

<resultMap type="cn.infocore.pojo.MyStreamer" id="streamerResultMap">
	<id column="id" property="id"/>
	<result column="username" property="username"/>
	<result column="password" property="password"/>
</resultMap>
<select id="list" resultMap="streamerResultMap">
	select * from Streamer
</select>

传递参数
–单个:#{参数名}
–多个:
—map:业务可读性差,一般不用;
—@Param注解:参数小于等于5个时,推荐使用;
—Java Bean:参数大于5个时,推荐使用;
—混合使用:参数中多个对象,支持EL;

分页参数RowRounds:MyBatis内置了一个专门处理分页的类RowRounds,适用于小数据量的查询,大量数据查询建议使用分页插件,源码如下:

public class RowBounds {
  public static final int NO_ROW_OFFSET = 0; //偏移量,从第几行开始读
  public static final int NO_ROW_LIMIT = Integer.MAX_VALUE;  //限制条数
  public static final RowBounds DEFAULT = new RowBounds();

  private final int offset;
  private final int limit;

  public RowBounds() {
    this.offset = NO_ROW_OFFSET;
    this.limit = NO_ROW_LIMIT;
  }

  public RowBounds(int offset, int limit) {
    this.offset = offset;
    this.limit = limit;
  }

  /****getter setter*****/
}

使用:

public List<MyStreamer> list(RowBounds rowBounds);

SQL:没有RowBounds信息,因为它是MyBatis的一个附加参数,会被自动识别从而进行分页;

<select id="list" resultMap="streamer">
	select * from Streamer
</select>

(2)insert
在这里插入图片描述
MyBatis执行完一条insert语句后,会返回一个整数表示其影响的记录数;

<insert id="insertDiskGroup" parameterType="diskgroup" useGeneratedKeys="true" keyProperty="group.id">
   	insert into DiskGroup(name,size,clientId) values('${group.name}','${group.size}','${group.clientId}')
   </insert>

useGeneratedKeys="true"表示获取自动生成的主键,同时配置keyProperty或keyColumn,表示把主键赋值到POJO的哪个属性中,如存在多个主键,则用逗号“,”隔开;实现自动生成的主键回填的功能;

<insert id="insertDiskGroup" parameterType="diskgroup">
	<selectKey keyProperty="group.id" resultType="int" order="BEFORE">
		select if (max(group.id)==null,1,max(group.id)+3) from DiskGroup
	</selectKey>
   	insert into DiskGroup(name,size,clientId) values('${group.name}','${group.size}','${group.clientId}')
   </insert>

自定义主键增长规则,上例为表记录为空时,id设置为1,否则id设置为当前id+3;返回一个int类型的结果集,order="BEFORE"表示该语句将在定义的SQL之前执行,还可以使用AFTER;

(3)update、delete
update和delete与insert类似,执行完也会返回一个表示影响数据库记录数的整数;

<update id="renameClient">
   	update Client set name=#{name} where id=#{cId}
</update>

<delete id="removeClient" parameterType="int">
   	delete from Client where id=#{cId}
</delete>

(4)sql元素
在MyBatis的xml文件里,sql元素作为定义的SQL的一部分,可以实现编写一次,而在其他元素中多次引用的功能;

<sql id="diskGroupCols">name,size,clientId</sql>
<insert id="insertDiskGroup" parameterType="diskgroup" useGeneratedKeys="true" keyProperty="group.id">
	insert into DiskGroup(<include refid="diskGroupCols"/>) values('${group.name}','${group.size}','${group.clientId}')
</insert>

sql元素还支持变量传递:在include元素下命名了一个alias的变量,其值是表DiskGroup的别名g,这样sql元素中就可以使用这个变量名了;

<sql id="diskGroupCols">${alias}.name,${alias}.size,${alias}.clientId</sql>
<insert id="insertDiskGroup" parameterType="diskgroup" useGeneratedKeys="true" keyProperty="group.id">
	insert into DiskGroup g(<include refid="diskGroupCols"><property name="alias" value="g"/></include>) values('${group.name}','${group.size}','${group.clientId}')
</insert>

(5)参数
-当一些数据库字段返回为null,而MyBatis系统又检测不到使用何种jdbcType进行处理时,会发生异常,这个时候就需要指定typeHandler:

update User set mode=#{mode} where username=#{username,typeHandler=org.apache.ibatis.type.StringTypeHandler}

-如果username是一个没有注册的类型,那么需要自定义typeHandler,然后再指定即可;
-指定jdbcType、javaType、typeHandler:可以支持精度;

#{username,javaType=int,jdbcType=NUMERIC,numericScale=2,typeHandler=MyTypeHandler}

存储过程参数支持:
#{id,mode=IN}:输入参数;
#{id,mode=OUT}:输出参数;
#{id,mode=INOUT}:输入输出参数;

(6)resultMap
定义映射规则、级联的更新、定义类型转换器等;结果集的映射关系;现有MyBatis只支持resultMap的查询,不支持更新或者保存;
resultMap元素构成如下:

<resultMap>
	<constructor> //配置构造方法,MyBatis会使用此构造方法构造POJO
		<idArg property="" column="" javaType="" jdbcType="" typeHandler=""/>
		<arg/>
	</constructor>
	<id/> //主键,允许多个主键,称为联合主键
	//配置POJO到SQL列名的映射关系
	<result property="" column="" javaType="" jdbcType="" typeHandler=""/> 
	<association/>
	<collection/>
	<discriminator>
		<case/>
	</discriminator>
</resultMap>

–存储结果集
可以使用map和POJO存储查询结果集,但由于map的可读性差,因此推荐POJO;使用方法,前文可见,就不再重复了;

(7)级联
级联可以十分快速的获取关联数据,但过多也会增加系统的复杂度和耦合度,从而使系统性能降低;因此当级联超过3层时,不建议使用,适用于对象关系比较简单,级联不多的场景;
MyBatis级联分3种:
–鉴别器(discriminator):根据某些条件采用具体实现类级联的方案;
–一对一(association):两个对象的关系是一对一;
–一对多(collection):两个对象的关系是一对多;
不支持多对多级联,因为过于复杂,可以通过两个一对多级联实现;

<resultMap type="cloudaccount" id="CloudAccountMap">
<association property="cloudserver" column="acId" select="cn.infocore.pojo.MyCloudServerDao.getServer" />
</resultMap>

一对一,property属性代表映射到指定POJO属性上;select配置命名空间+SQL id;column代表SQL的列,会作为参数传递给select指定的SQL,如果多个参数,用逗号隔开;

<resultMap type="cloudaccount" id="CloudAccountMap">
<collection property="servers" column="acId" select="cn.infocore.pojo.MyCloudServerDao.listByAcId" />
</resultMap>

一对多,select配置命名空间+SQL id;column代表SQL的列,会作为参数传递给select指定的SQL,如果多个参数,用逗号隔开;结果返回给property指定的POJO属性servers;

<discriminator javaType="long" cloumn="sex">
	<case value="1" resultMap="maleMapper"/>
	<case value="2" resultMap="femaleMapper"/>
</discriminator>

鉴别器,column代表使用哪个字段进行鉴别,子元素case用于区分,resultMap属性表示采用哪个ResultMap去映射;

通过级联设置,默认情况下会执行所有关联SQL,包括获取当前信息不需要的SQL,导致数据库资源的损耗和系统性能的下降;这个就出现了N+1问题,即当前N个关联关系完成级联,再加入一个级联关系,就变成N+1个级联,所有的级联SQL都会执行;针对这个问题,就提出了延迟加载的功能;

延迟加载配置:settings
-lazyLoadingEnabled :默认false,延迟加载的全局开关,true表示所有关联对象都会延迟加载,在特定关联关系中,可通过fetchType覆盖;实体的关系对象属于另一个层级;
-aggressiveLazyLoading:在3.4.1版本后,默认false;按需加载,true表示开启了层级开关的延迟加载;鉴别器与实体在同一个层级;
-fetchType:适用于association和collection,eager值表示获得当前POJO后立即加载对应的数据;lazy值表示获得当前POJO后延迟加载对应的数据;fetchType会忽略上述两个全局配置项;

SQL表连接基础上的级联:
-每一个级联元素中的主键与POJO实体配置的主键一一对应,形成级联;
-association通过javaType的定义声明实体映射,而collection是使用ofType声明;
-discriminator元素定义使用何种具体的resultMap进行级联;

<collection property="employeeTaskList" ofType="cn.infocore.pojo.EmployeeTask" column="id">
	<id column="et_id" property="id" />
	<result column="id" property="empId" />
	<result column="task_name" property="taskName" />
	<result column="note" property="note" />
	<association property="task" javaType="cn.infocore.pojo.Task" column="et_task_id">
		<id column="t_id" property="id" /> //实体id与et_task_id一一对应
		<result column="t_title" property="title" />
		<result column="t_context" property="context" />
		<result column="t_note" property="note" />
	</association>
</collection>
<discriminator javaType="int" column="sex"> //通过sex列判断
	<case value="1" resultMap="maleHealthFormMapper" />
	<case value="2" resultMap="femaleHealthFormMapper" />
</discriminator>

(8)缓存
MyBatis默认开启一级缓存,这个缓存不需要POJO对象可序列化(实现Serializable接口);
1)一级缓存:SqlSession上的缓存,通过同一个SqlSession对象进行数据获取,第一次查询后会缓存数据,第二次只要SQL与参数没变,且缓存未超时和未声明需要刷新时,就会从缓存读取数据;不同SqlSession对象中的缓存是不能共享的;

2)二级缓存:SqlSessionFactory上的缓存,即对<mapper>上定义的namespace命名空间内的所有select元素SQL查询的结果进行缓存,而其中的insert、delete、update语句在操作时会刷新缓存;可以共享不同SqlSession对象上的缓存,二级缓存需要手动开启;在映射文件里加上<cache/>即可;POJO对象需要可序列化;
Cache元素配置项:
在这里插入图片描述

public interface Cache {
  //获取缓存ID
  String getId();
  //保存对象,key为键,value为值
  void putObject(Object key, Object value);
  //获取缓存数据,key为键
  Object getObject(Object key);
  //删除缓存,key为键
  Object removeObject(Object key);
  //清除缓存
  void clear();
  //获取缓存大小
  int getSize();
 //获取读写锁,需要考虑多线程的场景
  ReadWriteLock getReadWriteLock();
}

默认缓存配置:flushCache表示是否刷新缓存,useCache是否使用缓存;

<select ... flushCache="false" useCache="true"/>
<update... flushCache="true"/>
<insert... flushCache="true"/>
<delete... flushCache="true"/>

引用其他映射器中cache元素的配置:

<cache-ref namespace="cn.infocore.mappser.RoleMapper"/>

重点再讲一下sqlSession.close()和sqlSession.commit():
1)执行select操作,会保存一级缓存,再调用close,会将其一级缓存的数据放进二级缓存中,此时一级缓存随着SqlSession的关闭也就不存在了;
2)执行select缓存,会保存一级缓存,再调用commit,会将其中的一级缓存的数据放进二级缓存中,并清空一级缓存
3)执行更新操作(update、delete、insert)时,同时不调用commit或close,这时只会清空其自身的一级缓存,对二级缓存没有影响;
4)执行更新操作(update、delete、insert)时,调用commit,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果);
5)执行更新操作(update、delete、insert)时,调用close,只会清空其自身的一级缓存(执行更新操作的效果),对二级缓存没影响了;当autoCommit为true时,会清空二级缓存;

(9)存储过程
数据库预先编译好,放在数据库内存中的一个程序片段,性能高,可重复使用;
参数类型:输入参数、输出参数、输入输出参数;
返回结果:整形、字符型OUT、INOUT参数等简易类型、游标类型;

<think>好的,用户之前让我帮忙整理MyBatis的学习笔记框架,现在他们又进一步要求介绍MyBatis的基本概念及简介。我需要先回顾之前的对话,确保这次回答和之前的内容一致,并且补充更基础的信息。 首先,用户当前的需求是了解MyBatis的基本概念和简介,这可能是一个刚接触MyBatis的新手,正在构建知识体系。他们可能需要简洁明了的解释,避免过于深入的技术细节,但又要覆盖关键点,帮助建立整体认识。 接下来,我需要确定回答的结构。之前的笔记框架已经涵盖了核心概念、配置文件、动态SQL、缓存机制等,但用户现在需要的是更基础的内容。因此,我应该从定义、核心特性、架构组成、工作流程、优缺点以及适用场景这几个方面来组织内容,这样逻辑清晰,适合新手理解。 需要确保回答中使用正确的术语,比如ORM框架、半自动化、SqlSessionFactory、SqlSession、Mapper接口等,这些在之前的回答中已经提到过,这里需要再次强调,但用更简洁的语言。同时,要对比全自动化的Hibernate,突出MyBatis的灵活性和对SQL的控制,这也是用户可能关心的点。 可能用户没有说出来的深层需求是了解为什么选择MyBatis而不是其他框架,所以在优缺点部分需要明确说明其适用场景,比如当项目需要高度优化的SQL或复杂查询时,MyBatis更有优势。此外,他们可能也想知道如何开始使用MyBatis,所以加入一个快速入门的代码示例会有帮助,展示基本配置和操作流程。 还要注意避免重复之前已经详细讲解的内容,比如动态SQL和缓存机制,这里只需简要提及,引导用户参考之前的笔记。同时,确保语言口语化,避免过于技术化的表达,让读者容易理解。最后,检查是否符合系统级指令,如行内公式使用$...$,独立公式用$$...$$,但在这个回答中可能用到的技术术语如SQL、JDBC等需要正确格式化。</think>以下是对MyBatis框架的简明介绍,采用结构化说明: ### 一、基本定义 MyBatis是一款**半自动化的持久层框架**(Persistence Framework),通过$XML$或注解实现$Java$对象与关系型数据库的映射(ORM)。其核心思想是**将SQL与业务代码解耦**,开发者可完全控制SQL语句,同时实现参数映射和结果集转换的自动化。 ### 二、核心特性 1. **半自动化设计** - 相比全自动化的Hibernate,需要手动编写SQL - 提供结果集到对象的自动映射 - 支持存储过程、复杂联表查询等高级功能 2. **动态SQL能力** 通过$XML$标签实现条件分支(`<if>`、`<choose>`)、循环(`<foreach>`)等逻辑处理 $$ \text{动态SQL} = \text{传统JDBC条件拼接} + \text{自动防注入处理} $$ 3. **轻量级架构** 核心JAR包仅约$2.7MB$,无第三方依赖 ### 三、核心架构组成 | 组件 | 作用描述 | |---------------------|---------------------------------| | `SqlSessionFactory` | 全局单例,通过`mybatis-config.xml`构建 | | `SqlSession` | 线程非安全的数据库会话对象,生命周期与请求绑定 | | `Mapper`接口 | 通过动态代理绑定到$XML$映射文件 | | `Executor` | 执行器,处理缓存、事务等底层操作 | ### 、工作流程示例 ```java // 1. 加载配置文件 String resource = "mybatis-config.xml"; InputStream is = Resources.getResourceAsStream(resource); // 2. 创建SqlSessionFactory SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is); // 3. 打开数据库会话 try (SqlSession session = factory.openSession()) { // 4. 获取Mapper接口代理对象 UserMapper mapper = session.getMapper(UserMapper.class); // 5. 执行SQL操作 User user = mapper.selectUserById(1); } ``` ### 五、核心配置文件 1. **全局配置文件**(mybatis-config.xml) 定义数据源、事务管理器、类型别名等全局配置 2. **Mapper映射文件**(UserMapper.xml) ```xml <mapper namespace="com.example.UserMapper"> <select id="selectUserById" resultType="User"> SELECT * FROM users WHERE id = #{id} </select> </mapper> ``` ### 六、核心优势与局限 **优势**: - 灵活控制SQL,适合复杂查询优化 - 学习曲线平缓,易于调试 - 与Spring等框架集成良好 **局限**: - 需要手动编写较多SQL - 多表关联映射配置较复杂 ### 七、适用场景 - 需要高度优化SQL性能的项目 - 遗留数据库系统(表结构不规范) - 需同时使用存储过程与ORM的场景 如果需要了解具体技术实现细节(如缓存机制、插件开发等),可参考我之前提供的完整学习笔记框架,或提出具体问题深入探讨。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值