SpringBoot中MyBatis的基本使用

在项目的src/main/resources下新建mappers文件夹,并将UserMapper.xml复制到这个文件夹下!

这个UserMapper.xml就是用于配置SQL语句的文件!

这种配置SQL语句的XML文件的根节点是,需要在根节点配置namespace属性,取值为之对应的接口的全名:

<mapper namespace="cn.tedu.mybatis.UserMapper">

</mapper>

接下来,根据需要执行的SQL语句的种类,从、、、中选择对应的子节点,节点的id属性就是对应的抽象方法的名称,然后在节点内部配置SQL语句:

<mapper namespace="cn.tedu.mybatis.UserMapper">

	<insert id="addnew">
		INSERT INTO t_user (
			username, password,
			age, phone,
			email
		) VALUES (
			#{username}, #{password},
			#{age}, #{phone},
			#{email}
		)
	</insert>

</mapper>

注意:如果配置的是节点,必须在该节点配置resultType或resultMap属性!

插入数据时获取自增的id

在配置时,添加配置useGeneratedKeys="true"和keyProperty="属性名"即可,例如:

<insert id="addnew"
	useGeneratedKeys="true"
	keyProperty="id">
	INSERT INTO t_user (
		username, password,
		age, phone,
		email
	) VALUES (
		#{username}, #{password},
		#{age}, #{phone},
		#{email}
	)
</insert>

注意:以上keyProperty属性的值表示“得到了自增的id后封装到哪个属性中”,以上的取值id表示“放到User类的id属性中”。

关于#{}内的名称

当抽象方法的参数是一个对象,并且,在SQL语句需要使用对象中的属性时,#{}中写的是属性名,例如:

<insert id="addnew"
	useGeneratedKeys="true"
	keyProperty="id">
	INSERT INTO t_user (
		username, password,
		age, phone,
		email
	) VALUES (
		#{username}, #{password},
		#{age}, #{phone},
		#{email}
	)
</insert>

以上#{username}就是抽象方法的参数User类型的对象中的username属性的值!

如果抽象方法的参数只有1个,且这个参数直接作为SQL语句中的参数值,则#{}里可以随便写!

使用自定义的别名解决名称不匹配的问题

准备工作:在“用户表”中增加新的字段“部门(department_id)”,用于表示某个用户归属于哪个部门!

ALTER TABLE t_user ADD COLUMN department_id INT;
然后,为用户分配部门:

UPDATE t_user SET department_id=2 WHERE id IN (4);
UPDATE t_user SET department_id=4 WHERE id IN (6,8,9);
UPDATE t_user SET department_id=6 WHERE id IN (5,7);

接下来,还应该在User类中添加新的属性private Integer departmentId;,并为该属性添加SET/GET方法,重新生成toString()方法!

再次查询时,会发现:查询的输出结果中,departmentId的值都是null!其原因是:查询到了相关的数据,却因为名称不匹配(数据表中的是department_id,而User类中的是departmentId),所以,MyBatis框架就无法正确的将结果封装到User类的对象中!

其实,MyBatis框架在执行查询并处理查询结果时,默认情况下,要求查询结果的列名(Column)与封装结果的类的属性名(Property)必须一致!

所以,在查询时,可以自定义别名,使得列名与属性名保持一致!例如:

<select id="findAll"
	resultType="cn.tedu.mybatis.User">
	SELECT 
		id, username,
		password, age,
		phone, email,
		department_id AS departmentId 
	FROM 
		t_user 
	ORDER BY 
		id
</select>

使用resultMap解决名称不匹配的问题

在配置SQL语句的XML文件中,可以配置节点,该节点的配置就是用于指导MyBatis如何将查询结果封装到返回结果中!

<!-- id属性:自定义名称 -->
<!-- type属性:封装查询结果的数据类型的全名 -->
<resultMap type="cn.tedu.mybatis.User" 
	id="UserMap">
	<!-- 将哪一列的结果封装到哪个属性中去 -->
	<result column="id" property="id" />
	<result column="username" property="username" />
	<result column="password" property="password" />
	<result column="age" property="age" />
	<result column="phone" property="phone" />
	<result column="email" property="email" />
	<!-- 在配置单表查询结果时,以上名称匹配的,其实可以不必配置 -->
	<result column="department_id" property="departmentId" />
</resultMap>

在配置节点时,就应该使用resultMap属性指定以上节点的id:

<select id="findById" resultMap="UserMap">
	SELECT * FROM t_user WHERE id=#{id}
