1. 程式人生 > >SQL的對映檔案

SQL的對映檔案

使用MyBatis 實現條件查詢

SQL對映檔案

mapper:對映檔案的根元素節點,只有一個屬性namespace(名稱空間),其作用如下:

  • 用於區分不同的mapper,全域性唯一
  • 繫結DAO介面,即面向介面程式設計,當namespace繫結某一介面之後,可以不用寫該介面的實現類, MyBatis會通過介面的完全限定名查詢到對應的mapper配置來執行SQL語句,因此namespace的命名必須要跟介面同名

cache:配置給定名稱空間的快取
cache-ref:從其他名稱空間引用快取配置
resultMap:用來描述資料庫結果集和物件的對應關係
sql:可以重用的SQL塊,也可以被其他語句引用
insert:對映插入語句
update:對映更新語句
delete:對映刪除語句
select:對映查詢語句

注意:在不同的Mapper檔案中,子元素的id可以相同,Mybatis通過namespace和子元素的id聯合區分,介面中的方法與對映檔案中SQL語句id應一一對應

使用select完成單條件查詢
<!--根據使用者名稱查詢使用者列表(模糊查詢)-->
<select id="getUserListByUserName" resultType="User" parameterType="string">
    SELECT * FROM USER WHERE userName LIKE concat('%',#{userName},'%')
</select>

各屬性介紹:
id:名稱空間中唯一的識別符號,可以被用來引用這條語句
parameterType:表示查詢語句傳入引數的型別的完全限定名或別名。
resultType:查詢語句返回結果型別的完全限定名或別名別名表

使用select完成多條件查詢

編寫介面

public interface UserMapper{
    //查詢使用者列表(引數:物件入參)
    List<User> getUserListByUser(User user);
}

編寫對映檔案

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

編寫測試

public void testGetUserList(){
    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("userName:"+user.getUserName()+"\t"+"userRole:"+user.getUserRole());
    }
}

當然也可以用別的方式入參,大家可以多試一試,都是大同小異的

使用resultMap完成查詢結果的展示

resultMap的意思就是我們資料庫的欄位和我們實體類中的屬性不一致的時候或者我們做一些複雜的查詢,需要使用到resultMap 比如:我們有一個使用者類,這裡面有一個角色id 但是沒有角色的名字,但是我們想要查這個角色的名字,這個時候我們就可以用到resultMap,具體操作請看下面示例 首先現在User(使用者)類中加入角色名字這個屬性

  private String roleName;//角色名稱
  //省略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>

編寫測試

 public void testGetUserList(){
    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>
使用Mybatis實現增刪改查操作
使用insert完成增加操作

在介面中新增add()方法

    public 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>

insert元素中屬性的意思和select一樣 編寫測試類

public void testAdd(){
    SqlSession sqlSession=null; 
    try{
        sqlSession=MyBatisUtil.createSqlSession();
        User user=new User();
        user.setUserCode("test");
        user.setUserName("測試資料");
        user.setUserPassword("anxin123");
        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()方法

    public 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>

編寫測試程式碼

public int modify(){
    SqlSession sqlSession=null;
    try{
        sqlSession=MyBatisUtil.createSqlSession();
        User user=new User();
        user.setId(15);
        user.setUserCode("test1");
        user.setUserName("測試皮皮修改");
        user.setUserPassword("mengqingpi123");
        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註解

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

上面程式碼中的@Param("userPassword")String pwd 就相當於把引數pwd改名為userPassword,在對映的SQl中需要使用#{註解名稱}
編寫修改的SQL語句

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

編寫測試類

public void testUpdatepwd(){
    SqlSession sqlSession=null; 
    try{
        sqlSession=MyBatisUtil.createSqlSession();
        int id=15;
        String pwd="pipi456";
        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);
    }
}

經驗:超過4個引數最好封裝成物件入參(特別是在常規增加或者修改時,欄位較多,封裝成物件比較方便)

使用delete完成刪除操作

編寫介面方法

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

在對映檔案中編寫刪除的SQL語句

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

編寫測試

public void testDeleteUser(){
    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實現高階結果對映(表表關聯)

association:對映到JavaBean的某個“複雜查詢”屬性,比如javaBean類,即JavaBean內部巢狀一個複雜資料型別,這種情況就屬於複雜型別的關聯,但是要注意:association只處理一對一的關係
在這裡我們用使用者的角色做演示,因為一個使用者只有一個角色(角色的意思 比如:管理員,站長)
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
}

修改User類,新增角色屬性(Role)

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介面中新增方法

public List<User> getUserListByRoleId(@Param("userRole")Integer roleId);

修改UserMapper.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>

如果我們每次都要查詢關聯資料的話,每次都要寫association這個節點,比較麻煩,我們可以用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>

編寫測試類:

public void getUserListByRoleIdTest(){
    SqlSession sqlSession=null;
    List<User> userList=new ArrayList<User>();
    Integer roleId=3;
    try{
        sqlSession=MyBatisUtil.createSqlSession();
        userList=sqlSession.getMapper(UserMapper.class).getUserListByRoleId(roleid);
    }catch (Exception ex){
        ex.printStackTrace();
    }finally {
        MyBatisUtil.closeSqlSession(sqlSession);
    }    
    for(User user:userList){
        System.out.print("userList--->userName:"+user.getUserName()
        +",Role:"+user.getRole.getId()
        +"----"+user.getRole.getRoleCode()
        +"----"+user.getRole().getRoleName());
    }
}

collection:collection元素的作用和association元素的作用差不多,事實上他們非常類似,也是對映到JavaBean的某個“複雜型別”屬性,只不過這個屬性是一個集合列表即JavaBean內部巢狀一個複雜資料型別(集合)屬性,和使用association元素一樣,我們使用巢狀查詢,或者從連線中巢狀結果集

collection處理的是 一對多的關聯 在這裡我們還是用使用者舉例 我們每個使用者有很多地址,就像我們淘寶購物一樣有不同的地址,所以說我們和地址是一對多的關係

建立Address類(地址)

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類新增地址屬性

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;  
    
    private List<Address> addressList();//使用者地址列表
    
    //省略getter&setter方法
}

編寫介面中的方法

public 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>

<select id="getAddressListByUserId" parameterType="Integer" resultMap="userAddressResult">
    select u.*,a.id as a_id,a.contact,a.addressDesc,a.postCode,a.tel 
        from smbms_user u LEET JOIN smbms_address a ON u.id=a.userId
            where u.id=#{id}
</select>

編寫測試方法

public void getAddressListByUserIdTest(){
    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自動對映級別

autoMappingBehavior的三個級別 NONE:禁止自動匹配
PARTIAL:(預設)自動匹配所有屬性,有內部巢狀(assocition,collection)除外
FULL:自動匹配所有

<settings>
    <setting name="autoMappingBehavior" value="Full"/>
</settings>

可能有很多東西講的不是很清晰,希望大家可以留言討論
by 安心