MyBatis
MyBatis是Apache的一個開源項目iBatis, iBatis一詞來源於“internet”和“abatis”的組合,是一個基於Java的持久層框架。 iBatis 提供的持久層框架包括SQL Maps和Data Access Objects(DAO)
Mybatis 是一個 半自動的ORM(Object Relation Mapping)框架
sql和java編碼分開,功能邊界清晰,一個專注業務、一個專注數據
MyBatis全局配置
MyBatis全局配置文件結構順序是規定好的,可以省略但不可顛倒位置
1)properties屬性
既可以在典型的 Java 屬性文件中配置,亦可通過 properties 元素的子元素來配置
還可以創建一個資源文件,通過properties引入外部文件
resource: 從類路徑下引入屬性文件
url: 引入網絡路徑或者是磁盤路徑下的屬性文件
<properties> <property name="driver" value="com.mysql.jdbc.Driver" /> </properties> <!-- 引入類路徑下文件 --> <properties resource="db.properties"></properties>
是 MyBatis 中極為重要的調整設置,它們會改變 MyBatis 的運行時行為
<settings> <!-- 映射下划線到駝峰命名 --> <setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 設置Mybatis對null值的默認處理 --> <setting name="jdbcTypeForNull" value="NULL"/> <!-- 開啟延遲加載 --> <setting name="lazyLoadingEnabled" value="true"/> <!-- 設置加載的數據是按需還是全部 --> <setting name="aggressiveLazyLoading" value="false"/> <!-- 配置開啟二級緩存 --> <setting name="cacheEnabled" value="true"/> </settings>
3)typeAliases 別名處理
類型別名是為 Java 類型設置一個短的名字,可以方便我們在配置文件中其他位置引用某個類。
很多的情況下,可以批量設置別名為這個包下的每一個類創建一個默認的別名,就是用簡單類名小寫的形式
<typeAliases> <package name="com.mybatis.bean"/> </typeAliases>
MyBatis已經取好的別名
4)typeHandlers 類型處理器
無論是 MyBatis 在預處理語句(PreparedStatement)中設置一個參數時,還是從結果集中取出一個值時, 都會用類型處理器將獲取的值以合適的方式轉換成 Java 類型
MyBatis3.4以前的版本需要我們手動注冊這些處理器,以后的版本都是自動注冊的,所以基本不需設置
我們也可以重寫類型處理器或創建自己的類型處理器來處理不支持的或非標准的類型
- 實現org.apache.ibatis.type.TypeHandler接口或者繼承org.apache.ibatis.type.BaseTypeHandler
- 指定其映射某個JDBC類型(可選操作)
- 在mybatis全局配置文件中注冊
5)objectFactory 對象工廠
6)plugins 插件機制
我們可以通過插件來修改MyBatis的一些核心行為。插件通過動態代理機制,可以介入四大對象的任何一個方法的執行
<plugins> <!-- 分頁插件 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin> </plugins>
四大對象
Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed) ParameterHandler (getParameterObject, setParameters) ResultSetHandler (handleResultSets, handleOutputParameters) StatementHandler (prepare, parameterize, batch, update, query)
7)environments 環境配置
MyBatis可以配置多種環境,根據需要每種環境使用一個environment標簽進行配置並指定唯一標識符
可以通過environments標簽中的default屬性指定一個環境的標識符來快速的切換環境
id:指定當前環境的唯一標識 transactionManager、和 dataSource 都必須有
<environments default="mysql"> <environment id="mysql"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="${jdbc.driver}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </dataSource> </environment> </environments>
實際開發中我們使用Spring管理數據源,並進行事務控制的配置來覆蓋上述配置
8)databaseIdProvider數據庫廠商標識
MyBatis 可以根據不同的數據庫廠商執行不同的語句
<databaseIdProvider type="DB_VENDOR"> <property name="MySQL" value="mysql"/> </databaseIdProvider>
Type: DB_VENDOR, 使用MyBatis提供的VendorDatabaseIdProvider解析數據庫廠商標識。也可以實現DatabaseIdProvider接口來自定義.
配置了databaseIdProvider后,在SQL映射文件中的增刪改查標簽中使用databaseId來指定數據庫標識的別名
<select id="getEmployeeById" resultType="com.mybatis.bean.Employee" databaseId="mysql"> select * from tbl_employee where id = #{id} </select>
MyBatis匹配規則如下
① 如果沒有配置databaseIdProvider標簽,那么databaseId=null
② 如果配置了databaseIdProvider標簽,使用標簽配置的name去匹配數據庫信息,匹配上設置databaseId=配置指定的值,否則依舊為null
③ 如果databaseId不為null,他只會找到配置databaseId的sql語句
④ MyBatis 會加載不帶 databaseId 屬性和帶有匹配當前數據庫databaseId 屬性的所有語句。如果同時找到帶有 databaseId 和不帶databaseId 的相同語句,則后者會被舍棄。
9)mappers 映射器
用來在mybatis初始化的時候,告訴mybatis需要引入哪些Mapper映射文件
resource : 引入類路徑下的文件
url : 引入網絡路徑或者是磁盤路徑下的文件
class : 引入Mapper接口
通常情況下使用批量注冊,這種方式要求SQL映射文件名必須和接口名相同並且在同一目錄下
<mappers> <package name="com.mybatis.dao"/> </mappers>
mapper 映射文件
MyBatis 的真正強大在於它的映射語句,就是針對 SQL 語句構建的
<mapper namespace="main.mapper.BookMapper" > </mapper>
SQL 映射文件有很少的幾個頂級元素
cache – 給定命名空間的緩存配置。
cache-ref – 其他命名空間緩存配置的引用。
resultMap – 是最復雜也是最強大的元素,用來描述如何從數據庫結果集中來加載對象。
parameterMap – 已廢棄!老式風格的參數映射。內聯參數是首選,這個元素可能在將來被移除,這里不會記錄。
sql – 可被其他語句引用的可重用語句塊。
insert – 映射插入語句
update – 映射更新語句
delete – 映射刪除語句
select – 映射查詢語
MyBatis 默認不是自動提交,需手動提交:sqlSession.commit();
insert
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO users (id,username,PASSWORD) VALUES(NULL,#{username},#{password}) </insert>
delete
<delete id="deleteUser"> DELETE FROM users WHERE id = #{id} </delete>
update
<update id="updateUser"> UPDATE users SET name=#{name},email=#{email} WHERE id = #{id} </update>
select
<select id="getUserById" resultType="main.beans.User"> SELECT id,username,`password`,`name`,email FROM users WHERE id = #{id} </select>
主鍵生成與獲取
數據庫分為支持主鍵自增與不支持的,mysql是支持的
功能:插入一條新數據時,即可通過其主鍵id值立馬查詢這條數據,一般在 insert 中設置 useGeneratedKeys 為 true,返回數據庫自動生成的主鍵 id,keyColumn 用於指定數據庫table中的主鍵,keyProperty 用於指定傳入對象的成員變量。
注意:settings 中設置為全局,在接口映射器(注解)中設置的 useGeneratedKeys 參數值將會覆蓋在settings元素中設置全局 useGeneratedKeys 參數值,xml 映射器中配置的 useGeneratedKeys參數只會對 xml 映射器產生影響
@Options(useGeneratedKeys=true,keyProperty="userId",keyColumn="userId")
參數傳遞
1) 單個普通類型參數
可以接受基本類型,包裝類型,字符串類型等。這種情況MyBatis可直接使用這個參數,#{abc},大括號內可隨便定義
2) 多個參數
任意多個參數,都會被MyBatis重新包裝成一個Map傳入。Map的key是param1,param2,或者0,1…, #{param1,param2}
值就是參數的值 #{key1,key2}:獲取參數的值,預編譯到SQL中。安全。
3) 命名參數
為參數使用@Param起一個名字,MyBatis就會將這些參數封裝進map中,key就是我們自己指定的名字
public Employee getEmployeeById(@Param("id")Integer id);
4) POJO
resultType自動映射,當這些參數屬於我們業務POJO時,我們直接傳遞POJO
autoMappingBehavior默認是PARTIAL,開啟自動映射的功能。唯一的要求是結果集列名和javaBean屬性名一致
5) Map
我們也可以封裝多個參數為map,直接傳遞 #{key} 直接傳入map中的key值
1) 查詢單行數據返回Map集合
public Map<String,Object> getEmployeeByIdReturnMap(Integer id );
2) 查詢多行數據返回Map集合
@MapKey("id") // 指定使用對象的哪個屬性來充當map的key public Map<Integer,Employee> getAllEmpsReturnMap();
6) Collection/Array
會被MyBatis封裝成一個 map 傳入, Collection 對應的 key 是 collection , Array 對應的 key 是 array . 如果確定是 List 集合,key 還可以是 list.
resultMap自定義映射
自定義 resultMap,可以實現高級結果集的映射
1) id :用於完成主鍵值的映射
2) result :用於完成普通列的映射
id、result屬性
<resultMap id="getBookById" type="main.beans.User"> <id column="id" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> </resultMap>
3) association :一個復雜的類型關聯,當一個對象的某個屬性是一個對象時,一般將結果包裝成此類型
我們可以使用聯合查詢,並以級聯屬性的方式封裝對象.使用 association 標簽定義對象的封裝規則
<select id="getEmployeeAndDept" resultMap="myEmpAndDept" > SELECT e.id eid, e.last_name, e.email,e.gender ,d.id did, d.dept_name FROM tbl_employee e , tbl_dept d WHERE e.d_id = d.id AND e.id = #{id} </select> <resultMap type="com.mybatis.beans.Employee" id="myEmpAndDept"> <id column="eid" property="id"/> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <!-- 級聯的方式 --> <result column="did" property="dept.id"/> <result column="dept_name" property="dept.departmentName"/> </resultMap>
對於每個實體類都應該有具體的增刪改查方法,也就是DAO層,因此我們也可以使用 association 分步查詢
在分步查詢的基礎上,可以使用延遲加載來提升查詢的效率,只需要在全局的 Settings 中配置
<select id="getEmployeeAndDeptStep" resultMap="myEmpAndDeptStep"> select id, last_name, email,gender,d_id from tbl_employee where id =#{id} </select> <resultMap type="com.mybatis.beans.Employee" id="myEmpAndDeptStep"> <id column="id" property="id" /> <result column="last_name" property="lastName"/> <result column="email" property="email"/> <result column="gender" property="gender"/> <association property="dept" select="com.mybatis.dao.DepartmentMapper.getDeptById" //mapper包中定義的查詢方法全類名 column="d_id" fetchType="eager"> </association> </resultMap>
4) collection :復雜類型的集,當一個對象的某個屬性是一個集合對象時
我們可以使用聯合查詢,並以級聯屬性的方式封裝對象.使用 collection 標簽定義對象的封裝規則
property: 關聯的屬性名
ofType: 集合中元素的類型
實際的開發中經常可以通過分步的方式完成查詢.
<select id="getDeptAndEmpsByIdStep" resultMap="myDeptAndEmpsStep"> select id ,dept_name from tbl_dept where id = #{id} </select> <resultMap type="com.mybatis.beans.Department" id="myDeptAndEmpsStep"> <id column="id" property="id"/> <result column="dept_name" property="departmentName"/> <collection property="emps" select="com.mybatis.dao.EmployeeMapper.getEmpsByDid" //mapper包中定義的查詢方法全類名 column="id"> </collection> </resultMap>
分步查詢多列值的傳遞
如果分步查詢時,需要傳遞給調用的查詢中多個參數,則需要將多個參數封裝成 Map來進行傳遞,語法如下: {k1=v1, k2=v2....}
在所調用的查詢方法取值時,就要參考Map的取值方式,需要嚴格的按照封裝map 時所用的key來取值.
fetchType屬性
在<association> 和 <collection> 標簽中都可以設置 fetchType,指定本次查詢是否要使用延遲加載。默認為 fetchType=”lazy” ,如果本次的查詢不想使用延遲加載,則可設置為 fetchType=”eager”.