</select>

另外,在配置,如果配置的是主键的对应关系,应该使用节点来配置,配置方式与节点的使用完全相同,这样做有利于实现MyBatis缓存数据!

关联表查询

需求:根据id查询某个用户信息,在查询结果中,要求体现该用户所在的部门的名称!

需要执行的SQL语句大致是:

select 
	t_user.id, username,
	password, age,
	phone, email,
	department_id AS departmentId, 
	name AS departmentName
from 
	t_user 
left join 
	t_department 
on 
	t_user.department_id=t_department.id 
where 
	t_user.id=6;

在设计抽象方法时,没有某个实体类能够封装查询结果!则需要创建新的VO(Value Object)类来封装查询结果:

public class UserVO {

	private Integer id;
	private String username;
	private String password;
	private Integer age;
	private String phone;
	private String email;
	private Integer departmentId;
	private String departmentName;

	// SET/GET/toString
}

实体类是与数据表相对应的,而VO类是与查询结果相对应的!从编写代码的角度来看,VO类与实体类是高度相似的,只是定位不同!
创建好VO类后,就可以设计抽象方法:

UserVO findVOById(Integer id);
然后,配置以上抽象方法的映射:

<select id="findVOById" resultType="cn.tedu.mybatis.UserVO">
	select 
		t_user.id, username,
		password, age,
		phone, email,
		department_id AS departmentId, 
		name AS departmentName
	from 
		t_user 
	left join 
		t_department 
	on 
		t_user.department_id=t_department.id 
	where 
		t_user.id=#{id}
</select>

使用配置1对多的查询

需求:根据id查询部门信息,并且,同时查出该部门的员工信息。

分析:需要执行的SQL语句大致是:

SELECT
	*
FROM
	t_department
LEFT JOIN
	t_user
ON
	t_department.id=t_user.department_id
WHERE
	t_department.id=?

在开发功能时,必须先创建VO类,用于封装此次的查询结果:

public class DepartmentVO {
	private Integer id;
	private String name;
	private List<User> users;
}

然后在DepartmentMapper接口中添加抽象方法:

DepartmentVO findVOById(Integer id);
接下来,在DepartmentMapper.xml中配置以上抽象方法的映射:

<select id="findVOById" 
	resultType="cn.tedu.mybatis.DepartmentVO">
	SELECT
		t_department.id AS did, name,
		t_user.*
	FROM
		t_department
	LEFT JOIN
		t_user
	ON
		t_department.id=t_user.department_id
	WHERE
		t_department.id=#{id}
</select>

目前,MyBatis框架并不知道如何将找到的若干条结果正确的封装到返回的DepartmentVO对象中!所以,需要配置!配置代码如下:

<resultMap id="DepartmentVOMap"
	type="cn.tedu.mybatis.DepartmentVO">
	<id column="did" property="id" />
	<result column="name" property="name" />
	<!-- collection节点:用于配置1对多的查询结果 -->
	<!-- property属性:类中的哪个属性用于封装多个结果中的数据 -->
	<!-- ofType属性:集合属性中的元素的类型,即:这个List集合中放的是什么类型的数据 -->
	<collection property="users"
		ofType="cn.tedu.mybatis.User">
		<id column="id" property="id" />
		<result column="username" property="username" />
		<result column="password" property="password" />
		<result column="age" property="age" />
		<result column="phone" property="phone" />
		<result column="email" property="email" />
		<result column="department_id" property="departmentId" />
	</collection>
</resultMap>

注意:此次涉及多表查询,即使名称对应(查询结果的列名与期望封装到的对象的属性名是相同的),也必须显式的配置!

则对应的查询节点就应该使用resultMap属性来配置,并且,在查询时,为了避免出现2个id列,会导致无法正确的封装查询结果,所以,需要为至少其中1列定义别名:

<select id="findVOById" resultMap="DepartmentVOMap">
	SELECT
		t_department.id AS did, name,
		t_user.*
	FROM
		t_department
	LEFT JOIN
		t_user
	ON
		t_department.id=t_user.department_id
	WHERE
		t_department.id=#{id}
</select>

动态SQL

此类问题可以通过动态SQL的<if>标签来解决:

UPDATE t_user
SET
	password=#{password},
		
	<if test="age != null">
	age=#{age},
	</if>
		
	phone=#{phone},

	<if test="email != null">
	email=#{email}
	</if>
WHERE id=#{id}

执行以上代码时,如果提供了有效的age值(非null),则SQL语句为:

