• Mybatis中原生DAO实现和Mapper动态代理实现


    Mybatis开发dao的方法通常用两种,一种是传统DAO的方法,另一种是基于mapper代理的方法。

    一、传统DAO方式开发

    1、sql语句映射文件编写

    User.xml

    <?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="test">
        <!-- 
        id:sql语句唯一标识
        parameterType:指定传入参数类型(pojo类中对应的类型,不是数据库中的类型)
        resultType:返回结果集类型
        #{}:占位符,如果传入的类型是基本类型(string,long,double,int,boolean,float等),那么#{}中变量名称可以任意
         -->
        <select id="findUserById" parameterType="java.lang.Integer" resultType="cn.itheima.pojo.User">
            SELECT * FROM user WHERE id=#{id}
        </select>
        
        <!-- 
        如果返回的结果为集合,resultType中也是配置为集合中泛型的类型,即resultType="cn.itheima.pojo.User"
        ${}:拼接符,如果传入的类型是基本类型(string,long,double,int,boolean,float等),那么${}中变量名称必须是value
         -->
        <select id="findUserByUserName" parameterType="java.lang.String" resultType="cn.itheima.pojo.User">
            SELECT * FROM user WHERE username LIKE '%${value}%'
        </select>
        
        <!-- 
        如果传入的是pojo类型,则#{}中变量名称必须是pojo中对应的属性.属性.属性......
        如果要返回数据库自增主键,可以使用SELECT LAST_INSERT_ID()
         -->
        <insert id="insertUser" parameterType="cn.itheima.pojo.User">
            <!-- 执行SELECT LAST_INSERT_ID()数据库函数,返回自增的主键
                keyProperty:将返回的主键放入传入的参数的Id中保存(保存到user对象中的id属性)
                order:当前函数相对于insert语句的执行顺序,在insert前执行用BEFORE,在insert后执行用AFTER
                resultType:id的类型,也就是keyProperty中属性类型
             -->
            <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                SELECT LAST_INSERT_ID()
            </selectKey>
            INSERT INTO user (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
        </insert>
        
        <delete id="deleteUserById" parameterType="java.lang.Integer">
            DELETE FROM user WHERE id=#{id}
        </delete>
        
        <update id="updateUserById" parameterType="cn.itheima.pojo.User">
            UPDATE user SET  username=#{username} WHERE id=#{id}
        </update>
    </mapper>

    2、配置User.xml映射信息

    在Sqlconfig.xml文件中引入User.xml

    <mappers>
            <mapper resource="User.xml"/>
    </mappers>

    3、编写DAO接口和实现类

    UserDAO.java

    package cn.itheima.dao;
    
    import java.util.List;
    
    import cn.itheima.pojo.User;
    
    public interface UserDAO {
    
        User findUserById(Integer id);
        
        List<User> findUserByUserName(String username);
    }

    UserDAOImpl.java

    package cn.itheima.dao;
    
    import java.util.List;
    
    import org.apache.ibatis.session.SqlSession;
    import org.apache.ibatis.session.SqlSessionFactory;
    
    import cn.itheima.pojo.User;
    
    public class UserDAOImpl implements UserDAO {
    
        private SqlSessionFactory sqlSessionFactory;
        // 通过构造方法注入
        public UserDAOImpl(SqlSessionFactory sqlSessionFactory) {
            this.sqlSessionFactory = sqlSessionFactory;
        }
        @Override
        public User findUserById(Integer id) {
            // SqlSession是线程不安全的,所以最佳使用范围是方法里
            SqlSession session = sqlSessionFactory.openSession();
            User user = session.selectOne("test.findUserById", id);
            return user;
        }
        @Override
        public List<User> findUserByUserName(String username) {
            SqlSession session = sqlSessionFactory.openSession();
            List<User> userList = session.selectList("test.findUserByUserName", username);
            return userList;
        }
    }

    4、测试

    package mybatis0523;
    
    import java.io.InputStream;
    import java.util.List;
    
    import org.apache.ibatis.io.Resources;
    import org.apache.ibatis.session.SqlSessionFactory;
    import org.apache.ibatis.session.SqlSessionFactoryBuilder;
    import org.junit.Before;
    import org.junit.Test;
    
    import cn.itheima.dao.UserDAO;
    import cn.itheima.dao.UserDAOImpl;
    import cn.itheima.pojo.User;
    
    public class UserDAOTest {
    
        private SqlSessionFactory sqlSessionFactory;
        
        // 在测试方法前执行的方法
        @Before
        public void setUp() throws Exception {
            String resource = "sqlMapConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
        
        @Test
        public void testFindUserById() throws Exception {
            // 将初始化好的sqlSessionFactory注入到实现类中
            UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
            User user = userDAO.findUserById(1);
            System.out.println(user);
        }
        
        @Test
        public void testFindUserByUserName() throws Exception {
            UserDAO userDAO = new UserDAOImpl(sqlSessionFactory);
            List<User> userList = userDAO.findUserByUserName("王");
            System.out.println(userList);
        }
    }

    二、Mapper代理方式开发

    1、实现原理

    Mapper接口开发方法只需要编写Mapper接口(实际上相当于DAO接口)然后由Mybatis根据接口定义创建接口的动态代理对象。换句话说也就是不用自己编写DAO接口的实现类了。

    2、Map接口编写规则

    (1)映射文件中的namespace要等于接口的全路径
    (2)映射文件中的sql语句id要等于接口的方法名称
    (3)映射文件中传入参数类型要等于接口方法中传入参数的类型
    (4)映射文件中返回结果集类型要等于接口方法的返回值类型

    3、编写Mapper接口(相当与传统的DAO接口)

    package cn.itheima.mapper;
    
    import java.util.List;
    
    import cn.itheima.pojo.User;
    
    public interface UserMapper {
        
        User findUserById(Integer id);
        
        List<User> findUserByUserName(String username);
        
        void insertUser(User user);
        
        void updateUserById(User user);
    }

    4、编写映射文件

    UserMapper.xml

    <?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接口代理实现编写规则:
        1、映射文件中的namespace要等于接口的全路径
        2、映射文件中的sql语句id要等于接口的方法名称
        3、映射文件中传入参数类型要等于接口方法中传入参数的类型
        4、映射文件中返回结果集类型要等于接口方法的返回值类型
     -->
    <mapper namespace="cn.itheima.mapper.UserMapper">
        <!-- 
        id:sql语句唯一标识
        parameterType:指定传入参数类型(pojo类中对应的类型,不是数据库中的类型)
        resultType:返回结果集类型
        #{}:占位符,如果传入的类型是基本类型(string,long,double,int,boolean,float等),那么#{}中变量名称可以任意
         -->
        <select id="findUserById" parameterType="java.lang.Integer" resultType="cn.itheima.pojo.User">
            SELECT * FROM user WHERE id=#{id}
        </select>
        
        <!-- 
        如果返回的结果为集合,resultType中也是配置为集合中泛型的类型,即resultType="cn.itheima.pojo.User"
        ${}:拼接符,如果传入的类型是基本类型(string,long,double,int,boolean,float等),那么${}中变量名称必须是value
         -->
        <select id="findUserByUserName" parameterType="java.lang.String" resultType="cn.itheima.pojo.User">
            SELECT * FROM user WHERE username LIKE '%${value}%'
        </select>
        
        <!-- 
        如果传入的是pojo类型,则#{}中变量名称必须是pojo中对应的属性.属性.属性......
        如果要返回数据库自增主键,可以使用SELECT LAST_INSERT_ID()
         -->
        <insert id="insertUser" parameterType="cn.itheima.pojo.User">
            <!-- 执行SELECT LAST_INSERT_ID()数据库函数,返回自增的主键
                keyProperty:将返回的主键放入传入的参数的Id中保存(保存到user对象中的id属性)
                order:当前函数相对于insert语句的执行顺序,在insert前执行用BEFORE,在insert后执行用AFTER
                resultType:id的类型,也就是keyProperty中属性类型
             -->
            <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
                SELECT LAST_INSERT_ID()
            </selectKey>
            INSERT INTO user (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address})
        </insert>
        
        <delete id="deleteUserById" parameterType="java.lang.Integer">
            DELETE FROM user WHERE id=#{id}
        </delete>
        
        <update id="updateUserById" parameterType="cn.itheima.pojo.User">
            UPDATE user SET  username=#{username} WHERE id=#{id}
        </update>
    </mapper>

    5、配置UserMapper.xml映射信息

    在SqlConfig.xml中引入

    <mappers>
            <!-- 
            使用class属性引入接口的全路径名称:
            使用规则:
                1、接口的名称和映射文件名称要完全一致
                2、接口和映射文件要放在同一个目录下
             -->
            <mapper class="cn.itheima.mapper.UserMapper"/>
        </mappers>

    6、测试

    package mybatis0523;
    
    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 cn.itheima.mapper.UserMapper;
    import cn.itheima.pojo.User;
    
    public class UserMapperTest {
    
        private SqlSessionFactory sqlSessionFactory;
        
        // 在测试方法前执行的方法
        @Before
        public void setUp() throws Exception {
            String resource = "sqlMapConfig.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        }
        
        @Test
        public void testFindUserById() throws Exception {
            SqlSession session = sqlSessionFactory.openSession();
            UserMapper userMapper = session.getMapper(UserMapper.class);
            User user = userMapper.findUserById(1);
            System.out.println(user);
        }
        
        @Test
        public void testFindUserByUserName() throws Exception {
            SqlSession session = sqlSessionFactory.openSession();
            UserMapper userMapper = session.getMapper(UserMapper.class);
            List<User> userList = userMapper.findUserByUserName("王");
            System.out.println(userList);
        }
        
    }

    三、总结

    原始DAO开发存在一些问题:

    1、存在一定量的模板代码。比如:通过SqlSessionFactory创建SqlSession;调用SqlSession的方法操作数据库;关闭Sqlsession。

    2、存在一些硬编码。调用SqlSession的方法操作数据库时,需要指定statement的id,这里存在了硬编码。

    Mapper代理的开发方式,只需要编写mapper接口(相当于dao接口)即可。Mybatis会自动的为mapper接口生成动态代理实现类。

    要实现mapper代理的开发方式,需要遵循一些开发规范:

    1、mapper接口的全限定名要和mapper映射文件的namespace的值相同。

    2、mapper接口的方法名称要和mapper映射文件中的statement的id相同。

    3、mapper接口的方法参数只能有一个,且类型要和mapper映射文件中statement的parameterType的值保持一致。

    4、  mapper接口的返回值类型要和mapper映射文件中statement的resultType值或resultMap中的type值保持一致。

    通过规范式的开发mapper接口,可以解决原始dao开发当中存在的问题:

    1、 模板代码已经去掉。

    2、 剩下去不掉的操作数据库的代码,其实就是一行代码。这行代码中硬编码的部分,通过第一和第二个规范就可以解决。

  • 相关阅读:
    随笔和文章的区别
    02. 什么是 SOA?
    GOF 23种设计模式(Patterns in Java)
    ASP.NET MVC: how to include <span> in link from Html.ActionLink?
    Head First 02.观察者模式(Observer)
    ActionResult types in MVC2
    探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探
    Head First 01.策略模式(Strategy Pattern)
    SOA实施:不能忽略商业价值
    nmon analyser——生成 AIX 性能报告的免费工具
  • 原文地址:https://www.cnblogs.com/binaway/p/9150047.html
Copyright © 2020-2023  润新知