MyBatisCRUD的最佳化上

來源:互聯網
上載者:User

標籤:style   color   使用   檔案   資料   os   

前幾天我們講了CRUD的全部測試,下面是對CRUD樣本的最佳化:
    1,typeAliases:在樣本中的UserMapper.xml檔案中可以看到,凡是使用到User類型的時候,都需要寫User的類的全限定名。在mybatis-config.xml中,可以使用typeAliases元素來簡化這個操作:
    在mybatis-config.xml中添加:
    <typeAliases>
        <typeAlias type="cd.itcast.mybatis.domain.User" alias="User"/>
    </typeAliases>
    即為cd.itcast.mybatis.domain.User起了一個簡化的名字:User,那麼之後在Mapper檔案中使用User就可以代替cd.itcast.mybatis.domain.User,想想hibernate的import。
    修改的UserMapper.xml檔案如下:
    <mapper namespace="cd.itcast.mybatis.domain.UserMapper">
        <insert id="save" keyProperty="id" parameterType="User" useGeneratedKeys="true">
            INSERT INTO user(name,hiredate) values (#{name},#{hireDate})
        </insert>

        <update id="update" parameterType="User">
            UPDATE user SET name = #{name},hiredate = #{hireDate} WHERE id = #{id}
        </update>

        <delete id="delete" parameterType="int">
            DELETE FROM user WHERE id = #{id}
        </delete>

        <select id="get" parameterType="int" resultType="User">
            SELECT * FROM user WHERE id = #{id}
        </select>

        <select id="list" resultType="User">
            SELECT * FROM user
        </select>
    </mapper>
    簡化不少。

    2, properties:我們說過資料庫的串連資訊一般要放到一個額外的.properties檔案中,mybatis允許我們這樣做。
    首先,修改mybatis-config.xml檔案:
    <environments default="default">
        <environment id="default">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="${driverClass}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    聯想spring的dataSource配置方式,不難理解。
    預留位置的資料來源配置有三種方式:
    第一種使用方式:在SqlSessionFactoryBuilder的build方法中,還提供了額外傳入Properties對象的方法:
    public SqlSessionFactory build(InputStream inputStream, Properties properties)
    這個方法後面的Properties對象就可以做為mybatis-config.xml中的參數來源。所以,我們可以這樣來使用:
    Properties p=new Properties();
    p.load(this.getClass().getClassLoader().getResourceAsStream(“db.properties”);
    並在classpath下定義一個db.properties檔案:
    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql:///hibernate
    username=root
    password=admin


    第二種使用方式:在mybatis-config.xml中有properties這樣一個標籤,那麼我們可以在mybatis-config.xml中定義:
    <properties>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql:///hibernate"/>
        <property name="username" value="root"/>
        <property name="password" value="admin"/>
    </properties>
    即可。

    第三種方式:在mybatis-config.xml中的properties元素中,引入外部的properties檔案:
    <properties resource="db.properties" />
    並在classpath中添加db.properties檔案即可。
    第三種方式和第二種方式可以混用,即:
    <properties resource="org/mybatis/example/config.properties">
          <property name="username" value="dev_user"/>
          <property name="password" value="F2Fa3!33TYyg"/>
    </properties>

    三者的優先順序為:代碼傳入的Properties > resource載入的Properties > properties元素中定義的property。

3,MyBatisUtil的抽象:
在mybatis中,SqlSessionFactory和SqlSession的作用和地位極其類似SessionFactory和Session,包括其執行緒安全性。即
SqlSessionFactory是安全執行緒的,在整個應用中對應一個資料來源只需要建立一個。
SqlSession是線程不安全的,生命週期最好是method或者線程。
所以,我們就能抽象一個MyBatisUtil來提供SqlSession的建立:
public class MyBatisUtil {
    private static SqlSessionFactory factory;

    static {
        try {
            factory = new SqlSessionFactoryBuilder().build(Resources
            .getResourceAsStream("mybatis-config.xml"));
        } catch (Exception e) {
            e.printStackTrace();
            }
        }

    public static SqlSession openSession() {
    return factory.openSession();
    }
}

4,Mapper介面的實現
在上面的測試案例中,在調用session的方法的時候,都會傳入要調用的SQL的namespace+id名稱,這不是必須的。可以只傳入id即可。但是,如果在mybatis的環境中有多個相同id的映射名稱,就會報錯。所以,一般情況下,調用方法最好還是使用namespace+id。但是,namespace+id的使用方式很容易報錯,因為是string類型的,沒有檢查。所以,mybatis提供了一種非常好的設計方式來避免這種問題,即Mapper介面。
對照UserMapper.xml的定義,我們只需要建立一個介面,注意,介面的名字和包必須和mapper.xml定義的namespace一致,即建立一個介面:cd.itcast.mybatis.domain.UserMapper:
package cd.itcast.mybatis.domain;
public interface UserMapper {
    //對應<insert id="save" keyProperty="id" parameterType="User">
    void save(User u);

    //對應<update id="update" parameterType="User">
    void update(User u);

    //對應<delete id="delete" parameterType="long">
    void delete(Long id);

    //對應<select id="get" parameterType="long" resultType="User">
    User get(Long id);

    //對應<select id="list" resultType="User">
    List<User> list();
}
對照每一個方法的注釋,應該是很好理解的。
使用Mapper介面。有了Mapper介面,並且Mapper介面放在了指定的位置之後,我們的測試就可以寫成:
public class CRUDTest {
@Test
public void testSave() {
    SqlSession session = MyBatisUtil.openSession();
    try {
        User u = new User();
        u.setName("itcasT");
        u.setHireDate(new Date());
        UserMapper mapper=session.getMapper(UserMapper.class);
        mapper.save(u);
        session.commit();
    } finally {
        session.close();
    }
}

@Test
public void testGet() {
    SqlSession session = MyBatisUtil.openSession();
    try {
        UserMapper mapper=session.getMapper(UserMapper.class);
        User u=mapper.get(2l);
        System.out.println(u);
    } finally {
        session.close();
    }
}

@Test
public void testUpdate() {
    SqlSession session = MyBatisUtil.openSession();
    try {
        User u = new User();
        u.setId(1l);
        u.setName("update");
        u.setHireDate(new Date());
        UserMapper mapper=session.getMapper(UserMapper.class);
        mapper.update(u);
        session.commit();
    } finally {
        session.close();
    }
}

@Test
public void testList() {
    SqlSession session = MyBatisUtil.openSession();
    try {
        UserMapper mapper=session.getMapper(UserMapper.class);
        List<User> us= mapper.list();
        System.out.println(us);
    } finally {
        session.close();
    }
}

@Test
public void testDelete() {
    SqlSession session = MyBatisUtil.openSession();
    try {
        UserMapper mapper=session.getMapper(UserMapper.class);
        mapper.delete(2l);
        session.commit();
    } finally {
        session.close();
    }
}
}
代碼變得非常清晰,並且類型都使用介面強制性的完成。
Mybatis怎麼做的?
測試:
@Test
public void testMapper(){
    SqlSession session = MyBatisUtil.openSession();
    try {
        UserMapper mapper=session.getMapper(UserMapper.class);
        System.out.println(mapper.getClass().getName());
    } finally {
        session.close();
    }
}
列印結果:
$Proxy4
很簡單了,mybatis為介面做了一個動態代理。在執行UserMapper介面上面的方法時,參考介面的全限定名,即可找到對應的UserMapper.xml,在執行介面上面的每一個方法的時候,實際上就是在執行namespace+id,mybatis在根據定義的方法的元素,選擇調用合適的session的方法來執行,並傳入參數可以。
使用Mapper介面的方式,在整合Spring+MyBatis也非常方便。因為我們可以直接把Mapper介面看作DOMAIN的DAO介面了。

假設現在User對象不變,但是對應USER表中的name列的名稱DBA重新設計成了username,那現在再來運行一遍測試:
可以看到這次的name屬性就為null。這時候就體現出mybatis在直接使用resultType的局限性,要求屬性名稱必須和列的名稱一致(大小寫可以不一致)。在這種情況下,就必須要手動來完成資料表列和對象的映射關係了。首先來修改get方法:
<select id="get" parameterType="int" resultMap="usermapping">
SELECT * FROM user WHERE id = #{id}
</select>
在這裡,可以看到,去掉了resultType,因為resultType只能完成預設的物件類型的轉換。在這裡修改成了resultMap,其實這裡叫做resultMapping對於學習了hibernate的童鞋來說更好理解。在這裡我把結果集定義到了一個名字叫做usermapping的映射上。下面定義usermapping:
<resultMap type="User" id="usermapping">
    <id property="id" column="id"/>
    <result property="name" column="username"/>
    <result property="hireDate" column="hiredate"/>
</resultMap>
resultMap定義了一個ORM的具體映射方式。
1,type:代表O,即最終返回的物件類型
2,id:為該映射設定一個名稱,這個名稱就是在get或list中使用的resultMap對應的id
3,id/result:對應這屬性的映射,可以參考hibernate的property。id和result的區別在於,id一般用於映射主鍵,可以提高速度,result一般對於普通的屬性。
設定完成後,就可以將對象正常get了。
在mybatis中,其實如果僅僅只是使用了resultType,相當於mybatis自動的幫我們建立了一個resultMap,只是這個resultMap直接完成了屬性和列相同名稱的映射而已。所以,mybatis真正完成映射的地方就在resultMap。

到此,單對象的CRUD的Mybatis實現就完成了。可以看到,在mybatis中,大部分的控制細節仍然是交由我們自己去控制,特別是sql。所以,待會我們看到多個物件關係的時候,一定要有這個概念,mybatis不會像hibernate那樣為我們考慮周全對象的CRUD,所有的SQL都應該由我們自己去控制。所以,在完成mybaits對象關係的配置中,需要轉變一些在hibernate中的固有的物件導向的思想。如果說hibernate是物件導向為主,關係為輔,那麼在mybatis中則是著重考慮的是關聯式模式,換句話說,如果物件模型設計的不好,就會很容易的感覺到實現的難度。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.