UPDATE t_user SET password=?, age=?, phone=?, email=? WHERE id=?

但是,如果没有提供age值,则SQL语句为:

UPDATE t_user SET password=?, phone=?, email=? WHERE id=?

注意:在编写动态SQL时,参数直接写名字即可,例如test="age != null"中的age就是参数的名称,不需要使用#{}这类的语法!
目标:一次删除多条数据,这些数据的id是作为参数体现的,但是,是没有规律的。

在接口中声明抽象方法:

Integer deleteUserByIds(List<Integer> ids);

以上方法的设计,参数可以是List<Integer>,也可以是Integer[]

然后,配置映射:

	<!-- collection:使用哪个集合,取值使用list或array -->
	<!-- item:每次遍历到的元素的名称 -->
	<!-- separator:IN内部的各个值之间使用的分隔符 -->
	<!-- open:遍历后的结果的起始字符 -->
	<!-- close:遍历后的结果的结束字符 -->
	<delete id="deleteUserByIds">
		DELETE FROM t_user 
		WHERE id IN 
		<foreach collection="list"
			item="id" separator=","
			open="(" close=")">
			#{id}
		</foreach>
	</delete>

注意:在中的collection属性,当抽象方法只有1个参数时,取值为list或array,根据参数类型决定,当抽象方法的参数超过1个时,该属性的值为参数的名称(参数的注解中使用的名称)!

关于动态SQL,主要掌握<if><foreach>的使用!

=============================================================

<insert>节点中,添加parameterType属性,用于指定参数的类型,即抽象方法中的参数类型:
执行SQL语句时的参数值均使用#{}类似的语法,其中的名称是User类中的属性名:

<!-- id:抽象方法的名称 -->
	<!-- parameterType:抽象方法中的参数的类型 -->
<insert id="addnew"
		useGeneratedKeys="true"
		keyProperty="id">
		INSERT INTO t_user (
			username, password,
			age, phone,
			email
		) VALUES (
			#{username}, #{password},
			#{age}, #{phone},
			#{email}
		)
	</insert>

<delete id="deleteByIds">
		DELETE FROM t_user WHERE id IN (
			<foreach collection="array" 
				item="id" separator=",">
				#{id}
			</foreach>
		)
	</delete>

<update id="updateEmailById">
		UPDATE t_user SET email=#{email} WHERE id=#{id}
	</update>


在配置的XML映射中,每个查询对应的都是`<select>`节点,该节点必须配置`resultType`或`resultMap`属性,用于表示查询结果的类型(即使返回值类型是`Integer`也必须配置)!

**如果返回结果是User对象,则resultType的值是User类的全名,如果返回结果是List,其resultType也是User类的全名,而不是List的全名!

<{插入的类型看抽象方法的参数的类型,查询的类型看返回值的类型}>
在设计MyBatis中的抽象方法时,如果参数超过1个,则每个参数之前都必须添加@Param注解,在映射的SQL语句中,#{}中填入也是注解中使用的名称!
注意:在编写动态SQL时,参数直接写名字即可,例如test="age != null"中的age就是参数的名称,不需要使用#{}这类的语法!

<select id="count" useCache="false"
		resultType="java.lang.Integer">
		SELECT COUNT(*) FROM t_user
	</select>
<select id="find" 
		resultType="cn.tedu.mybatis.User">
		SELECT * FROM t_user
		<if test="where != null">
		WHERE 
			${where}
		</if>
		<if test="orderBy != null">
		ORDER BY 
			${orderBy}
		</if>
		<if test="offset != null and count != null">
		LIMIT 
			#{offset}, #{count}
		</if>
	</select>
----------------------------------------------------------------------------------------------------------------------------------------------------------
<!-- id属性:自定义名称 -->
	<!-- type属性:封装查询结果的数据类型的全名 -->
	<resultMap type="cn.tedu.mybatis.User" 
		id="UserMap">
		<!-- 将哪一列的结果封装到哪个属性中去 -->
		<id column="id" property="id" />
		<result column="username" property="username" />
		<result column="password" property="password" />
		<result column="age" property="age" />
		<result column="phone" property="phone" />
		<result column="email" property="email" />
		<!-- 在配置单表查询结果时,以上名称匹配的,其实可以不必配置 -->
		<result column="department_id" property="departmentId" />
	</resultMap>
	
	<select id="findById"
		resultMap="UserMap">
		SELECT * FROM t_user WHERE id=#{id}
	</select>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值