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中究竟有多少物件,這樣不利於業務層的可擴充套件。