如何快速上手SQL映射文件的编写

在讲之前先说说它的好处:Mybatis真正强大之处就是在于SQL映射语句,也是他的魅力所在。相对于它强大的功能,SQL映射文件的配置却非常简单。简单的对比一下SQL映射配置和JDBC代码,发现使用SQL映射文件配置可减少50%以上的代码量。并且MyBatis专注于SQL,对于开发人员来说,也可极大限度地进行SQL调优,以保证性能。

关于SQL映射文件的几个顶级元素配置:

顶级元素配置
mapper:映射文件的根元素节点,只有一个属性namespace(命名空间),作用如下:

  • 用于区分不同的mapper,全局唯一
  • 绑定DAO接口,即面向接口编程。当namespace绑定某一接口之后,可以不用写该接口的实现类, MyBatis会通过接口的完全限定名查找到对应的mapper配置来执行SQL语句,因此namespace的命名必须要跟接口同名

cache:配置给定命名空间的缓存
cache-ref:从其他命名空间引用缓存配置
resultMap:用来描述数据库结果集和对象的对应关系
sql:可以重用的SQL块,也可以被其他语句引用
insert:映射插入语句
update:映射更新语句
delete:映射删除语句
select:映射查询语句

使用select完成单条件查询编写Mapper映射文件
<!--根据用户名查询用户列表(模糊查询)-->
<select id="getUserListByUserName" resultType="User" parameterType="string">
    SELECT * FROM USER WHERE userName LIKE concat('%',#{userName},'%')
</select>

各属性介绍:
id:命名空间中唯一的标识符,可以被用来引用这条语句
parameterType:表示查询语句传入参数的类型的完全限定名或别名。
resultType:查询语句返回结果类型的完全限定名或别名别名表

别名 映射的类型 别名 映射类型
string String double Double
byte Byte float Float
loang Long boolean Boolean
short Short date Date
int Integer map Map
integer Integer hashmap HashMap
arrayList ArrayList list List

使用select实现多条件查询

使用对象入参
编写映射文件

<select id="getUserListByUser" resultType="User" parameterType="User">
    SELECT * FROM USER WHERE userName LIKE concat('%',#{userName},'%')     and userRole=#{userRole}
</select>

编写接口

List<User> getUserListByUser(User user);

编写测试

SqlSession sqlSession=null;
List<User> userList=new ArrayList<User>(); try{
    sqlSession=MyBatisUtil.createSqlSession();
    User user=new User();
    user.setUserName("赵");
    user.setUserRole(3);
    userList=sqlSession.getMapper(UserMapper.class).getUserListByUser(user);
}catch (Exception ex){
    ex.printStackTrace();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}
for (User user:
        userList) {
    System.out.println(user.getUserName()+"\t"+user.getUserRole());
}

使用Map入参编写接口

List<User> getUserListByMap(Map<String,String> userMap);

编写UserMapper.xml文件

<select id="getUserListByMap" resultType="User" parameterType="Map">
    SELECT * FROM USER WHERE userName LIKE concat('%',#{userName},'%')
    and userRole=#{userRole}
</select>

编写测试

SqlSession sqlSession=null;
List<User> userList=new ArrayList<User>(); try{
    sqlSession=MyBatisUtil.createSqlSession();
    Map<String,String> userMap=new HashMap<String,String>();
    userMap.put("userName","赵");
    userMap.put("userRole","3");
    userList=sqlSession.getMapper(UserMapper.class).getUserListByMap(userMap);
}catch (Exception ex){
    ex.printStackTrace();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}
for (User user:
        userList) {
    System.out.println(user.getUserName()+"\t"+user.getUserRole());
}

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

先在User类中加入userRoleName属性:private String userRoleName,及其相应的getter和setter方

编写UserMapper.xml文件,修改其中的getUserList方法

<select id="getUserList" resultMap="userList" parameterType="User">
    SELECT u.*,r.roleName FROM USER u,Role r WHERE u.userName LIKE concat('%',#{userName},'%')
    AND u.userRole=#{userRole} AND u.userRole=r.id
</select> 
添加id为userList的resultMap元素节点  
<resultMap id="userList" type="User">
    <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>

测试

SqlSession sqlSession=null;
List<User> userList=new ArrayList<User>(); try{
    sqlSession=MyBatisUtil.createSqlSession();
    User user=new User();
    user.setUserName("赵");
    user.setUserRole(3);
    userList=sqlSession.getMapper(UserMapper.class).getUserList(user); }catch (Exception ex){
    ex.printStackTrace();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}
for (User user:
        userList) {
    
System.out.println(user.getUserName()+"\t"+user.getUserRole()+"\t"+user.getUserRoleName());
}

resultMap元素的属性值和子节点:
id属性:唯一标识,此id值用于select元素resultMap属性的引用
type属性:表示该resultMap的映射结果类型
result子节点:用于标识一些简答的属性,其中column属性表示从数据库中查询的字段名,property则
表示查询出来的字段对应的赋值给实体对象的哪个属性
resultType和resultMap的异同点及场景

  • 1.resultType直接表示返回类型,包括基本数据类型和复杂数据类型
  • 2.resultMap则是对外部resultMap定义的引用,对应外部resultMap的id
  • 3.MyBatis的每个查询映射的返回类型都是resultMap,当我们提供的返回类型是resultType,会自动赋值
    给指定属性
  • 4.resultMap自动映射界别默认映射级别为PARTIAL,在resultMap没有做映射关联时也能自动匹配。
    关闭方法:
<settings>
    <!--设置resultMap的自动映射级别为NONE(禁止自动匹配)-->
    <setting name="autoMappingBehavior" value="NONE"/> 
    </settings>

实现增删改的操作

1使用insert完成增加操作
在接口中添加add()方法
int add(User user);
在映射文件中编写插入语句

<insert id="add" parameterType="User">
    INSERT INTO USER (userCode,userName,userPassword,gender,birthday,
      phone,address,userRole,createdBy,creationDate)
    VALUES (#{userCode},#{userName},#{userPassword},#{gender},#{birthday},
      #{phone},#{address},#{userRole},#{createdBy},#{creationDate})
</insert>

编写测试代码

SqlSession sqlSession=null; try{
    sqlSession=MyBatisUtil.createSqlSession();
    User user=new User();
    user.setUserCode("testtt");
    user.setUserName("测试");
    user.setUserPassword("fajklfd");
    user.setGender(1);
    Date birthday=new SimpleDateFormat("yyyy-MM-dd").parse("1990-1-1");     user.setBirthday(birthday);
    user.setPhone("1228392324");
    user.setAddress("北京");
    user.setUserRole(3);
    user.setCreatedBy(1);
    user.setCreationDate(new Date());
    int count=sqlSession.getMapper(UserMapper.class).add(user);
    System.out.println("数量:"+count);
    sqlSession.commit();
}catch (Exception ex){
    ex.printStackTrace();
    sqlSession.rollback();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}

使用update完成修改

在接口中添加modify()方法
int modify(User user);
在映射文件中编写修改语句

<update id="modify" parameterType="User">
    UPDATE USER SET userCode=#{userCode},userName=#{userName},userPassword=# {userPassword},
    gender=#{gender},phone=#{phone},address=#{address},userRole=#{userRole},modifyBy=# {modifyBy},
    modifyDate=#{modifyDate},birthday=#{birthday}     WHERE id=#{id}
</update>

编写测试代码

SqlSession sqlSession=null; try{
    sqlSession=MyBatisUtil.createSqlSession();
    User user=new User();
    user.setId(15);
    user.setUserCode("testtt");
    user.setUserName("测试修改");
    user.setUserPassword("fajklfd");
    user.setGender(1);
    Date birthday=new SimpleDateFormat("yyyy-MM-dd").parse("1990-1-1");
    user.setBirthday(birthday);
    user.setPhone("1228392324");
    user.setAddress("北京");
    user.setUserRole(3);     user.setCreateBy(1);
    user.setCreationDate(new Date());
    int count=sqlSession.getMapper(UserMapper.class).modify(user);
    //int i=2/0;//测试事务回滚
    System.out.println("数量:"+count);
    sqlSession.commit();
}catch (Exception ex){
    ex.printStackTrace();
    sqlSession.rollback();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}

使用@Param注解实现多参数入参

如果参数只有两个,封装成对象并不合适,多参数入参可读性高。
在参数前增加@Param注解

int updatePwd(@Param("id")Integer id,@Param("userPassword")String pwd);

编写修改语句

<update id="updatePwd">
    UPDATE USER  SET userPassword=#{userPassword} WHERE id=#{id}
</update>

编写测试

SqlSession sqlSession=null; try{
    sqlSession=MyBatisUtil.createSqlSession();
    int id=15;
    String pwd="abc1223";
    int count=sqlSession.getMapper(UserMapper.class).updatePwd(id,pwd);
    //int i=2/0;//测试事务回滚
    System.out.println("数量:"+count);
    sqlSession.commit();
}catch (Exception ex){
    ex.printStackTrace();
    sqlSession.rollback();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}

使用delete完成删除操作

编写接口方法

int deleteUserById(@Param("id")Integer delId);

在映射文件中编写删除语句

<delete id="deleteUserById">
    DELETE FROM USER  WHERE id=#{id}
</delete>

编写测试

SqlSession sqlSession=null;
try{
    sqlSession=MyBatisUtil.createSqlSession();
    int id=15;
    int count=sqlSession.getMapper(UserMapper.class).deleteUserById(id);
    System.out.println("数量:"+count);
    sqlSession.commit();
}catch (Exception ex){
    ex.printStackTrace();
    sqlSession.rollback();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}

使用resultMap实现高级结果映射(表表关联)

使用resultMap实现高级结果映射(表表关联)

Role类
public class Role {
    private Integer id;
    private String roleCode;
    private String roleName;
    private Integer createdBy;
    private Date creationDate;
    private Integer modifyBy;
    private Date modifyDate;
    //省略getter和setter
}

修改pojo User类

public class User {
    private Integer id;             //id
    private String userCode;        //用户编码  
    private String userName;        //用户名称 
    private String userPassword;    //用户密码 
    private Integer gender;         //性别
    private Date birthday;          //出生日期
    private String phone;           //电话 
    private String address;         //地址
    private Integer userRole;       //用户角色
    private Integer createdBy;       //创建者
    private Date creationDate;      //创建时间 
    private Integer modifyBy;       //更新者     private Date modifyDate;        //更新时间
    //private String userRoleName; 
    //用户角色名称     private Role role;
    //省略getter&setter方法
}
在UserMapper接口中添加方法
List<User> getUserListByRoleId(@Param("userRole")Integer roleId);

修改UserMapper.xml 增加getUserListByRoleId
xml <resultMap id="userRoleResult" type="User"> <id property="id" column="id"/> <result property="userCode" column="userCode"/> <result property="userName" column="userName"/> <result property="userRole" column="userRole"/> <association property="role" javaType="Role"> <id property="id" column="r_id"/> <result property="roleCode" column="roleCode"/> <result property="roleName" column="roleName"/> </association> </resultMap> <select id="getUserListByRoleId" parameterType="Integer" resultMap="userRoleResult"> SELECT u.*,r.id AS r_id,r.roleCode,r.roleName FROM user u,role r WHERE u.userRole=#{userRole} and u.userRole=r.id </select>
使用外部resultMap复用配置

<resultMap id="roleResult" type="Role">
    <id property="id" column="r_id"/>
    <result property="roleCode" column="roleCode"/>
    <result property="roleName" column="roleName"/>
</resultMap>
<resultMap id="userRoleResult" type="User">
    <id property="id" column="id"/>
    <result property="userCode" column="userCode"/>
    <result property="userName" column="userName"/>
    <result property="userRole" column="userRole"/>
    <association property="role" javaType="Role" resultMap="roleResult"/>
</resultMap>

collection 一对多关联
创建pojo Addres.java

public class Address {     private Integer id;
    private String contact;
    private String addressDesc;
    private String postCode;
    private String tel;
    private Integer createdBy;
    private Date creationDate;
    private Integer modifyBy;
    private Date modifyDate;     private Integer userId;
    //省略getter和setter
}

修改User类增加地址列表属性

List<Address>addressList;

编写接口中的方法

List<User> getAddressListByUserId(@Param("id")Integer userId);

编写映射文件

<resultMap id="addressResult" type="Address">
    <id column="a_id" property="id"/>
    <result property="postCode" column="postCode"/>
    <result property="tel" column="tel"/>
    <result property="contact" column="contact"/>
    <result property="addressDesc" column="addressDesc"/>
</resultMap>
<resultMap id="userAddressResult" type="User">
    <id property="id" column="id"/>
    <result property="userCode" column="userCode"/>
    <result property="userName" column="userName"/>
    <collection property="addressList" ofType="Address" resultMap="addressResult"/>
</resultMap>

编写测试

SqlSession sqlSession=null; try{
    sqlSession=MyBatisUtil.createSqlSession();
    List<User> userList=sqlSession.getMapper(UserMapper.class).getAddressListByUserId(1);     for (User user: userList) {
        System.out.println(user.getUserName());         List<Address> addresses=user.getAddressList();         for (Address address:
                addresses) {
            System.out.println("--- "+address.getContact());
        }
    }
}catch (Exception ex){
    ex.printStackTrace();
}finally {
    MyBatisUtil.closeSqlSession(sqlSession);
}

resultMap自动映射级别和MyBatis缓存

autoMappingBehavior的三个级别
NONE:禁止自动匹配
PARTIAL:(默认)自动匹配所有属性,有内部嵌套(assocition,collection)除外
FULL:自动匹配所有