映射器
映射器
映射器是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框架整合开发入门到实战》侵删。
本人现役大三小白一枚,如有不足之处还望指正。