映射器

映射器

映射器是MyBatis中最复杂且重要的组件,由一个接口加上XML文件组成。MyBatis的映射器也可以注解完成,但实际应用中使用不广泛,原因主要来自以下几个方面:

  • 面对复杂的SQL会显得很无力
  • 注解的可读性较差
  • 注解丢失了XML上下文相互引用的功能

因此,推荐使用XML文件开发映射器,SQL映射文件的常用配置元素如下:

元素名称 描述 备注
select 查询语句,最常用、最复杂的元素之一 可以自定义参数、返回结果集等、
insert 插入语句 执行后返回一个整数,代表影响的行数
update 更新语句 执行后返回一个整数,代表影响的行数
delete 删除语句 执行后返回一个整数,代表影响的行数
sql 定义一部分SQL,在多个位置被引用 例如一张表,列明一次定义,可以在多个SQL语句中使用
resultMap 用来描述从数据库结果集中来加载对象,是最复杂、且强大的元素 提供映射规则

select元素常用属性:

属性名称 描述
id 它和Mapper的命名空间结合起来使用,是唯一标识符,供MyBatis调用
parameterType 表示传入SQL语句的参数类型的全限定名或别名。他是一个可选属性,MyBatis能推断出具体传入语句的参数
resultType SQL语句执行后返回的类型。如果是集合类型,返回的是集合元素的类型,返回时可以使用resultType或resultMap之一
resultMap 他是映射集的引用,与< resultMap>元素一起使用,返回时可以使用resultTyoe或resultMap之一
flushCache 用于设置在调用SQL语句后是否要求MyBatis清空之前查询的本地缓存和二级缓存,默认值为false,如果设置为true,则任何时候只要SQL语句被调用都将清空本地缓存和二级缓存
useCache 启用二级换存开关,默认值为true,表示将查询结果存入二级缓存中
timeout 用于设置超时参数,单位是秒,超时将抛出异常
fetchSize 获取记录的总条数设定
statementType 告诉MyBatis使用哪个JDBC的Statement工作,取值为STATEMENT、PREPARED、CALLABLE
resultSetType 这是针对JDBC的ResultSet接口而言,其值可设置为FORWARD_ONLY(只允许向前访问)、SCROLL_SENSITIVE(双向滚动,但不及时更新)、SCROLL_INSENSITIVE(双向滚动,及时更新)

使用Map方式传递多个参数示例代码:

<resultMap type="po.MapUser" id="resultmap">
		<id property="muid" column="uid"/>
		<result property="muname" column="uname" />
		<result property="musex" column="usex"/>
	</resultMap>
	
	<select id="selectUsers" resultMap="resultmap">
		select * from user
	</select>
List<MapUser> users = userDao.selectUsers();
		for(MapUser mapUser : users) {
			System.out.println(mapUser);
		}

insert特有属性:

  • keyProperty:该属性的作用是将插入或更新操作时的返回值赋给PO类的某个属性,通常会设置为主键对应的属性。如果是联合主键,可以将多个值用逗号隔开。
  • keyColumn:该属性用于设置低级列是主键,当主键列不是表中的第一列时需要设置。如果时联合主键,可以将多个值用逗号隔开。
  • useGeneratedKeys:该属性将MyBatis使用JDBC的getGenernatedKeys()方法获取由数据库内部产生的主键,例如MySQL、SQL Server等自动递增的字段,其默认值为false。

主键自动回填示例代码如下:

