zoukankan      html  css  js  c++  java
  • Mybatis之旅第二篇-Mapper动态代理方式

    一、引言

    通过上一篇mybatis的入门学习,我们已经会使用mybatis实现简单的增删改查,但是我们也发现了用原始Dao开发的一些问题:

    1. Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法

    2. 调用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

    内容:

    public interface UserMapper {
    
        //查询用户
        User queryUserById(int id);
        //查询用户列表
        List<User> selectUserAll();
    
        //模糊查询
        List<User> selectLikeUserName(String username);
    
        //新增
        void saveUser(User user);
        
    }

    第三步:加载UserMapper.xml文件

    <mappers>
        <!-- 映射文件方式1,一个一个的配置-->
        <mapper resource="config/sqlmap/User.xml"/>
        <mapper resource="config/mapper/UserMapper.xml"/>
    </mappers>

    测试:

    public class MapperTest {
        private SqlSessionFactory sqlSessionFactory;
    
        @Before
        public void init() throws Exception {
            // 创建SqlSessionFactoryBuilder
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            // 加载SqlMapConfig.xml配置文件
            InputStream inputStream = Resources.getResourceAsStream("config/SqlMapConfig.xml");
            // 创建SqlsessionFactory
            this.sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
        }
    
        @Test
        public void 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
        public void testQueryUserByUsername() {
            // 获取sqlSession,和spring整合后由spring管理
            SqlSession sqlSession = this.sqlSessionFactory.openSession();
    
            // 从sqlSession中获取Mapper接口的代理对象
            UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
            // 执行查询方法
            List<User> list = userMapper.selectLikeUserName("张");
            for (User user : list) {
                System.out.println(user);
            }
    
            // 和spring整合后由spring管理
            sqlSession.close();
        }
    
        @Test
        public void 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的通用性。

  • 相关阅读:
    Android Service 与 Activity使用Pending Intent通信
    Android四大组件之Service(一)
    Android中的进程和线程
    Java虚拟机结构(二)
    Java虚拟机结构(一)
    Android四大组件之Activity(一)
    一阶规则学习
    规则学习
    算法链接
    41. First Missing Positive
  • 原文地址:https://www.cnblogs.com/yuanqinnan/p/10548717.html
Copyright © 2011-2022 走看看