天天看點

MyBatis(随筆2 : Sql映射檔案 )Sql檔案映射

Sql檔案映射

這裡隻是筆記,屬性詳情,關鍵還是要多練 ——執行個體代碼

MyBatisDemo

MyBatis 真正的強大在于映射語句,專注于SQL,功能強大,SQL映射的配置卻是相當簡單

SQL映射檔案的幾個頂級元素

name 詳情
mapper namespace: 命名空間
cache 配置給定命名空間的緩存
cache-ref 從其他命名空間引用緩存配置
resultMap 用來描述資料庫結果集和對象的對應關系
sql 可以重用的SQL塊,也可以被其他語句引用
insert 映射插入語句
update 映射更新語句
delete 映射删除語句
select 映射查詢語句
:--------: -------------:
  • mapper

    namespace:命名空間: 一般引用對應的接口類位址,也可以随便起名,如果面向接口程式設計則必須要是對應接口的位址引用…

    namespace和子元素的id聯合保證唯一,接口中的方法與映射檔案中的sql 語句 一一對應;

<mapper namespace="命名空間">
	<select id="login" …
		……
	</select>
</mapper>
           
  • Select

    select是MyBatis中最常用的元素之一, 用于查詢 sql 操作;

    select語句有很多屬性可以詳細配置每一條語句

    常用屬性

    id

    命名空間中唯一的辨別符可随意 但如果是 面向接口程式設計 方法名與映射檔案中的SQL語句 id 一 一 對應(要相同);

    parameterType

    傳入SQL語句的參數類型,

    基礎資料類型: int、String、 Date等隻能傳入一個,通過 #{随意參數名} 即可擷取傳入的值; 這裡參數名可以随意… 因為參數隻有一個無須細分了~

    複雜資料類型: Java實體類、Map等通過 #{屬性名} 或者 #{map的keyName} 即可擷取傳入值; Map可用于多個參數;

    resultType

    SQL語句傳回值的類型 與

    parameterType

    類似, 可以是基礎或複雜資料類型…

    MyBatis中resultType自動映射, 字段名 和 屬性名必須一緻才可以哦~

    注意: 傳回結果如果是 實體類類型,盡量類屬性名 與資料庫列名一緻,不然會很麻煩哦~

    resultMap

    命名引用外部的resultMap

    flushCache

    将其設定為true,不論語句什麼時候被調用,都會導緻緩存被清空。預設值:false

    useCache

    将其設定為true,将會導緻本條語句的結果被緩存。預設值:true

    timeout

    這個設定驅動程式等待資料庫傳回請求結果,并抛出異常時間的最大等待值。預設不設定(驅動自行處理)

    fetchSize

    這是暗示驅動程式每次批量傳回的結果行數

  • resultMap

    上面查詢結果類型是 User類型, 但如果資料庫列名與實體類的屬性名, 不一緻,MyBatis 檔案映射不出來:

    而可以通過SQL 語句查詢,列起别名形式進行, 改正:

    但還是不好,而且 兩表連接配接查詢時候, Java一般會在實體類中存在另一個類型對象…這個怎麼解決呢~

    eg: 檢視使用者及使用者的部門資訊… 使用者表/部門表; 而兩表連接配接需要存部門的資訊; 使用者有部門屬性,是以一般實體類 會放一個部門類的對象… 這就可以使用

    resultMap

    常用屬性

    id

    唯一辨別,id 值用于select元素 resuMap的引用;

    type

    表示resultMap的映射結果;

    id 标簽

    子節點:< id property="屬性名“ column=”主鍵列名“ /> 一般一個resultMap 隻有一個表示查詢的主鍵列,提高程式效率; 如果需要查詢多個資料時, !不然你永遠隻會查到一條資料!

    吃過虧的我...可别學我

    至于為啥:

    resultMap中如果不定義類似主鍵之類的能夠區分每一條結果集的字段的話,會引起後面一條資料覆寫前面一條資料的現象。

    result:

    子節點:用于辨別屬性,< result property="屬性名“ column=”列名“ /> 如果查詢時候有些屬性應該有值,結果卻是 null 就是沒有映射上!或 映射級别過低…

    assoction

    子節點: A表 B表, 兩表連接配接… A類存在B類型對象屬性; 就需要使用 assoction 進行映射;

    assoction 處理 ”一對一“ 的關聯關系; w是人事部 s是技術部…

    property:表示在A類中的屬性名; javaType : 表示該屬性的類名; …

    collection

    同 assoction 類似, assoction表示 一對一, 而 collection 則表示 一對多;

    即:查詢人事部的所有員工; Java的部門類中就需要一個使用者集合…

    關于映射級别

    可以在MyBatis-config.xml 中 < setting name=“auto<appMappingBehavior” value=“PARTIAL” />

    NONE : 禁止自動映射;

    PARTIAL : 預設值,允許自動映射; 但 collection/assoction 子元素中,無法自動映射;——級别不夠

    FULL :更進階的映射, 允許 collection/assoction 子元素中自動映射;

    最後,最後 還要注意的是: 資料庫列一定要和實體類類對應!

    sql語句多表檢視不要出現相同的列名(

    這個問題不大

    ) ,實體類的資料類型 要注意! 與資料庫的值可以比對的:

    Error getting nested result map values for 'sort'. Cause: java.sql.SQLException: Invalid value for getInt() - '鏂囧叿'

    中:擷取“sort”的嵌套結果映射值時出錯。 無效的值 getInt() '鏂囧叿'————這是我報的錯真的是坑死了!實體類是 int 資料庫是 字元串!!!

    一定注意!