<insert id="insertUser1" parameterType="po.MyUser" keyProperty="uid" useGeneratedKeys="true">
		insert into user(uname,usex) values(#{uname},#{usex})
	</insert>
		MyUser user1 = new MyUser();
		user1.setUname("张三");
		user1.setUsex("男");
		userDao.insertUser1(user1);
		System.out.println("user1 id ="+ user1.getUid());

自定义主键示例代码如下:

	<insert id="insertUser2" parameterType="po.MyUser">
		<selectKey keyProperty="uid" resultType="int" order="BEFORE">
			select if(max(uid) is null,1,max(uid)+1) as newuid from user
		</selectKey>
		insert into user(uid,uname,usex) values(#{uid},#{uname},#{usex})
	</insert>
MyUser user2 = new MyUser();
		user2.setUname("李四");
		user2.setUsex("女");
		userDao.insertUser2(user2);
System.out.println("user1 id ="+ user2.getUid());

其中< selectKey>元素的keyProperty属性制定了新生主键值返回给PO类的哪个属性。order属性可以设置为BEFORE或AFTER,BEFORE表示先执行< selectKey>元素然后执行插入语句;AFTER表示先执行插入语句再执行< selectKey>元素

sql元素可以用来定义SQL语句的一部分,配置示例如下:

<sql id="name">uid,usex,uname</sql>

在使用时只需在SQL语句中将其包含进来,示例代码如下:

select <include refid="name"/> from userr

级联查询

级联关系是一个数据库的实体概念,有三种级联关系,分别是一对一级联、一对多级联、多对多级联。级联的有点事获取关联数据十分方便,但级联较多会影响系统复杂的,从而降低系统运行性能。

一对一级联查询

Mybatis处理一对一级联方式:

通过< resultMap>元素的子元素< association>处理这种一对一级联关系。在< association>元素中通常使用以下属性。

  • property:指定映射到实体类的对象属性。
  • column:指定表中对应的字段(即查询返回的列名)
  • javaType:指定映射到实体对象属性的类型
  • select:指定引入嵌套查询的子SQL语句,该属性用于关联映射中的嵌套查询。

代码示例:
先在Mybatis中打开延迟加载的开关并将积极加载改为按需加载

<?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>
	<!-- MyBatis的延迟加载 -->
	<settings>
	<!-- 打开延迟加载开关 -->
	<setting name="lazyLoadingEnabled" value="true"/>
	<!-- 将积极加载改为按需加载 -->
	<setting name="lazyLoadingEnabled" value="false"/>
	</settings>
	<mappers>
	<!-- 映射文件的位置 -->
	<mapper resource="mapper/ClazzMapper.xml"/>
	<mapper resource="mapper/StudentMapper.xml"/>
	</mappers>
</configuration>

再在mapper中编写映射文件

<?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="dao.ClazzDao">
	<!--二次查询 -->
	<resultMap type="po.Clazz" id="resultClazz1">
		<!--class表映射 -->
		<id property="cid" column="cid" />
		<result property="clazz_name" column="clazz_name" />
		<collection property="students" ofType="po.Student"
			column="cid" select="dao.SelectStudentDao.selectStudentByCid">
		</collection>
	</resultMap>
	<!--查询所有班级,所有学生 -->
	<select id="selectClazz1" resultMap="resultClazz1">
		select * from clazz
	</select>
	<!--SQL级联查询 -->
	<resultMap type="po.Clazz" id="resultClazz2">
		<!--class表映射 -->
		<id property="cid" column="cid" />
		<result property="clazz_name" column="clazz_name" />
		<collection property="students" ofType="po.Student">
			<!--student表映射 -->
			<id property="id" column="id" />
			<result property="name" column="name" />
			<result property="cid" column="cid" />
		</collection>
	</resultMap>
	<!--查询所有班级,所有学生 -->
	<select id="selectClazz2" resultMap="resultClazz2">
		select clazz.*,student.*
		from clazz,student where clazz.cid=student.cid
	</select>
</mapper>
<?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="dao.SelectStudentDao">
	<select id="selectStudentByCid" parameterType="Integer" resultType="po.Student">
		select * from student where cid=#{cid};
	</select>
</mapper>

一对多级联查询

<?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.dao.UserDao">
	<!-- 根据uid查询一个用户信息 -->
	<select id="selectUserById" parameterType="Integer" 
		resultType="com.po.MyUser">
		select * from user where uid = #{uid}
	</select>
	<!-- 查询陈姓男性用户信息 -->
	<select id="selectAllUser"  resultType="com.po.MyUser" parameterType="com.pojo.SeletUserParam">
		select * from user 
		where uname like concat('%',#{u_name},'%')
		and usex = #{u_sex}
	</select>
	<!-- 添加一个用户,成功后将主键值回填给uid(po类的属性),#{uname}为com.po.MyUser的属性值-->
	<insert id="addUser" parameterType="com.po.MyUser" 
	keyProperty="uid" useGeneratedKeys="true">
		insert into user (uname,usex) values(#{uname},#{usex})
	</insert>
	<!-- 修改一个用户 -->
	<update id="updateUser" parameterType="com.po.MyUser">
		update user set uname = #{uname},usex = #{usex} where uid = #{uid}
	</update>
	<!-- 删除一个用户 -->
	<delete id="deleteUser" parameterType="Integer"> 
		delete from user where uid = #{uid}
	</delete>
	<!-- 使用自定义结果集类型 -->
	<resultMap type="com.pojo.MapUser" id="myResult">
		<!-- property是com.pojo.MapUser类中的属性-->
		<!-- column是查询结果的列名,可以来自不同的表 -->
		<id property="m_uid" column="uid"/>
		<result property="m_uname" column="uname"/>
		<result property="m_usex" column="usex"/>
	</resultMap>
	<!-- 使用自定义结果集类型查询所有用户 -->
	<select id="selectResultMap" resultMap="myResult">
		select * from user
	</select>
	<!-- 查询所有用户信息存到Map中 -->
	<select id="selectAllUserMap"  resultType="map">
		select * from user 
	</select>
	<!-- 一对多 根据uid查询用户及其关联的订单信息:第一种方法(嵌套查询) -->
	<resultMap type="com.po.MyUser" id="userAndOrders1">
		<id property="uid" column="uid"/>
		<result property="uname" column="uname"/>
		<result property="usex" column="usex"/>
		<!-- 一对多关联查询,ofType表示集合中的元素类型,将uid传递给selectOrdersById-->
		<collection property="ordersList" ofType="com.po.Orders" column="uid" 
		 select="com.dao.OrdersDao.selectOrdersById"/>
	</resultMap>
	<select id="selectUserOrdersById1" parameterType="Integer" resultMap="userAndOrders1">
		select * from user where uid = #{id}
	</select>
	<!-- 一对多 根据uid查询用户及其关联的订单信息:第二种方法(嵌套结果) -->
	<resultMap type="com.po.MyUser" id="userAndOrders2">
		<id property="uid" column="uid"/>
		<result property="uname" column="uname"/>
		<result property="usex" column="usex"/>
		<!-- 一对多关联查询,ofType表示集合中的元素类型 -->
		<collection property="ordersList" ofType="com.po.Orders" >
			<id property="id" column="id"/>
			<result property="ordersn" column="ordersn"/>
		</collection>
	</resultMap>
	<select id="selectUserOrdersById2" parameterType="Integer" resultMap="userAndOrders2">
		select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=#{id}
	</select>
	<!-- 一对多 根据uid查询用户及其关联的订单信息:第三种方法(使用POJO存储结果) -->
	<select id="selectUserOrdersById3" parameterType="Integer" resultType="com.pojo.SelectUserOrdersById">
		select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=#{id}
	</select>
</mapper>
<?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.dao.OrdersDao">
	<!-- 根据用户uid查询订单信息 -->
	<select id="selectOrdersById" parameterType="Integer" resultType="com.po.Orders">
		select * from orders where user_id=#{id}
	</select>
</mapper>

多对多级联查询

<?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.dao.OrdersDao">
	<!-- 根据用户uid查询订单信息 -->
	<select id="selectOrdersById" parameterType="Integer" resultType="com.po.Orders">
		select * from orders where user_id=#{id}
	</select>
	<!-- 多对多关联 查询所有订单以及每个订单对应的商品信息(嵌套结果) -->
	<resultMap type="com.po.Orders" id="allOrdersAndProducts">
		<id property="id" column="id"/>
		<result property="ordersn" column="ordersn"/>
		<!-- 多对多关联 -->
		<collection property="products" ofType="com.po.Product">
			<id property="id" column="pid"/>
			<result property="name" column="name"/>
			<result property="price" column="price"/>
		</collection>
	</resultMap>
	<select id="selectallOrdersAndProducts" resultMap="allOrdersAndProducts">
		select o.*,p.id as pid,p.name,p.price
		from orders o,orders_detail od,product p
		where od.orders_id = o.id 
		and od.product_id = p.id
	</select>
</mapper>

本文鉴于笔者写作时因初次学习,很多并内容不是十分清楚,可能错误较多或指代错误还望指正,后期将会统一修改。

参考教材《JavaEE框架整合开发入门到实战》侵删。
本人现役大三小白一枚,如有不足之处还望指正。

posted @ 2020-03-30 12:42  Aaron`Joe  阅读(269)  评论(0)    收藏  举报