1. 程式人生 > >mybatis(7)--使用mapper代理開發代替原始的dao開發

mybatis(7)--使用mapper代理開發代替原始的dao開發

在原始的dao中我們發現了很多問題,而mapper代理開發則會幫我們解決這些問題。
具體思路:
1.需要編寫對映檔案mapper.xml
2.使用mapper介面來代替dao介面
3.mybatis會自動實現mapper介面的代理類物件
how?
mapper介面是有一定的編寫規範,mybatis根據這些規範動態的使用反射獲取方法名方法引數等,從而實現mapper的代理

首先來看mapper.xml,不難看出,它和之前的user.xml
幾乎是一樣的,只是這個namespace不一樣,以前的是test,所以我們呼叫的時候便只能硬編碼呼叫。那麼現在,他把這個sql的呼叫寫成一個類,裡面的方法遵循一定的規範,根據這種規範,去實現其代理。

<?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.xml的namespace需要和mapper的介面地址一致 -->
<mapper namespace="com.ddd.mybatis.mapper ">

    <select id="findUserById" parameterType
="int" resultType="com.ddd.mybatis.pojo.User">
SELECT * FROM USER WHERE id=#{id} </select> <select id="findUserByName" parameterType="java.lang.String" resultType="com.ddd.mybatis.pojo.User"> SELECT * FROM USER WHERE username LIKE '%${value}%' </select
>
<insert id="insertUser" parameterType="com.ddd.mybatis.pojo.User"> <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer"> SELECT LAST_INSERT_ID() </selectKey> INSERT INTO USER(username,sex,birthday,address) VALUES(#{username},#{sex},#{birthday},#{address}) </insert> <delete id="deleteUserById" parameterType="java.lang.Integer"> DELETE FROM USER WHERE id=#{id} </delete> <update id="updateUser" parameterType="com.ddd.mybatis.pojo.User"> UPDATE USER SET username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} WHERE id=#{id} </update> </mapper>

再看mapper.java是怎麼寫的:

package com.ddd.mybatis.mapper;

import java.util.List;

import com.ddd.mybatis.pojo.User;

/**
 * 使用mapper介面相當於dao介面
 * 
 * @author Dan
 * mapper.xml的namespace需要和mapper.java的介面地址一致
 *mapper.java中的方法的方法名要和mapper.xml中的statement的id一致
 *輸入引數要和mapper.xml中的statement的parameterType指定型別一致
 *方法的返回值要和mapper.xml中的statement的resultType指定型別一致
 */
public interface UserMapper {

    // 根據id查詢一個user
    public User findUserById(int id);
    //根據名字查詢user
    public List<User> findUserByName(String name);
    // 新增使用者
    public void insertUser(User u);

    // 刪除使用者
    public void deleteUserById(int id);

    // 更新使用者
    public void updateUser(User u);

}

根據這四個規範,我們可以看出,方法名字,sql的id名字,輸入輸出型別的限制,可以使用Method.class.getDeclaredMethod(name, parameterTypes)來獲取到一個方法,在這方法的前後加入sqlSession的建立提交等,這很明顯我們可以使用動態代理。

接下來測試:(記得要將userMapper.xml加入到sqlMapConfig.xml中)

package com.ddd.mybatis.mapperTest;

import static org.junit.Assert.*;

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

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.Before;
import org.junit.Test;

import com.ddd.mybatis.mapper.UserMapper;
import com.ddd.mybatis.pojo.User;

public class UserMapperTest {
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setUp() throws IOException{
        String fileSource="SqlMapConfig.xml";
        //獲取檔案流
        InputStream inputStream=Resources.getResourceAsStream(fileSource);
        //根據載入的配置檔案資訊建立SqlSessionFactory
        sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
    }
    @Test
    public void testFindUserById() {
        //由於之前是在UserDaoImpl中每次獲取sqlSession,所以這裡需要我們手動寫
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //mybatis自動生成mapper代理物件,代理物件內部呼叫selectOne或者selectList
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        //呼叫userMapper的方法
        User u=userMapper.findUserById(1);
        System.out.println(u);
    }
    @Test
    public void testFindUserByName() {
        //由於之前是在UserDaoImpl中每次獲取sqlSession,所以這裡需要我們手動寫
        SqlSession sqlSession=sqlSessionFactory.openSession();
        //mybatis自動生成mapper代理物件,代理物件內部呼叫selectOne或者selectList
        UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
        //呼叫userMapper的方法,返回集合,但這裡如果不小心用一個單個user來接收,那會報錯
        List<User> list=userMapper.findUserByName("小明");
        System.out.println(list);
    }
}

問題總結:

mapper的方法是依據parameterType來寫,而它只能有一個,這是否會影響我們擴充套件維護呢?

在我們的系統框架中,dao層的程式碼是被業務層呼叫的,即使mapper介面的方法只有一個引數,可以使用包裝型別的pojo滿足不同的業務方法需求
ps:持久層方法中引數可以是包裝型別,例如map等,但service中不建議使用包裝型別,因為service是被各種各樣的前臺服務呼叫的,而前臺並不知道你這個map中究竟有多少物件,這樣不利於業務層的可擴充套件。