SQL映射

UserMapper.xml

<!-- 面向接口 -->
	 <!-- 
 		resultMap元素屬性和子節點: 
 			id:		唯一辨別,此ID 用于select元素 resultMap 屬性的引用;
 			type:	表示resultMap 映射的類型;
 			result: 子節點 property類屬性  column庫列名 進行一一對應,解決了名字不比對問題;
 		
 		resultMap 與 resultType 的關聯:
 	 		resultType:	直接表示傳回結果類型,包括基本資料類型 和 複雜資料類型;
 	 		resultMap:	則是對外部 resultMap 定義的引用,它的場景一般是 資料庫字段與實體類屬性名不一緻使用; 或 兩表連接配接A類存在B類型對象;
 	 		關聯:		MyBatis進行查詢映射時候,其實查詢出來的字段值都放在一個對應的Map裡面,key字段名 value值;
 	 					select 設定 resultType 時,傳回結果也是Map 結構,而底層将 Map的值取出來進行 resultType類型的 setter(xx);進行指派了;  是以需要get/set!别忘了哦! 
 	 					resultType  resultMap 本質上都是 Map 資料結構, 兩者不可以同時在一個 select 中使用哦~;
 	 -->
	<resultMap type="User" id="userMap">
		<!-- property類屬性  column庫列名 MyBatis也會對 資料庫/實體列 相同的進行一一映射,不一緻的就需要手動進行映射了;  -->
		<id property="id" column="id"  />
 		<result property="userCode" column="userCode" />  
 		<!-- ...還好我這兒與資料庫都一樣就不需要一一映射了 -->
 		<association property="role" javaType="Role"  >
 		<!-- <result property="xxx" column="xxx" /> -->
 		<!--  ...還好我這兒與資料庫都一樣 且MyBatis: setting 設定 autoMappingBehavior 屬性級别 FULL  就不需要一一映射了 -->
 		</association>
 	</resultMap>
	<!--MyBatis-config.xml setting 設定resultMap的自動映射級别,NONE(禁止自動比對),PARTIAL(預設)自動比對所有屬性,有内部嵌套(association、collection)的除外,FULL(自動比對所有屬性) -->

	<!-- 面向接口形式, id 要與接口的方法名相同; -->
	<!-- 接口參數使用了 Java注解是以,映射檔案這裡就不需要,parameterType參數類型了, #{注解名} 找到對應注解值; -->
	<select id="login" resultMap="userMap"  >
 		SELECT su.*,sr.`roleName` FROM `smbms_user` su ,`smbms_role` sr WHERE su.`userRole` = sr.`id` AND su.`userName`= #{name} AND su.`userPassword` = #{pwd}
 	</select>
           

