Mybatis SQL映射文件

本文深入探讨MyBatis框架的高级特性,包括增删改查接口定义、自增主键处理、参数传递机制、自动映射、联合查询、延迟加载、鉴别器使用等,帮助开发者掌握MyBatis的进阶技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Mybatis 的增删改操作的接口方法定义中返回值可以定义为以下几种:
int、long、boolean或其包装类以及void

sqlSessionfactory.openSession()获取到的SqlSession 默认是不主动提交,需要手动提交。
sqlSessionfactory.openSession(true)是自动提交。

mysql支持自增主键,自增主键值的获取,Mybatis利用statement.getGenratedKeys(),通过设置而useGeneratedKeys=“true”,使用自增主键获取主键值策略;keyProperty,指定对应的主键属性,也就是Mybatis获取到主键值之后,将这个值封装给JavaBean的哪个属性。

<insert id="insertStudent" parameterType="com.learncmzy.pojo.StudentBean" useGeneratedKeys="true" keyProperty="id">
	insert into t_student(id,cnname,sex,note) values(#{id},#{cnname},#{sex},#{note})
</insert>

oracle中不支持自增,oracle使用序列来模拟自增,每次插入的数据的主键是从序列中拿到的值,在Mybatis中如何拿到这个值

<insert id="insertStudent" parameterType="com.learncmzy.pojo.StudentBean" databaseId="oralce">
		<!--keyProperty表示将查出的主键值封装给JavaBean的哪个属性
			order="BEFORE" 表示当前sql在插入sql之前运行,AFTER则表示之后
		  -->
		<selectKey keyProperty="id" order="BEFORE">
			select student_seq.nextval from dual
		</selectKey>
		<!-- 插入时的主键从序列中获取 -->
		insert into t_student(id,cnname,sex,note) values(#{id},#{cnname},#{sex},#{note})
	</insert>

Mybatis参数:
单个参数:Mybatis不会做特殊处理,直接#{参数名}
多个参数:Mybatis会做特殊处理,多个参数会被封装成为一个map
key:param1…paramN,或者使用参数的索引
value:传入的具体值
#{}就是从map中获取指定的key的值

//接口中的定义方法
public StudentBean getStudent(int id,String cnname);
//sql映射文件中定义
<select id="getStudent" parameterType="int" resultType="com.learncmzy.pojo.StudentBean">
		select id,cnname,sex,note from t_student where id=#{param1} and cnname=#{param2}
	</select>

如果直接使用上述形式,可读性差,不好维护,可以使用命名参数,明确指定封装参数时map的key,在接口定义方法的时候使用注解@Param明确指定

public StudentBean getStudent(@Param("id")int id,@Param("cnname")String cnname);


<select id="getStudent"  resultType="com.learncmzy.pojo.StudentBean">
		select id,cnname,sex,note from t_student where id=#{id} and cnname=#{cnname}
	</select>

如果多个参数正好是业务逻辑的数据模型,则可以直接传入POJO,使用#{属性名} 来去除传入POJO的属性值。

既然Mybatis传入多个参数的时候会自动转换成map对象,那么可以自己将多个参数手动封装成map对象传入,key值对应#{}中显示的值,value则为真正传入的数据

注意:如果是Collection(List、Set)类型或者是数组类型,会做特殊处理,把传入的List或者数组封装在map中。
key:如果是Collection,那么key就是collection,如果是List,那么会更精确,key是list,数组则是array。

public StudentBean getStudent(List<Integer ids);

在取第一个值的时候形式为#{list[0]}

参数值的获取:
#{}:可以获取map中的值或者POJO对象属性的值
${}:也可获取map中的值或者POJO对象属性的值
区别:#{}是以预编译的形式,将参数设置到sql语句中:PreparedStatement,可以防止sql注入
KaTeX parse error: Expected 'EOF', got '#' at position 42: …注入。 对于大多数情况下,使用#̲{}获取参数的值,但是在一些原…{}进行取值,比如分表,按照年份拆分:
select * from ${year}_salary where xxx=‘xxx’;
select * from table order by ${name}

${}更丰富的用法:
规定参数的一些规则:javaType,jdbcType,mode,numericScale,resultType,typeHandler,jdbcTypeName
jdbcType通常需要在某种特定的条件下被设置。当我们的数据为null的时候,有些数据库可能不能识别Mybatis对null的默认处理,比如oracle。当插入null值到oracle中会报错,提示jdbcType OTHER,无效的类型。因为Mybatis对所有的null都映射的是原生Jdbc的OTHER类型,oracle无法识别,所以当时oracle的sql查询时,需要设置JdbcType

<insert id="insertStudent" parameterType="com.learncmzy.pojo.StudentBean" databaseId="oralce">
		<!--keyProperty表示将查出的主键值封装给JavaBean的哪个属性
			order="BEFORE" 表示当前sql在插入sql之前运行,AFTER则表示之后
		  -->
		<selectKey keyProperty="id" order="BEFORE">
			select student_seq.nextval from dual
		</selectKey>
		<!-- 插入时的主键从序列中获取 -->
		insert into t_student(id,cnname,sex,note) values(#{id},#{cnname,jdbcType=NULL},#{sex},#{note})
	</insert>

因为在全局配置中jdbcTypeForNull默认值是OTHER,所以oracle无法识别,所以可以在特定的sql映射出修改,也可以在全局settings中设置jdbcTypeForNull属性为NULL。

resultType属性:
resultType是启用Mybatis自动封装的机制,在全局配置settings中设置属性autoMappingBehavior,默认是PARTIAL,开启自动映射功能。唯一要求是列名与JavaBean属性名一致。如果设置autoMappingBehavior设置为null,则会取消自动映射。如果在使用resultType属性的时候要求数据库字段命名规范,POJO属性符合驼峰命名法,如A_COLUMN->aColumn,也可以设置开启自动驼峰命名规范映射功能,mapUnderscoreToCamelCase=true

select标签要查询返回值是List的数据,其resultType设置为集合中具体元素的类型

select标签要查询返回值是Map的数据,Mybatis对其map进行了别名,resultType=“map”,返回的数据会自动按照key是列名,值是对应列名对应的值。

对于多条记录封装为一个map,Map<Integer,StudentBean>,键是这条记录的主键,值是记录封装后的JavaBean。需要在接口中定义方法时指定key为POJO的那个属性,使用@MapKey注解,在SQL映射文件中将resultType设置为map中对应value 中的元素类型。

@MapKey("id")
public Map<Integer,StudentBean> getStudentMaps(String cnname);


<select id="getStudentMaps"   resultType="com.learncmzy.pojo.StudentBean">
	select id,cnname,sex,note from t_student where cnname=#{cnname}
</select>

resultMap属性:resultMap 和resultType只能选择一个
在select标签中使用resultMap前,需要先定义resultMap,type为自定义规则的Java类型,id为唯一标识,方便后面引用

//id定义主键,底层会做优化,column指定哪一列,property指定对应的JavaBean属性
//result是其他的属性映射,如果有相应的字段没有写,则会自动封装(要保证数据库列明和JavaBean属性相同),建议都写上。

<resultMap type="studentBean" id="studentMap">
		<id property="id" column="id"/>
		<result property="cnname" column="cnname" />
		<result property="sex" column="sex"/>
		<result property="note" column="note"/>
	</resultMap>

联合查询
比如student 属于不同的班级,Student中有班级信息,使用级联属性封装结果集,,
配置好resultMap

<resultMap type="studentBean" id="studentPlus">
		<id column="id" property="id"/>
		<result column="cnname" property="cnname"/>
		<result column="sex" property="sex"/>
		<result column="note" property="note"/>
		<result column="class_id" property="classInfo.id"/>
		<result column="class_name" property="classInfo.className"/>
	</resultMap>
 
 映射sql
 <select id="getStudentAndClass"   resultMap="studentPlus">
		select student.id id,student.cnname cnname,student.sex sex,student.note note,class.id class_id,class.class_name class_name 
		from t_student student LEFT JOIN tb_class class on student.class_info=class.id where student.id=#{id}
	</select>

使用association标签association,其中property对应的是哪个属性是级联对象,javaType指定这个对象的类型
association中对应的属性应该是需要级联对象的属性,数据库的查询列也需要对应

<resultMap type="studentBean" id="studentPlusNew">
		<id column="id" property="id"/>
		<result column="cnname" property="cnname"/>
		<result column="sex" property="sex"/>
		<result column="note" property="note"/>
		<association property="classInfo" javaType="com.learncmzy.pojo.ClassInfo">
			<id column="class_id" property="id"/>
			<result column="class_name" property="className"/>
		</association>
	</resultMap>

使用association分步查询:
首先按照学生id查出学生的具体信息
然后根据学生信息中的class_info字段查询班级信息。
具体流程:使用select指定的方法(传入column指定的这列参数的值)查出对象,并封装给property指定的属性。

首先定义班级的查询映射语句

<select id="getClassInfoById" resultType="com.learncmzy.pojo.ClassInfo">
   	select * from tb_class where id=#{id}
   </select>

在学生映射文件中配置resultMap和sql映射语句,同样property是student中需要级联的对象,select中则是当前属性是由调用select指定的方法,这里是classInfo中的方法查出的结果,
然后将结果封装到property中的属性中,column则是指定使用已经查询出的学生信息中的哪个字段对应的值作为条件传入select指定的方法中
<resultMap type="studentBean" id="studentPlusByStep">
   	<id column="id" property="id"/>
   	<result column="cnname" property="cnname"/>
   	<result column="sex" property="sex"/>
   	<result column="note" property="note"/>
   	<association property="classInfo" select="com.learncmzy.mapper.ClassInfoMapper.getClassInfoById" column="class_info"></association>
   </resultMap>
   
   <select id="getStudentByStep"   resultMap="studentPlusByStep">
   	select * from t_student where id=#{id}
   </select>

级联查询使用延迟加载,在全局配置文件中配置setting
延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。
特定关联关系中可通过设置 fetchType 属性来覆盖该项的开关状态。

<setting name="lazyLoadingEnabled" value="true"/>
当开启时,任何方法的调用都会加载该对象的所有属性。 否则,每个属性会按需加载
<setting name="aggressiveLazyLoading" value="false"/>

collection 查询集合属性的元素:
查询班级信息的时候需要将所有学生的信息查询出来。
方式1,collection嵌套结果集的方式,定义关联的集合类型元素的封装规则

<resultMap type="com.learncmzy.pojo.ClassInfo" id="classAndStudents">
		<id column="id" property="id"/>
		<result column="class_name" property="className"/>
             //collection定义关联集合类型的属性的封装规则
             //ofType指定集合里面元素的具体类型
		<collection property="students" ofType="com.learncmzy.pojo.StudentBean">
			<id column="eid" property="id"/>
			<result column="cnname" property="cnname"/>
			<result column="sex" property="sex"/>
			<result column="note" property="note"/>
			 
		</collection>
	
	</resultMap>
	//定义sql映射语句,使用left join查询出班级和学生的信息
	<select id="getClassAndStudents" resultMap="classAndStudents">
		select class.id,class.class_name,s.id eid,s.cnname,s.sex,s.note from tb_class class left join t_student s
		on class.id=s.class_info where class.id=#{id}
		
	</select>

方式2,使用分步查询:

//先配置学生查询映射,根据班级id
<select id="getStudentsByClassId" resultType="com.learncmzy.pojo.StudentBean">
		select id,cnname,sex,note from t_student where class_info=#{id}
	</select>
 
 
 //配置班级映射规则,collection标签中 select表明从学生那里查询学生信息,column表示将班级上面班级查询出的id传入学生查询方法作为参数
 <resultMap type="com.learncmzy.pojo.ClassInfo" id="classAndStudentsByStep">
		<id column="id" property="id"/>
		<result column="class_name" property="className"/>
		<collection property="students" select="com.learncmzy.mapper.StudentMapper.getStudentsByClassId" column="id"></collection>
	</resultMap>
	
	
	<select id="getClassAndStudentsByStep" resultMap="classAndStudentsByStep">
		select * from tb_class where id=#{id}
	</select>
 

将多列值作为参数传入,是将多列值封装成为map之后传入
column="{key1=column1,key2=column2}"
如上述分步查询中,使用封装成map之后的形式为:关键点是column的设置,key查询学生的方法的参数名,如学生查询时的sql是select id,cnname,sex,note from t_student where class_info=#{id},这里的key就是id,如果把学生查询的id换成别的如classId,那么column="{classId=id}",符合前面介绍的,mybatis实际上是将查询参数封装成为map之后查询的。同时collection中的fetchType是设置延迟加载的属性,默认为fetchType=“lazy” ,表示延迟加载,即使全局配置了延迟加载,设置fetchType=“eager” 之后也可以立即加载

<resultMap type="com.learncmzy.pojo.ClassInfo" id="classAndStudentsByStep">
		<id column="id" property="id"/>
		<result column="class_name" property="className"/>
		<collection property="students" select="com.learncmzy.mapper.StudentMapper.getStudentsByClassId" column="{id=id}"></collection>
	</resultMap>

discriminator鉴别器:mybatis可以使用鉴别器判断某列的值,然后根据某列的值改变封装行为

例如查询的学生,如果是女生,那么就将其部门也查询出来,如果是男生,那么就不查询部门,但是将note属性赋值给cnname属性。

<resultMap type="studentBean" id="discriminatorTest">
		<id column="id" property="id"/>
		<result column="cnname" property="cnname"/>
		<result column="sex" property="sex"/>
		<result column="note" property="note"/>
		//discriminator 中的column属性是指定需要判定的列,javaType是指定列对应的java类型
		<discriminator javaType="com.learncmzy.util.SexEnum" column="sex">
                      //根据value中的值做判断,resultType指定封装成为的类型,是不能够省略的
			<case value="FMALE" resultType="studentBean">
				<association property="classInfo" select="com.learncmzy.mapper.ClassInfoMapper.getClassInfoById" column="class_info"></association>
			</case>
			<case value="MALE" resultType="studentBean">
				<result column="note" property="cnname"/>
			</case>
		</discriminator>
	</resultMap>
	
	<select id="getStudentDiscrimiter" resultMap="discriminatorTest">
	
		select * from t_student where id=#{id};
	</select>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值