一、引言
通過上一篇mybatis的入門學習,我們已經會使用mybatis實現簡單的增刪改查,但是我們也發現了用原始Dao開發的一些問題:
Dao方法體存在重復代碼:通過SqlSessionFactory創建SqlSession,調用SqlSession的數據庫操作方法
調用sqlSession的數據庫操作方法需要指定statement的id,這里存在硬編碼,不得于開發維護。
為了解決這些問題,我們采用Mapper動態代理方法來進行開發:程序員編寫Mapper接口(相當于Dao接口),由Mybatis框架根據接口定義創建接口的動態代理對象,代理對象的方法體同上邊Dao接口實現類方法。
二、開發規范
Mapper接口開發需要遵循以下規范:
1、 Mapper.xml文件中的namespace與mapper接口的類路徑相同。
2、 Mapper接口方法名和Mapper.xml中定義的每個statement的id相同
3、 Mapper接口方法的輸入參數類型和mapper.xml中定義的每個sql 的parameterType的類型相同
4、Mapper接口方法的輸出參數類型和mapper.xml中定義的每個sql的resultType的類型相同
三、改造
第一步:Mapper.xml(映射文件)
定義mapper映射文件UserMapper.xml,將UserMapper.xml放在config下mapper目錄下,效果如下:
文件內容如下:
<?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"><!-- namespace:命名空間,用于隔離sql,還有一個很重要的作用,后面會講 --><mapper namespace="com.yuanqinnan.mapper.UserMapper"><select id="queryUserById" parameterType="int" resultType="com.yuanqinnan.model.User">? ? SELECT * FROM `user`where id=#{id}
? </select><!-- 查詢 user 表的所有數據--><select id="selectUserAll" resultType="com.yuanqinnan.model.User">? ? ? ? select * from user
? ? </select><!--? ? ? ? ? ? 1、${value}里面必須要寫value,不然會報錯
? ? ? ? ? ? 2、${}表示拼接 sql 字符串,將接收到的參數不加任何修飾拼接在sql語句中
? ? ? ? ? ? 3、使用${}會造成 sql 注入
? ? --><select id="selectLikeUserName" resultType="com.yuanqinnan.model.User" parameterType="String">? ? ? ? select * from user where username like '%${value}%'
? ? </select><!--#{}實現--><select id="selectLikeUserName2" resultType="com.yuanqinnan.model.User" parameterType="String">? ? ? ? select * from user where username like #{username}
? ? </select><!-- 向 user 表插入一條數據 --><insert id="insertUser" parameterType="com.yuanqinnan.model.User">? ? ? ? insert into user(id,username,sex,birthday,address)
? ? ? ? ? ? value(#{id},#{username},#{sex},#{birthday},#{address})
? ? </insert><!-- 保存用戶 --><insert id="saveUser" parameterType="com.yuanqinnan.model.User"><!-- selectKey 標簽實現主鍵返回 --><!-- keyColumn:主鍵對應的表中的哪一列 --><!-- keyProperty:主鍵對應的pojo中的哪一個屬性 --><!-- order:設置在執行insert語句前執行查詢id的sql,在執行insert語句之后執行查詢id的sql --><!-- resultType:設置返回的id的類型 --><selectKey keyColumn="id" keyProperty="id" order="AFTER"? ? ? ? ? ? ? ? ? resultType="int">? ? ? ? ? ? SELECT LAST_INSERT_ID()
? ? ? ? </selectKey>? ? ? ? INSERT INTO `user`
? ? ? ? (username,birthday,sex,address) VALUES
? ? ? ? (#{username},#{birthday},#{sex},#{address})
? ? </insert><!-- 根據 id 更新 user 表的數據 --><update id="updateUserById" parameterType="com.yuanqinnan.model.User">? ? ? ? update user set username=#{username} where id=#{id}
? ? </update><!-- 根據 id 刪除 user 表的數據 --><delete id="deleteUserById" parameterType="int">? ? ? ? delete from user where id=#{id}
? ? </delete></mapper>
其他地方未有改動,主要是namespace="com.yuanqinnan.mapper.UserMapper"的修改,現在我們實現這個接口
第二步:UserMapper(接口文件)
新建mapper包,新增接口UserMapper
內容:
publicinterface UserMapper {
? ? //查詢用戶User queryUserById(int id);
? ? //查詢用戶列表List selectUserAll();
? ? //模糊查詢List selectLikeUserName(String username);
? ? //新增void saveUser(User user);
}
第三步:加載UserMapper.xml文件
<mappers><!-- 映射文件方式1,一個一個的配置--><mapper resource="config/sqlmap/User.xml"/><mapper resource="config/mapper/UserMapper.xml"/></mappers>
測試:
publicclass MapperTest {
? ? private SqlSessionFactory sqlSessionFactory;
? ? @Before
? ? publicvoidinit()throws Exception {
? ? ? ? // 創建SqlSessionFactoryBuilderSqlSessionFactoryBuilder sqlSessionFactoryBuilder =new SqlSessionFactoryBuilder();
? ? ? ? // 加載SqlMapConfig.xml配置文件InputStream inputStream = Resources.getResourceAsStream("config/SqlMapConfig.xml");
? ? ? ? // 創建SqlsessionFactorythis.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
? ? }
? ? @Test
? ? publicvoid testQueryUserById() {
? ? ? ? // 獲取sqlSession,和spring整合后由spring管理SqlSession sqlSession =this.sqlSessionFactory.openSession();
? ? ? ? // 從sqlSession中獲取Mapper接口的代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
? ? ? ? // 執行查詢方法User user = userMapper.queryUserById(1);
? ? ? ? System.out.println(user);
? ? ? ? // 和spring整合后由spring管理? ? ? ? sqlSession.close();
? ? }
? ? @Test
? ? publicvoid testQueryUserByUsername() {
? ? ? ? // 獲取sqlSession,和spring整合后由spring管理SqlSession sqlSession =this.sqlSessionFactory.openSession();
? ? ? ? // 從sqlSession中獲取Mapper接口的代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
? ? ? ? // 執行查詢方法List list = userMapper.selectLikeUserName("張");
? ? ? ? for (User user : list) {
? ? ? ? ? ? System.out.println(user);
? ? ? ? }
? ? ? ? // 和spring整合后由spring管理? ? ? ? sqlSession.close();
? ? }
? ? @Test
? ? publicvoid testSaveUser() {
? ? ? ? // 獲取sqlSession,和spring整合后由spring管理SqlSession sqlSession =this.sqlSessionFactory.openSession();
? ? ? ? // 從sqlSession中獲取Mapper接口的代理對象UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
? ? ? ? // 創建保存對象User user =new User();
? ? ? ? user.setUsername("劉備");
? ? ? ? user.setBirthday(new Date());
? ? ? ? user.setSex("1");
? ? ? ? user.setAddress("蜀國");
? ? ? ? // 執行查詢方法? ? ? ? userMapper.saveUser(user);
? ? ? ? System.out.println(user);
? ? ? ? // 和spring整合后由spring管理? ? ? ? sqlSession.commit();
? ? ? ? sqlSession.close();
? ? }
}
測試結果與上一篇相同
四、總結
selectOne和selectList
動態代理對象調用sqlSession.selectOne()和sqlSession.selectList()是根據mapper接口方法的返回值決定,如果返回list則調用selectList方法,如果返回單個對象則調用selectOne方法。
namespace
mybatis官方推薦使用mapper代理方法開發mapper接口,程序員不用編寫mapper接口實現類,使用mapper代理方法時,輸入參數可以使用pojo包裝對象或map對象,保證dao的通用性。