Java接口:

UserMapper.Java

@Param 注解實作多參數

// 有時候, 參數需要很多可以使用 parameterType 的 Map Java實體類 但還是比較麻煩~ 還可使用Java 注解來解決…

// 隻需要在定義接口時候在參數清單,需要的參數使用:

@Param(" sql中使用的name ")參數類型 參數名

即可;

public interface UserMapper {
	//登入方法,根據使用者名/密碼使用者登入,并顯示使用者部門名稱.. 兩表連接配接.. assoction;
	public User login(@Param("name")String name,@Param("pwd")String pwd);  //使用了: 注解形式傳參;
}
           

注意

mybatis傳單個類型參數,可以不用@param注解,前提是xml中不含有 條件表達式(when,if..動态标簽中沒有引用到該參數) 大忌!!

映射檔案代碼片段~

<!-- 動态SQl 後面文章有詳細講解~ -->
<!-- 單個參數如果參數不加 @param if/where/..中是無法使用的..大忌!(當時找了好久~) -->
<if test="w !=null and w != ''">
 	<!-- 通過 #{w} 方式引入單個參數的值,拼接動态SQL -->
</if>
           

運作類

Run.Java

public User login(String name,String pwd){
		SqlSession session = MyBatisUtil.createSqlSession();
		UserMapper um = session.getMapper(UserMapper.class);
		User u = um.login(name, pwd);
		MyBatisUtil.closeSqlSession(session);
		return u;
	}
           
MyBatis(随筆2 : Sql映射檔案 )Sql檔案映射
  • collection 一對多;

    根據部門ID查部門,及其所有員工

    SQL映射

    RoleMapper.xml

<cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/> <!-- 二級緩存 -->
	<!-- 
		eviction		:檔案的儲存形式;
		flushInterval	:緩存對象的毫秒數;
		size			:緩存對象的個數; 先進先出原則,如果已經滿了,則最先進的移除,添加新的
		readOnly		: 隻讀
	 -->
	
	<resultMap type="Role" id="RoleMap">
 		<result property="id" column="id" />  
 		<collection property="users" ofType="User"  >
 			<!--  ...還好我這兒與資料庫都一樣 且MyBatis: setting 設定 autoMappingBehavior 屬性級别 FULL  就不需要一一映射了 -->
 		</collection>
 	</resultMap>
 	
	<select id="cha" resultMap="RoleMap" useCache="true" >
	SELECT rs.*,us.`userName` FROM `smbms_role` rs ,`smbms_user` us WHERE rs.`id` = us.`userRole` AND rs.`id`=#{id};
	</select>
           

Java接口

RoleMapper.Java

//根據部門id檢視部門資訊,及該部門的所有員工
	public Role cha(@Param("id")int id);
           

運作類

Run.Java

//根據編号查部門及 部門員工;
		public void bmcha(){
			SqlSession session = MyBatisUtil.createSqlSession();
			RoleMapper rm = session.getMapper(RoleMapper.class);
			//一級緩存:緩存資料存儲在 sqlSession中;
			Role r = rm.cha(1);
			System.out.println(r.getRoleName()+"\t"+r.getId());
			List<User> u = r.getUsers();
			for (User user : u) {
				System.out.println(user.getUserName());
			}
			MyBatisUtil.closeSqlSession(session); 
		}
           
  • insert

    insert完成新增操作;

    增 删 改 : 會對資料庫造成影響, 屬于事務. 是以在 MyBatisUtil 類中

    SqlSessionFactory.openSession(false); // 參數false表是開啟事務控制,不傳參數表示預設為true(為自動送出事務)

    如果是false 則記住需要手動送出事務哦, 不然資料不會改變哦;

    常用屬性

    id

    同上

    parameterType

    同上

    //一般隻有查詢,有傳回結果… 增 删 改 差不多都一緻。。。

SQL映射

UserMapper.xml

