使用MyBatis 實現Dao層,並使用Mapper動態代理

一個小案例

如果我不用id作爲主鍵,而是用UUID作爲主鍵,怎麼操作?

第一種方法

    <insert id="insertUser" parameterType="com.bamzhy.bean.User">
        INSERT INTO tt_user VALUES (#{id},#{username},#{password},#{email},#{age});
    </insert>
    @Test
    public void test3() throws IOException {
        //使用Mybatis的api去實現
        //加載配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //操作數據庫的一個載體
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //返回一個對象
        User user = new User();
        //Universally Unique Identifier(UUID 通用唯一識別碼)
        user.setId(UUID.randomUUID().toString());
        user.setUsername("haha4");
        user.setPassword("12345");
        user.setEmail("[email protected]");
        user.setAge(199191);
        int insert = sqlSession.insert("test.insertUser", user);
        sqlSession.commit();

        System.out.println("insert "+insert);
    }

第二種方法

  • 使用selectKey

    <insert id="insertUser" parameterType="com.bamzhy.bean.User">
        <!--keyProperty對應的是下邊{}中的名稱,resultType是其格式,order是執行時間在此條sql語句前還是語句後-->
        <selectKey keyProperty="id" resultType="string" order="BEFORE">
            SELECT UUID()
        </selectKey>
        INSERT INTO tt_user VALUES (#{id},#{username},#{password},#{email},#{age});
    </insert>

使用MyBatis ORM實現DAO層

案例2實現之前代碼的重構

src下邊的mybatis.xml和user.xml跟之前的沒有區別(那些不用動)

  • 新增UserDaoImpl.java
    @Override
    public User findUserById(int id) throws IOException {
        //使用Mybatis的api去實現
        //加載配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        //操作數據庫的一個載體
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //返回一個對象
        User user = sqlSession.selectOne("test.findUserById", id);
        System.out.println("user"+user);
        return null;
    }
  • 新增一個測試用例
    @Test
    public void findUserById() throws IOException {
        UserDao user=new UserDaoImpl();
        user.findUserById(2);
    }
  • 考慮到沒必要每一次操作都new一個sqlSessionFactory,所以我們把new這個操作的過程放進DAO中
    這裏寫圖片描述

對之前案例的反思

  • 有大量代碼是重複的
  • SqlSessionFactory,應該是全局範圍的,整個應用只有一個工廠。使用單例模式來實現。與spring集成了之後,由spring對其來進行單例管理。
  • SqlSession。它內部含有一塊數據區域,操作數據庫的時候是需要通過它去設置隔離級別等事務特性。如果放在成員變量中使用spring對其來進行單例管理,則在多線程的情況下會存在線程安全問題。所以應該將sqlSession聲明在方法內部。 這樣每個線程用自己的sqlSession,不共享數據,則不存在線程安全問題。

從全新角度出發解決問題(Mapper動態代理實現)

開發規範

  • Mapper接口的全限定名要和Mapper映射文件的namespace一致
    這裏寫圖片描述
    這裏寫圖片描述

  • Mapper接口的方法名稱要和Mapper映射文件的statement id一致
    這裏寫圖片描述 這裏寫圖片描述

  • Mapper接口的方法參數類型要和Mapper映射文件的statement parameter Type類型一致,而且它的參數是一個(多個參數也沒關係,可以使用map裝進去)

  • Mapper接口的方法返回值類型要和Mapper映射文件的statement的Result Type一致
    這裏寫圖片描述
    這裏寫圖片描述

如果是List<>的話,需要保證其泛型類型與resultType保持一致(每一行的類型)

  • bean裏邊的xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bamzhy.dao.UserDao">

    <!--parameterType是參數的類型,以前的問號?用#{}代替-->
    <!--這一行SQL語句要映射到哪個類上要使用resultType指明-->
    <select id="findUserById" parameterType="int" resultType="com.bamzhy.bean.User">
        SELECT * FROM tt_user WHERE id=#{id};
    </select>

    <select id="findUserByName" parameterType="string" resultType="com.bamzhy.bean.User">
        SELECT * FROM tt_user WHERE username Like #{id};
    </select>

    <insert id="insertUser" parameterType="com.bamzhy.bean.User">
        <!--keyProperty對應的是下邊{}中的名稱,resultType是其格式,order是執行時間在此條sql語句前還是語句後-->
        <!--<selectKey keyProperty="id" resultType="string" order="BEFORE">-->
            <!--SELECT UUID()-->
        <!--</selectKey>-->
        <selectKey keyProperty="id" resultType="string" order="AFTER">
            SELECT LAST_INSERT_ID()
        </selectKey>
        INSERT INTO tt_user VALUES (#{id},#{username},#{password},#{email},#{age});
    </insert>

    <delete id="deleteUserById" parameterType="int">
        DELETE FROM tt_user WHERE id=#{id};
    </delete >

    <update id="updateUserById" parameterType="com.bamzhy.bean.User">
        UPDATE tt_user SET username=#{username},password=#{password} WHERE  id=#{id};
    </update>

</mapper>
  • Dao接口
package com.bamzhy.dao;

import com.bamzhy.bean.User;

import java.io.IOException;
import java.util.List;

public interface UserDao {
    User findUserById(int id) throws IOException;

    User finduUserByName(String username) throws IOException;

    int AddUser(User user) throws IOException;

    List<User> queryAllUser( ) throws IOException;
}
  • test
package com.bamzhy.test;

import com.bamzhy.bean.User;
import com.bamzhy.dao.UserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

public class test {

    SqlSessionFactory sqlSessionFactory ;
    UserDao dao;
    SqlSession sqlSession;

    //在任何一個測試方法之前執行
    @Before
    public void before() throws Exception {
        //加載配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);

        sqlSession = sqlSessionFactory.openSession();

        dao = sqlSession.getMapper(UserDao.class);

    }
    //在任何一個測試方法之後執行
    @After
    public void After(){
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void test6() throws IOException {
        User userById = dao.findUserById(1);
        System.out.println("user=" + userById);
    }
}

使用Mapper動態代理的好處

  • 使用之前的session,selectOne(“test.findUserById”,1),通過字符串調用標籤定義的SQL,一是容易出錯,而是XML中的id修改以後那麼用了這個id的程序就都得改,這樣比較麻煩
  • 爲了防止這些現象的出現,採用了Mapper方法

使用Mapper動態代理的流程

  • 我們定義一個接口類,裏邊函數名和需要與Bean中的XML文件定義的id保持一致。
  • 把Bean中的namespace替換成接口類的全類名
  • 獲取session,並獲取Mapper接口的代理對象(這個可用使用AOP放在方法執行前執行)
        //加載配置文件
        InputStream resourceAsStream = Resources.getResourceAsStream("mybatis.xml");
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession = sqlSessionFactory.openSession();
        //獲取代理對象
        dao = sqlSession.getMapper(UserDao.class);
  • 調用代理對象方法,關閉session(也用AOP實現)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章