MyBatis-02 Sql映射文件

一、Sql映射文件顶级配置元素

  • mapper:映射文件的根元素节点,
    仅有一个属性namespace(命名空间)
    属性作用:
    (1)区分不同的mapper,全局唯一
    (2)绑定DAO接口,即面向接口 编程,当namespace绑定某一接口后,可以不用写该接口的实现类,MyBatis会通过接口的完全限定名查找到对应的mapper 配置来执行sql语句,因此namespace的命名必须要跟接口同名
  • cache:配置给定命名空间的缓存
  • cache-ref:从其他命名空间引用缓存配置
  • resultMap:用来描述数据库结果集和对象的对应关系
  • sql:可重用的sql块,也可以被其他语句引用
  • insert/delete/update/select:映射增删改查语句

注: 关于MyBatis的sql映射文件中的mapper元素的namespace属性

  • namespace的命名必须跟某个DAO接口同名,且同属于DAO层,故代码结构中,映射文件与该DAO
    接口在同一package下,并且习惯上都是以Mapper结尾,如(UserMapper.xml、UserMapper.java)
  • 在不同的mapper文件中,子元素的id可以相同,MyBatis通过namespace和子元素的id联合区分。
    接口中的方法(名)与映射文件中的sql语句id应一一对应。

二、select查询操作

注:以下代码中主要显示sql映射文件中语句,其他环境配置等代码见初始MyBatis-1

1、使用select 完成单条件查询操作
UserMapper.xml

