Mybatis 框架使用的最核心內容(一):Mybatis的特點和對映管理
關於mybatis是什麼、有什麼特點、實現機制之類的話題,網上通篇大論,這裡不再贅述,只談乾貨,希望能夠用最高的效率,最精確的和讀者找到共鳴並相互交流。
一、為什麼要使用mybaits框架?
1)效率上最優:相比hibernate而言,mybatis的體積如同九牛一毛,載入速度快,執行速度快,極大的提供和程式和資料庫之間的互動效率;
2)靈活性最強:mybatis框架的實現是基於開發者對SQL語句的使用,因此開發者可以非常靈活的對SQL語句進行編寫和修改已到達需要的結果;
3)學習性強:通過對mybaits框架的時候,開發者可以更好更多的結合資料庫進行SQL語句的編寫,在完成功能開發的同時也進一步練習和提高了對資料庫常用技術的使用,可謂一石二鳥。
二、mybatis在專案中扮演什麼角色?以什麼形式存在?mybatis的事物管理機制是怎樣的?
1)mybatis是一個ORM框架,屬於DAO層,負責和資料庫進行互動;
2)DAO層資料夾中分別存放了mapper.java 和 mapper.xml ;
3)mapper.xml 是對 mapper.java 介面的實現。他們之間的關聯通過mapper.xml 中的<mapper ></mapper> 標籤中的namespace屬性實現繫結
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="mapper.OrderitemMapper" > </mapper>
4)檢驗是否繫結成功:如果按住ctrl鍵點選namespace中的值,可以直接跳轉到對應的介面,則表示跳轉成功
5)mybatis框架獨立執行時,需要手動控制事物,進行開啟、提交、回滾、關閉操作。若集成了Spring框架,則可以將其託管到Spring中自動管理
SqlSession session= MyBatisSessionFactory.getSession(); //獲取資料庫連線
session.commit(); //提交
session.rollback(); //回滾
session.close(); //關閉連線
三、mybaits介面方法和介面方法的實現
1)mapper.xml 是 mapper.java 的實現,兩者通過 <statementSql></statementSql> 的 id屬性來關聯 【statementSql 泛指xml檔案中的sql執行語句片段】
mapper.java
package mapper;
import java.util.List;
import pojo.CustomerAndOrder;
public interface CustomerMapperOrder {
List<CustomerAndOrder> findCusAndOrderByCid ();
}
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="mapper.CustomerMapperOrder" >
<!-- 此mapper.xml 是作為一對一的關係表結果的對映管理 -->
<sql id="cusAndOrder">
c.*,
o.order_id as orderId,
o.create_date as createDate
</sql>
<select id="findCusAndOrderByCid" resultType="pojo.CustomerAndOrder">
select
<include refid="cusAndOrder"/>
from
customer c,ordertable o
WHERE
c.cid = o.cid
</select>
</mapper>
可以看到<select id = " finCusAndOrderByCid" > 中 id 的值 就是 mapper.java 中的方法名
四、介面方法和介面實現中 出入參 型別的定義
1)介面實現中可用的型別:java中的普通型別 和 自定義的pojo型別
2)定義入參的的屬性:在 parameterType = " " 屬性中定義【注意:入參是可選屬性,根據需求設定】
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from product
where product_id = #{productId,jdbcType=VARCHAR}
</select>
3)定義出參的屬性:出參定義的是mapper.xml中的重點。
對於增刪改語句,返回值是可選引數,如果要求有返回值,則他們的返回值預設為 int 型,這是由mybatis的底層定義的
如:mapper.xml
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
delete from product
where product_id = #{productId,jdbcType=VARCHAR}
</delete>
<insert id="insert" parameterType="pojo.Product" >
insert into product (product_id, product_factroy, product_store,
product_descript)
values (#{productId,jdbcType=VARCHAR}, #{productFactroy,jdbcType=VARCHAR}, #{productStore,jdbcType=INTEGER},
#{productDescript,jdbcType=VARCHAR})
</insert>
<pre name="code" class="html"><update id="updateByPrimaryKey" parameterType="pojo.Product" >
update product
set product_factroy = #{productFactroy,jdbcType=VARCHAR},
product_store = #{productStore,jdbcType=INTEGER},
product_descript = #{productDescript,jdbcType=VARCHAR}
where product_id = #{productId,jdbcType=VARCHAR}
</update>
mapper.java
int deleteByPrimaryKey(String productId) throws Exception;
int insert(Product record) throws Exception ;
int updateByPrimaryKey(Product record) throws Exception;
而對於查詢語句<select > 而言,返回值是查詢語句得到每一條結果的對映。
查詢結果的資料型別,決定了出參的型別;查詢結果的條目數,決定了是否採用集合或者陣列。換言之:如果返回單個值,外部用單值的方式接收;如果是多個值,就需要用List<?> 來接收
mapper.java
//通過主鍵查詢結果,只可能是一個物件,所以直接用自定義物件接收
Product selectByPrimaryKey(String productId) throws Exception;
//通過條件進行查詢的結果,可能是返回對個物件,因此需要用List<Product> 來接收
List<Product> selectProByConditions(Product product);
mapper.xml 【在xml中的返回值型別為pojo.Product ,返回值的條目數決定了外部接收的單個值型別還是多個值型別】
<select id="selectByPrimaryKey" resultMap="pojo.Product" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from product
where product_id = #{productId,jdbcType=VARCHAR}
</select>
<select id="selectProByConditions" parameterType="<span style="font-family:Arial, Helvetica, sans-serif;">java.lang.String</span>" resultMap="pojo.Product">
select * from product
<where>
<if test="productId!=null and productId!=''">
and product_id = #{productId}
</if>
<if test="productFactroy!=null and productFactroy!='' ">
and product_factroy = #{productFactroy}
</if>
<if test="productStore!=null">
and product_store = #{productStore}
</if>
<if test="productDescript!=null">
and product_descript = #{productDescript}
</if>
</where>
</select>
管理結果對映的標籤有兩種,分別是resultType和 resultMap 。通過這兩個標籤建立資料庫查詢結果的列和程式中實體類或java型別的對映關係
resultType 和 resultMap 之間的關係和區別,一直是mybatis開發者關心的問題。但其實通過幾個小的練習,就可以將兩者的關係和使用場景搞明白了。
resultType:是屬性,可以管理普通返回值型別,也可以返回自定義的pojo包裝類。
如:
<sql id="cusAndOrder">
c.*,
o.order_id as orderId,
o.create_date as createDate
</sql>
<select id="findCusAndOrderByCid" resultType="pojo.CustomerAndOrder">
select
<include refid="cusAndOrder"/>
from
customer c,ordertable o
WHERE
c.cid = o.cid
</select>
其中pojo.CustomerAndOrder是筆者自定義的型別,繼承與Customer 類,並加入了幾條Order的屬性【注意:在宣告自定義類時,一定要生成getter、setter、還有兩構造方法 】
有了構造方法,物件才能被初始化,查詢結果才能被對映到對應欄位
package pojo;
import java.math.BigDecimal;
import java.util.Date;
public class CustomerAndOrder extends Customer {
private String orderId;
private Date createDate;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public CustomerAndOrder(String cid, String cname, String address,
String clevel, String email, BigDecimal balance, String orderId,
Date createDate) {
super(cid, cname, address, clevel, email, balance);
this.orderId = orderId;
this.createDate = createDate;
}
public CustomerAndOrder() {
super();
// TODO Auto-generated constructor stub
}
public CustomerAndOrder(String cid, String cname, String address,
String clevel, String email, BigDecimal balance) {
super(cid, cname, address, clevel, email, balance);
// TODO Auto-generated constructor stub
}
}<strong>
</strong>
操作技巧:通過resultType定義返回值的時候,一定要注意查詢結果的列名和屬性名要一致才能被對映到。如果列名和欄位名不一致,可以通過對欄位名起別名,將值對映到自定義的屬性中
從上方的兩段程式碼中可以發現<sql>片段中將order_id 起別名為 orderId 的目的就是為了對映關聯
resultMap:是屬性,也是標籤;它可以定義返回值型別,也可以作為對映管理器標籤獨立存在
<resultMap id="BaseResultMap" type="pojo.OrderTable" >
<id column="order_id" property="orderId" jdbcType="VARCHAR" />
<result column="cid" property="cid" jdbcType="VARCHAR" />
<result column="address" property="address" jdbcType="VARCHAR" />
<result column="create_date" property="createDate" jdbcType="TIMESTAMP" />
<result column="orderitem_id" property="orderitemId" jdbcType="VARCHAR" />
<!--維護一對多的關係 -->
<collection property="orderitemList" ofType="pojo.Orderitem">
<id column="orderitem_id" property="orderitemId"/>
<result column="product_id" property="productId"/>
<result column="count" property="count"/>
</collection>
</resultMap>
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
<!--
WARNING - @mbggenerated
This element is automatically generated by MyBatis Generator, do not modify.
This element was generated on Fri May 06 15:49:42 CST 2016.
-->
select
<include refid="Base_Column_List" />
from ordertable
where ordertable.order_id = #{orderId,jdbcType=VARCHAR}
</select>
從上面的程式碼塊中可以發現:resultMap 作為對映管理器標籤獨立使用 ,其中id屬性的值作為對映管理器的標識碼,可以被statementSql引用
而對映管理器的作用在於可以用來維護實體類之間的關係,如程式碼片段中所示:resultMap中通過<collection>標籤維護了一個一對多的關係,在pojo.OrderTable中有一個以List存在的Orderitem 類,和OrderTable是一對多的關係。
resultMap作為對映管理器標籤的具體功能將在《Mybatis 框架使用的最核心內容(二):mpper.xml中的常用標籤詳解》中介紹