Mybatis-基本學習(下)
四,MAP的使用–超常用
思考:多表連接查詢怎麼做?—MAP的好處!—返回
List<Object>
使用場景
類似加了一層封裝
- 實體類,或者資料庫中的表,欄位或者參數過多,就考慮使用Map
- 非常靈活,不用死死的在方法中定一個值,然後最後處理一個值的鎖定。。。它可以隨意定義幾個值的鎖定(前提是sql語句有對應)
規範? -滿足pojo的類型,SQL值的需求- Map需要<XX,Object>,因為Object通配所有,畢竟有int float String……
使用的依據:
- 本質上parameterType就是一個送參數的,不管你送啥,你要將下面的值和sql以後要使用的參數對應就好
- 最後送參時還是要對應原本的類型的,只是使用容器作為一個中介
考慮,能否使用ArrayList---答:能 比較麻煩,沒有map直接
–未考慮好
注意:因為map只是送值的,所以只有put操作。。且value不分類型—(為了安全起見最好對應-)map.put(“id”,”8″);
操作
- 介面中
// map的使用---萬能的Map
int addUser1(Map<String,Object> map);
User getUserById1(Map<String,Object> map); // map 用法
- Mapper.xml中
<!--map的使用-->
<insert id="addUser1" parameterType="map">
insert into mybatis.user(id,name,password) values (#{userId},#{userName},#{userPassword});
</insert>
<select id="getUserById1" parameterType="map" resultType="com.zjz.pojo.User">
select * from mybatis.user where id = ${id}
</select>
- Test
@Test
public void TestAddUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("userId",5); // 對應#{userId}--類型限制POJO
map.put("userName","zjz5"); // 對應#{userName}--類型限制POJO
map.put("userPassword","321616"); // 對應#{UserPassword}--類型限制POJO
mapper.addUser1(map);
// 提交事務
sqlSession.commit();
sqlSession.close();
}
@Test
public void TestGetUserById1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<>();
map.put("id","8");
User userById1 = mapper.getUserById1(map);
System.out.println(userById1);
sqlSession.close();
}
使用詳情及規範
- 類型限制(POJO),值對應(SQL)
- 方法只使用 put 送值-,
- value類型沒對應好,直接運行-沒報錯–
- key沒對應好,如果送的值多了,報錯—少了,送null –(主鍵不送—肯定報錯啊!)
- 註:查詢時必須都得對應上key
不懂的—兩個例子,你自己做一個,三列即可確定一件事了
問題以及雙鎖定條件
根據 密碼 和 名字 查詢用戶
-
思路一:直接在方法中傳遞參數
-
- 在介面方法的參數前加 @Param屬性
- ——為啥需要@Param,不加時,直接報錯,因為類型影響後面
-
- Sql語句編寫的時候,直接取@Param中設置的值即可,不需要單獨設置參數類型(parameterType)
//通過密碼和名字查詢用戶 User selectUserByNP(@Param("username") String username,@Param("pwd") String pwd); /* <select id="selectUserByNP" resultType="com.kuang.pojo.User"> select * from user where name = #{username} and pwd = #{pwd} </select> */
-
-
思路二:使用萬能的Map
-
- 在介面方法中,參數直接傳遞Map;
-
- 編寫sql語句的時候,需要傳遞參數類型,參數類型為map
-
- 在使用方法的時候,Map的 key 為 sql中取的值即可,沒有順序要求!
User selectUserByNP2(Map<String,Object> map); <select id="selectUserByNP2" parameterType="map" resultType="com.kuang.pojo.User"> select * from user where name = #{username} and pwd = #{pwd} </select> Map<String, Object> map = new HashMap<String, Object>(); map.put("username","小明"); map.put("pwd","123456"); User user = mapper.selectUserByNP2(map);
-
-
總結:
- 如果參數過多,我們可以考慮直接使用Map實現,如果參數比較少,直接傳遞參數即可
@Param註解
1.使用@Param
-
實例一 @Param註解單一屬性
// 依據id,name查詢 User getUserByIdName(@Param("id") int id,@Param("name") String name); ------------------------------------- <select id="getUserByIdName" resultType="com.zjz.pojo.User"> select * from mybatis.user where id = #{id} AND name = #{name} </select>
-
1.當你使用了使用@Param註解來聲明參數時,如果使用 #{} 或 ${} 的方式都可以。
// 根據id查詢
User getUserById(@Param("id")int id);
<select id="getUserById" parameterType="int" resultType="com.zjz.pojo.User">
select * from mybatis.user where id = ${id}
</select>
- 2.當你不使用@Param註解來聲明參數時,必須使用 #{}方式且只有一個參數。在我的版本(M361,S802) ${} 的方式,不會報錯。(可能其它版本報錯)
- 所以目前還是單個參數可以不用,多個參數要用
// 根據id查詢
User getUserById(int id);
<select id="getUserById" parameterType="int" resultType="com.zjz.pojo.User">
select * from mybatis.user where id = ${id}
</select>
2,不使用@Param註解
- 不使用@Param註解時,參數只能有一個,可以是屬性,也可以是對象
- 目前似乎不支援@param(“User”)
- 目前也沒有此限制–
並且是Javabean。在SQL語句里可以引用JavaBean的屬性,而且只能引用JavaBean的屬性。
- 目前也沒有此限制–
// 插入insert int addUser(User user); <insert id="addUser" parameterType="com.zjz.pojo.User"> insert into mybatis.user(id,name,password) values (#{id},#{name},#{password}); </insert> @Test public void TestAddUser(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); mapper.addUser(new User(4, "zjz4", "123456")); // 提交事務 sqlSession.commit(); sqlSession.close(); }
- 目前似乎不支援@param(“User”)
小結:
- 所有的增刪改操作都需要提交事務!
- 介面所有的普通參數,盡量都寫上@Param參數,尤其是多個參數時,必須寫上!(否則報錯)
- 有時候根據業務的需求,可以考慮使用map傳遞參數!
- 為了規範操作,在SQL的配置文件中,我們盡量將Parameter參數和resultType都寫上!
五.配置解析
1.核心配置文件
- mybatis-config.xml
configuration(配置)
properties(屬性)
settings(設置)
typeAliases(類型別名)
typeHandlers(類型處理器)
objectFactory(對象工廠)
plugins(插件)
environments(環境配置)
environment(環境變數)
transactionManager(事務管理器)
dataSource(數據源)
databaseIdProvider(資料庫廠商標識)
mappers(映射器)
<!-- 注意元素節點的順序!順序不對會報錯 -->
2.environments元素
配置MyBatis的多套運行環境,將SQL映射到多個不同的資料庫上,必須指定其中一個為默認運行環境(通過default指定)
默認 事務JDBC 數據源 POOLED
-
1.子元素節點:environment
- 具體的一套環境,通過設置id進行區別,id保證唯一!
- 子元素節點:transactionManager – [ 事務管理器 ]
-
`
` 有**兩個事務管理器**,不是一個!!
-
2.子元素節點:數據源(dataSource)
- dataSource 元素使用標準的 JDBC 數據源介面來配置 JDBC 連接對象的資源。
- 數據源是必須配置的。
- 有三種內建的數據源類型
type="[UNPOOLED|POOLED|JNDI]")
—JNDI 正常連接- (池:用完可以回收,不關,等下一個來連)
-
3.屬性(properties)
-
使用它實現引用配置文件
-
優先走外部的,再走裡面的property
<!--引入外部配置文件--> <properties resource="db.properties"> <property name="username" value="root"/> <property name="password" value="123456"/> </properties>
-
-
4.別名(typeAliases)
-
1.起別名typeAlias
<!--起別名--> <typeAliases> <typeAlias type="com.zjz.pojo.User" alias="User"/> </typeAliases> // 這樣在XXXMapper.xml中的resultType就可以直接使用User,不用com.zjz.pojo.User <select id="getUserList" resultType="User" > select * from user </select>
-
2.package(重要)
-
掃描包下的實體類,將類名首字母小寫作為別名—–
-
可以自定義DIY — 註解
@Alias
<!--起別名-->
<typeAliases>
<package name="com.zjz.pojo"/>
</typeAliases>
非必須:javabean 註解
@Alias("xiaoming")
- 兩個之間的區別
- Aliases 可以之間手動DIY一個別名
- package 需要找到對應的javaBean,註解 ,然後就DIY的,否則都是類名首字母小寫
設置
-
setting
-
一個配置完整的 settings 元素的示例如下:
<settings> <setting name="cacheEnabled" value="true"/> <!--開關映射器配置文件中已配置的任何快取--> <setting name="lazyLoadingEnabled" value="true"/> <!--延遲載入的全局開關。--> <setting name="multipleResultSetsEnabled" value="true"/> <!--是否允許單個語句返回多結果集(需要資料庫驅動支援)--> <setting name="useColumnLabel" value="true"/> <!--使用列標籤代替列名--> <setting name="useGeneratedKeys" value="false"/> <!--允許 JDBC 支援自動生成主鍵,需要資料庫驅動支援--> <setting name="autoMappingBehavior" value="PARTIAL"/> <!--允許 JDBC 支援自動生成主鍵,需要資料庫驅動支援--> <!--NONE 表示關閉自動映射;PARTIAL 只會自動映射沒有定義嵌套結果映射的欄位。 FULL 會自動映射任何複雜的結果集(無論是否嵌套)--> <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/> <!--指定發現自動映射目標未知列(或未知屬性類型)的行為。--> <!-- NONE: 不做任何反應 WARNING: WARNING 輸出警告日誌('org.apache.ibatis.session.AutoMappingUnknownColumnBehavior' 的日誌等級必須設置為 WARN) FAILING: FAILING 映射失敗 (拋出 SqlSessionException) --> <setting name="defaultExecutorType" value="SIMPLE"/> <!--配置默認的執行器。SIMPLE 就是普通的執行器;--> <setting name="defaultStatementTimeout" value="25"/> <!--設置超時時間--> <setting name="defaultFetchSize" value="100"/> <!--為驅動的結果集獲取數量(fetchSize)設置一個建議值。此參數只可以在查詢設置中被覆蓋。--> <setting name="safeRowBoundsEnabled" value="false"/> <!--禁止在嵌套語句中使用結果處理器(ResultHandler) true開啟禁止--> <setting name="mapUnderscoreToCamelCase" value="false"/> <!--是否開啟駝峰命名自動映射, 即從經典資料庫列名 A_COLUMN 映射到經典 Java 屬性名 aColumn。註:ORACLE資料庫常見--> <setting name="localCacheScope" value="SESSION"/> <!--MyBatis 利用本地快取機制(Local Cache)防止循環引用和加速重複的嵌套查詢。--> <setting name="jdbcTypeForNull" value="OTHER"/> <!--當沒有為參數指定特定的 JDBC 類型時,空值的默認 JDBC 類型--> <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/> <!--指定對象的哪些方法觸發一次延遲載入--> </settings>
-
其它配置
-
類型處理器 typeHandlers
-
對象工廠 objectFactory
-
plugins 插件
- mybatis-generator-core
- mybatis-plus—–以後學
- 通用mapper
映射(mapper)
- MapperRegistry:註冊綁定我們的配置文件
- 方式一 resource(推薦使用)
<!--每一個mapper.xml都需要在mybatis核心配置文件中註冊-->
<mappers>
<mapper resource="com/zjz/dao/UserMapper.xml"/>
</mappers>
- 方式二 使用class文件綁定註冊
<!--每一個mapper.xml都需要在mybatis核心配置文件中註冊-->
<mappers>
<mapper class="com.zjz.dao.UserMapper"/>
</mappers>
- class使用注意:
- 介面必須和他的Mapper配置文件必須同名
- 介面和他的配置文件必須在同一個包下
<environments default="test"> <!--使用test環境-->
<environment id="development">
<!-- 事務管理-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis? useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
<environment id="test">
<!-- 事務管理-->
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url"
value="jdbc:mysql://localhost:3306/mybatis? useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
生命周期和作用域
- 作用域(Scope)和生命周期
- 理解我們目前已經討論過的不同作用域和生命周期類是至關重要的,因為錯誤的使用會導致非常嚴重的並發問題。
-
SqlSessionFactoryBuilder:
- 一旦創建了SqlSessionFactor,就不再需要了
- 局部變數
-
SqlSessionFactory:
- 生命周期就同於 MyBatis 的應用周期。
- 可以想像為:資料庫連接池
- 一旦創建了 SqlSessionFactory,就要長期保存它,直至不再使用MyBatis 應用
- 往往希望 SqlSessionFactory 作為一個單例,讓它在應用中被共享。所以說 SqlSessionFactory 的最佳作用域是應用作用域。
-
SqlSession
- 連接到連接池的請求
- SqlSession 就相當於一個資料庫連接(Connection 對象),你可以在一個事務裡面執行多條 SQL,
然後通過它的 commit、rollback等方法,提交或者回滾事務。 - 所以它應該存活在一個業務請求中,處理完整個請求後,應該關閉這條連接,讓它歸還給 SqlSessionFactory,
否則資料庫資源就很快被耗費精光,系統就會癱瘓,所以用 try…catch…finally… 語句來保證其正確關閉。
ResultMap
屬性名,欄位名不一致
-
如果POJO同資料庫的欄位不一致
-
正常運行會顯示不一致的欄位為null
User{id=0, name='zjz0', pwd='null'}
-
1.解決方法–別名
<select id="selectUserById" resultType="User"> select id , name , password as pwd from user where id = #{id} </select>
-
2.方案二:使用結果集映射->ResultMap 【推薦】
- 注意:
<resultMap id="UserMap" type="User"> 的id
對應<select id="selectUserById" resultMap="UserMap">的resultMap
<resultMap id="UserMap" type="User"> <!-- id為主鍵 --> <id column="id" property="id"/> <!-- column是資料庫表的列名 , property是對應實體類的屬性名 --> <result column="name" property="name"/> <result column="pwd" property="password"/> </resultMap> <select id="selectUserById" resultMap="UserMap"> select id , name , pwd from user where id = #{id} </select>
- 注意:
-
資料庫中,存在一對多,多對一的情況,我們之後會
使用到一些高級的結果集映射,association,collection這些