<!-- 根据用户名称模糊查询用户列表 -->
<select id="getUserListByUserName" resultType="user" parameterType="string">
	select * from smbms_user where userName like
	CONCAT('%',#{userName},'%')
	<!--以上sql语句相当于JDBC的语句如下 -->
	<!-- PreParedStatement pstmt=conn.prePareStatement(sql); ps.setString(1,userName); -->
</select>

UserMapper.java

	/**
	 * 根据用户名模糊查询用户列表
	 * @param userName 用户姓名
	 * @return	User列表
	 * @throws Exception
	 */
	public List<User> getUserListByUserName(String userName)throws Exception;

2、使用select完成多条件传操作

  • 封装为对象入参

UserMapper.xml

	<select id="getUserList" resultType="user" parameterType="User">
   <!--根据用户名称、用户角色模糊查询;因有多个条件,所以将条件封装为对象查询-->
    		select * from smbms_user where userName like
    		CONCAT('%',#{userName},'%')
    		and userRole=#{userRole}
   	</select>

UserMapper.java

	/**
	 * 查询用户列表(对象入参)
	 * @param user
	 * @return
	 * @throws Exception
	 */
	public List<User> getUserList(User user)throws Exception;
  • 封装为Map入参

UserMapper.xml

	<!--查询用户列表 -->
	<select id="getUserListByMap" resultType="user" parameterType="hashmap">
		<!--将多个条件封装为Map集合,而对应的parameterType类型为hashmap-->
		select * from smbms_user where userName like
		CONCAT('%',#{userName},'%')
		and userRole=#{userRole}
	</select>

UserMapper.java

	/**
	 * 查询用户列表(map入参)
	 * @param user
	 * @return
	 * @throws Exception
	 */
	public List<User> getUserListByMap(Map<String,String> userMap)throws Exception;

3、使用resultMap完成查询结果的展现

需求: 查询所有用户列表,其中的角色信息要以角色名称(userRoleName)展示,而User表中只有userId属性且与Role(角色表)主外键关系对应。

解决方案:

  • 方案一 修改pojo:User.java类,增加userRoleName属性,并修改sql映射文件UserMapper.xml的sql语句,对用户表和Role角色表进行连表查询,做resultType自动映射。
  • 方案二 通过resultMap来映射自定义结果
    注:方案一不做演示,推荐使用方式为第二种

UserMapper.java不做更改

User.java

添加属性userRoleName

	private String userRoleName;	//角色名称
	public String getUserRoleName() {
		return userRoleName;
	}
	public void setUserRoleName(String userRoleName) {
		this.userRoleName = userRoleName;
	}

UserMapper.xml

 <!--根据角色id和用户姓名模糊查询用户列表 -->
	<!---resultMap属性值对应resultMap元素的id属性值->
	<select id="getUserList" resultMap="userList" parameterType="user">
		select u.*,r.roleName from smbms_user as u,smbms_role as r
		where u.userRole=r.id and u.userRole=#{userRole} 
		and u.userName like CONCAT('%',#{userName},'%')
	</select> 
	<resultMap type="User" id="userList">
		<!-- property为属性名 column对应数据库列名 -->
		<result property="id" column="id" />
		<result property="userCode" column="userCode" />
		<result property="userName" column="userName" />
		<result property="phone" column="phone" />
		<result property="birthday" column="birthday" />
		<result property="gender" column="gender" />
		<result property="userRole" column="userRole" />
		<result property="userRoleName" column="roleName" />
	</resultMap> 

UserMapperTest.java测试类

	/**
   	* 查询用户列表
   	*/
   	@Test
   	public void testGetUserList() {
   		SqlSession sqlSession = null;
   		List<User> ulist = null;
   		try {
   			sqlSession = MyBatisUtil.createSqlSession();
   			// 对象入参
   			User user = new User();
   			user.setUserName("赵");
   			user.setUserRole(3);
   			ulist = sqlSession.getMapper(UserMapper.class).getUserList(user);
   			for (User u : ulist) {
   				 logger.info("用户编码:"+u.getUserCode()+",用户姓名:"+u.getUserName()+",用户角色:"+u.getUserRoleName()+",用户地址:"+u.getAddress());
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		} finally {
    			MyBatisUtil.closeSqlSession(sqlSession);
    		}
    
    	}

讲解:

  • resultMap元素的属性值和子节点
    id属性 唯一标识,此id值用于select元素resultMap属性的引用
    type属性 表示该resultMap的映射结果类型
    result子节点 用于标识一些简单属性,
    result节点的属性:1、column属性表示从数据库中查询的字段名
    2、property表示查询出来的字段值赋给实体对象的哪个属性

  • MyBatis中在对查询进行select映射时的两种方式resultType和resultMap之间的关联与区别

    区别:

    • resultType直接表示返回类型,包括基础数据类型和复杂数据类型。
    • resultMap则是对外部resultMap定义的引用,对应外部resultMap的id,表示返回结果映射到哪一个resultMap上。应用场景:数据库字段信息和对象属性不一致或需要做复杂的联合查询。

    关联:
    在使用MyBatis进行查询映射时,实际上查询出的每个字段信息都放在一个对应的map里面,key对象字段名,value对应相应的值,当select元素提供的返回类型属性为resultType时,MyBatis会将map中的键值对取出赋给resultType所指定的对象的属性(即调用对象属性的setter方法)。
    因此,当使用resultType,直接在后台就能接收到相应的对象属性值。由此可看出,其实MyBatis的每个查询映射的返回值类型都是resultMap,只是当提供的返回值类型是resultType时,MyBatis会自动把对应的值赋给指定对象的属性,而当返回值类型为resultMap时,因为map不能很好的表示领域模型,所以需要手动转化为对应的实体对象。( 领域模型:业务对象模型[对象])

注:

  • 在MayBatis的select元素中,resultType与resultMap本质是一样的,都是Map数据结构,
    但resultType和resultMap属性绝对不能同时存在,只可二选一
  • resultMap的自动映射级别:使用resultMap自动映射的前提是属性名和自动名必须一致,在默认映射级别(PARTIAL)情况下,如果没有做匹配也可以在后台获取到未匹配过的属性值;若不一致且在resultMap中没有做映射,则无法获取到数据

三、增删改操作

1、insert插入操作

UserMapper.java

	/**
	 * 添加用户
	 * @param user
	 * @return
	 */
	public int add(User user)throws Exception;

UserMapper.xml

	<!-- 新增 -->
	<insert id="add" parameterType="User">
		insert into
		smbms_user(userCode,userName,userPassword,gender,birthday,phone,
		address,userRole,createdBy,creationDate)
		values(#{userCode},#{userName},#{userPassword},#{gender},#{birthday},
		#{phone},#{address},#{userRole},#{createdBy},#{creationDate})
	</insert>

2、update更新操作
UserMapper.java

	/**
	 * 修改用户
	 * @param user
	 * @return
	 */
	public int modify(User user)throws Exception;

UserMapper.xml

	<!-- 修改 -->
	<update id="modify" parameterType="User">
		UPDATE smbms_user set userCode=#{userCode},
		userName=#{userName},userPassword=#{userPassword},gender=#{gender},
		birthday=#{birthday},phone=#{phone},address=#{address},
		userRole=#{userRole},modifyBy=#{modifyBy},modifyDate=#{modifyDate}
		WHERE id=#{id} 
	</update>

3、使用@Param注解实现多参数注入
需求: 修改指定用户的个人密码
分析: 可以明确方法传入的参数有两个,用户id和新密码,需要修改列只有一个,所以将条件参数封装为对象不合适,所以此处运用@Param实现多参数传递,代码如下
UserMapper.java

	/**
	 * 为指定用户修改密码
	 * @param id
	 * @param pwd
	 * @return
	 */
	public int updatePwd(@Param("id")Integer id,@Param("userPassword")String pwd)throws Exception;

UserMapper.xml

	<!-- 修改密码 -->
	<update id="updatePwd">
		update smbms_user set userPassword=#{userPassword}
		where id=#{id}
	</update>

UserMapperTest.java测试类

	/**
	 * 修改密码
	 */
	@Test
	public void testUpdatePwd() {
		SqlSession sqlSession = null;
		int count = 0;
		try {
			sqlSession = MyBatisUtil.createSqlSession();
			count = sqlSession.getMapper(UserMapper.class).updatePwd(16, "888888");
			// int i=2/0; //模拟操作失败
			sqlSession.commit();	//提交
		} catch (Exception e) {
			sqlSession.rollback();	//回滚
			e.printStackTrace();
			count = 0;
		} finally {
			MyBatisUtil.closeSqlSession(sqlSession);
		}
		logger.debug("updatePwd count---->" + count);
	}

讲解:

  • 使用@Param与不使用的区别
    若不使用@Param注解,则会报错,报错信息类似于Parameter’参数名’
    not found。深入MyBatis源码,MyBatis的参数类型为Map,若使用 @Param注解参数,那么就会记录指定的参数名(@Param后括号内的名称)为key;若参数没有加@Param,那么就会记录"param"+它的序号作为Map的key,故在进行多参数入参时,若没有使用@Param指定参数,那么映射的sql语句中获取不到#{参数名},从而报错。

  • @Param注解参数使用场景
    (1)一般情况下,超过4个以上的参数最好封装为对象(特别是常规的增加、修改操作,字段较多的情况)
    (2)对于参数固定,推荐使用@Param,原因是此方法较灵活,代码可读性高

注: 当参数为基础数据类型时,不管是多参数入参还是单独一个参 数,都需要使用@Param注解参数

4、delete删除操作

UserMapper.java

	/**
	 * 删除指定用户
	 * @param id
	 * @return
	 */
	public int deleteUserById(@Param("id")Integer id)throws Exception;

UserMapper.xml

	<!-- 删除指定用户 -->
	<delete id="deleteUserById" parameterType="Integer">
		delete from smbms_user
		where id=#{id}
	</delete>

四、实现MyBatis高级结果映射

1、association(一对一):
映射到某个JavaBean的某个复杂类型数据,比如Java类,即JavaBean内部嵌套一个复杂数据类型的属性,这种情况就属于复杂类型的关联。注:association仅处理一对一的关联关系。
属性

  • javaType:完整java类名或别名,若映射到一个JavaBean,则MyBatis通常会自行监测到其类型;若映射到一个HashMap,则应该明确指定javaType,来确保其行为
  • property:映射数据库列的实体对象的属性名子元素
    property子元素
    1、id:对应数据库中改行的主键id
    2、result映射数据库列
    result属性
    1)property:映射数据列的实体对象的属性
    2)column:数据库列名或别名

注: 在做映射的过程中,要确保所有的列名都是唯一且无歧义的

Demo演示
需求: 根据角色id获取用户列表

User.java添加属性Role对象

	private Role role;	//角色
	public Role getRole() {
		return role;
	}
	public void setRole(Role role) {
		this.role = role;
	}

Role.java

package cn.smbms.pojo;
import java.util.Date;

/**
 * 用户角色类
 * @author 14062
 *
 */
public class Role {
	private Integer id;			//主键id
	private String roleCode;		//角色编码
	private String roleName;		//角色名称
	private Integer createdBy;	//创建者
	private Date creationDate;	//创建日期
	private Integer modifyBy;	//修改者
	private Date modifyDate;	//修改日期
	//省略getter/setter方法	
}

UserMapper.java

	/**
	 * 根据roleId查询用户列表
	 * @param roleId
	 * @return
	 */
	public List<User> getUserListByRoleId(@Param("userRole")Integer roleId)throws Exception;

UserMapper.xml

	<!-- 根据角色id获取用户列表 -->
	<select id="getUserListByRoleId" resultMap="userRoleResult"
		parameterType="Integer">
		select u.*,r.id as r_id,r.roleCode,r.roleName from
		smbms_user as u,smbms_role as r
		where userRole=#{userRole} and u.userRole=r.id
	</select>
	<resultMap type="user" id="userRoleResult">
		<!--唯一标识结果集 -->
		<id property="id" column="id" />
		<result property="gender" column="gender" />
		<result property="userCode" column="userCode" />
		<result property="userName" column="userName" />
		<result property="userRole" column="userRole" />
		<result property="address" column="address" />
		<!-- 映射复杂数据类型的属性 -->
		<!-- 实现association结果映射的复用 resultMap属性值指向对应resultMap元素的id属性值 -->
		<association property="role" javaType="Role" resultMap="roleResult" />
	</resultMap>

	<!-- association复用 -->
	<resultMap type="role" id="roleResult">
		<!--查出数据后为id起了别名r_id 唯一标识结果集 -->
		<id property="id" column="r_id" />
		<result property="roleCode" column="roleCode" />
		<result property="roleName" column="roleName" />
	</resultMap>

UserMapperTest.java测试类

	/**
	 * 根据角色id获取用户列表
	 */
	@Test
	public void testGetUserListByRoleId() {
		SqlSession sqlSession = null;
		List<User> list = new ArrayList<User>();
		try {
			sqlSession = MyBatisUtil.createSqlSession();
			list = sqlSession.getMapper(UserMapper.class).getUserListByRoleId(2);
			logger.info("符合条件的用户数:" + list.size());
			for (User user : list) {
				logger.info("用户姓名:" + user.getUserName());
				logger.info("用户角色:" + user.getRole().getId());
				logger.info("用户角色:" + user.getRole().getRoleName());
				logger.info("角色编码:" + user.getRole().getRoleCode());
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			MyBatisUtil.closeSqlSession(sqlSession);
		}
	}

2、collection(一对多):
作用与association类似,也是映射到JavaBean的某个复杂数据类型的 属性,区别是这个类型是一个集合列表,即JavaBean内部嵌套一个复杂数据类型(集合)属性。
属性

  • ofType:完整java类名或别名,即集合所包含的类型
  • property:映射实体对象中的(集合类型)属性名

例:<collection property="addressList" ofType="Address"></collection>
注: 以上代码可以理解为一个属性名为adressList,类型为Address的 集合

Demo演示

需求: 获取指定用户的相关信息和地址列表
分析: 一个用户有多个地址,用户对地址为一对多的关系
User.java添加属性List<Address> 地址集合

	private List<Address> addressList;	//用户地址列表
	public List<Address> getAddressList() {
		return addressList;
	}
	public void setAddressList(List<Address> addressList) {
		this.addressList = addressList;
	}

UserMapper.java

	/**
	 * 获取指定用户的相关信息和地址列表
	 */
	public List<User> getAddressListByUserId(@Param("id")Integer userId);

UserMapper.xml

	<!-- 根据用户id查询用户地址信息 -->
	<select id="getAddressListByUserId" resultMap="userAddressResult"
		parameterType="Integer">
		select u.*,a.id as
		a_id,a.contact,a.addressDesc,a.postCode,a.tel,userId
		from smbms_user as
		u,smbms_address as a
		where u.id=#{id} and u.id=a.userId
	</select>
	<resultMap type="user" id="userAddressResult">
		<id property="id" column="id" />
		<result property="userCode" column="userCode" />
		<result property="userName" column="userName" />
		<!--使用collection一对多 高级映射 ofType为JavaBean类型 -->
		<collection property="addressList" ofType="Address"
			resultMap="addressResult" />
	</resultMap>

	<!-- 根据用户id获取地址新列表 collection复用 -->
	<resultMap type="address" id="addressResult">
		<id property="id" column="a_id" />
		<result property="postCode" column="postCode" />
		<result property="tel" column="tel" />
		<result property="contact" column="contact" />
		<result property="addressDesc" column="addressDesc" />
	</resultMap>

UserMapperTest.java

	/**
	 * 根据用户id获取地址列表-测试
	 */
	@Test
	public void testGetAddressListByUserId() {

		SqlSession sqlSession = null;
		List<User> list = new ArrayList<User>();
		try {
			sqlSession = MyBatisUtil.createSqlSession();
			list = sqlSession.getMapper(UserMapper.class).getAddressListByUserId(2);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			MyBatisUtil.closeSqlSession(sqlSession);
		}
		logger.info("用户数量:" + list.size());
		if (list.size() > 0) {
			for (User u : list) {
				logger.info("用户姓名:" + u.getUserName());
				logger.info("用户密码:"+u.getUserPassword());
				logger.info("--------------地址列表-----------------");
				for (Address a : u.getAddressList()) {
					logger.info("用户id:"+a.getUserId());
					logger.info("联系人:" + a.getContact());
					logger.info("地址详情:" + a.getAddressDesc());
					logger.info("邮政编码:" + a.getPostCode());
				}
			}
		}
	}

五、MyBatis的自动映射级别

  • NONE:禁止自动匹配
  • PARTIAL(默认):自动匹配所有属性,有内部嵌套的除外
  • FULL:匹配所有

六、MyBatis执行原理

mybatis运行时要先通过resources把核心配置文件也就是mybatis.xml文件加载进来,然后通过xmlConfigBulider来解析,解析完成后把结果放入configuration中,并把它作为参数传入到build()方法中,并返回一个defaultSQLSessionFactory。我们再调用openSession()方法,来获取SqlSession,在构建SqlSession的同时还需要transaction和executor用于后续执行操作。 推荐文章MyBatis运行原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值