<!-- 新增 -->
<!-- 面向接口形式, id 要與接口的方法名相同; -->
 	<insert id="xz" parameterType="User" >
 		INSERT into `smbms_user` values
		(null,#{userCode},#{userName},#{userPassword},1,'1983-10-10','13688889999','北京市東城區前門東大街9号',2,1,'2020-08-18 09:56:31',NULL,NULL);
 	</insert>
           

Java接口:

UserMapper.Java

public interface UserMapper {
	//新增
	public int xz(User u);
           

運作類

Run.Java

public void addxz(){
		//新增的User 對象;
		User us = new User();
		us.setUserCode("WSM");
		us.setUserName("wangX");
		us.setUserPassword("540707");
		SqlSession session = MyBatisUtil.createSqlSession();
		int jg = 0;
		try {
		//采用面向接口方法
		//sqlSession.getMapper(接口類.Class);   前提是映射檔案命名空間指向接口的位址;
		// 且映射檔案對應的ID名要 和 接口的方法名相同;
		// Mybatis 底層實作了UserMapper接口,并傳回了對應執行個體,友善調用起對應方法;
		// 好處,不用在在意 SqlSession 的增删改查的方法: selectone(); insert();...方法了; 可以根據,自定義的方法來實作 "增删改查..操作";
		UserMapper um = session.getMapper(UserMapper.class);
		//傳回影響行數
		jg = um.xz(us); 
		session.commit();  //手動送出事務
		// 注意增删改查操作; 需要送出,雖然資料庫進行了新增,但是事務還沒結束,根據事務原子性; 成功/失敗; 
		} catch (Exception e) {
			e.printStackTrace();
			session.rollback();  //出現異常,事務復原; 
		}finally{
			MyBatisUtil.closeSqlSession(session);
			if(jg==1){
				System.out.println("新增成功");
			}else{
				System.out.println("新增失敗");
			}
		}
	};
           
  • Update

    Update完成修改操作;

SQL映射

UserMapper.xml

<!-- 修改 -->
 	<update id="xiugai"  >
 		UPDATE `smbms_user` SET `userName` =#{name} WHERE `id` =#{id}
 	</update>
           

Java接口:

UserMapper.Java

//修改 根據角色ID 修改角色姓名;
	public int xiugai(@Param("id")int id,@Param("name")String name);
           

運作類

Run.Java

public void upd(){
		System.out.println("請輸入要修改使用者id");
		int id = input.nextInt();
		System.out.println("請輸入修改後使用者name");
		String name = input.next();
		SqlSession session = MyBatisUtil.createSqlSession();
		try {
			UserMapper um = session.getMapper(UserMapper.class);
			if(um.xiugai(id, name)==1){
				session.commit();  //成功送出事務
				System.out.println("成功");
			}else{
				System.out.println("失敗");
			}
		} catch (Exception e) {
			e.printStackTrace();
			session.rollback();
		}finally{
			MyBatisUtil.closeSqlSession(session);
			
		}
	}
           
  • delete 完成删除操作

SQL映射

UserMapper.xml

<!-- 删除 -->
 	<delete id="del" parameterType="int"  >
 		DELETE FROM `smbms_user`  WHERE id=#{del}  <!-- 參數隻有一個可以随意一點了.. -->
 	</delete>
           

Java接口:

UserMapper.Java

//删除 根據角色Id 删除;
	public int del(int id);
           

運作類

Run.Java

public void del(){
		System.out.println("請輸入要删除ID");
		int id = input.nextInt();
		SqlSession session = MyBatisUtil.createSqlSession();
		try {
			UserMapper um = session.getMapper(UserMapper.class);
			if(um.del(id)==1){
				session.commit();  //成功送出事務
				System.out.println("成功");
			}else{
				System.out.println("失敗");
			}
		} catch (Exception e) {
			e.printStackTrace();
			session.rollback();
		}finally{
			MyBatisUtil.closeSqlSession(session);
			
		}
	}
           

這裡隻是筆記,屬性詳情,關鍵還是要多練 ——執行個體代碼

MyBatisDemo

加油!奧利

碩!