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中究竟有多少对象,这样不利于业务层的可扩展。

<think>首先,用户的问题是如何将基于DAO模式的代码(如JDBC实现)转换为使用MyBatisMapper接口的形式。我需要参考系统指令和用户提供的引用内容。系统指令要求:-行内数学表达式用$...$(但在这个上下文中,可能不涉及数学公式,所以要小心)。-独立公式用$$...$$(同样,不太相关)。-LaTeX语法正确(在回答中确保代码块格式正确)。-使用中文回答。-生成相关问题。-在引用的段落末尾添加引用标识。用户提供的引用:-[^1]:讨论MyBatis与Spring的整合,传统DAO方式vs.Mapper接口方式。传统方式有重复代码和id正确性问题。-[^2]:提到MyBatis开发方式:原始DAO开发方法和Mapper接口代理开发方法。-[^3]:强调MyBatis消除JDBC代码,用XML或Annotations配置。-[^4]:配置文件示例,设置生成实体类、DAOMapper等的东西。用户的上一次问题是关于将DAO转换为Mapper接口的方式。我的回答需要:1.结构清晰,逐步解决问题。2.保证真实可靠。3.在回答末尾生成相关问题。4.添加引用标识到引用的内容末尾。回答结构:-先理解问题:将基于JDBC的DAO转换为MyBatisMapper接口。-参考引用,Mapper接口方式可以减少重复代码和避免id错误。-步骤应该是:-1.定义Mapper接口。-2.创建对应的XML映射文件或使用注解。-3.配置MyBatis来识别Mapper接口。-4.使用Mapper接口而不是具体DAO实现类。参考引用中的关键点:-[^1]提到使用Mapper接口可以避免重复代码和id错误。-[^2]区分了原始DAO开发Mapper代理开发-[^3]说明MyBatis使用XML或Annotations。-[^4]显示配置文件示例。在我的回答中:-使用中文。-添加引用:当提到减少代码重复时,可以引用[^1]。-代码示例:类似系统指令中的示例,用代码块展示代码。生成相关问题:在末尾添加§§相关问题§§部分。大纲回答:1.**介绍转换的好处**:基于引用[^1],说明Mapper接口的优势。2.**步骤**:-步骤1:定义Mapper接口。-解释:定义一个接口包含数据库操作方法。-示例代码。-步骤2:实现映射(XML或注解)。-使用XML映射文件定义SQL语句。-使用注解在接口上定义。-示例代码。-步骤3:配置MyBatis整合。-在Spring或纯MyBatis中配置Mapper扫描。-参考引用[^4]的配置片段。-步骤4:使用Mapper接口。-在service层直接注入Mapper接口。3.**关键点注意事项**:-确保映射正确。-避免JDBC代码。4.**结论**:总结好处。5.**引用添加**:在描述内容末尾加[^n]。6.**相关问题生成**。相关问题:-类似于示例,生成2-3个相关问题:-1.如何测试MyBatisMapper接口?-2.在Spring中如何更好地整合MyBatisMapper-3.Mapper接口与传统DAO的性能比较?确保回答真实可靠:基于MyBatis文档和通用实践。</think> ### 如何将基于DAO模式的代码(如JDBC实现)转换为使用MyBatis Mapper接口的形式 将传统的JDBC DAO实现转换为MyBatis Mapper接口形式,可以显著减少代码重复、提升开发效率和类型安全性。这种转换避免了直接在代码中硬编码SQL语句ID,消除了运行时可能出现的错误。参考引用[^1],传统DAO方式需要在实现类中编写大量重复逻辑(如设置参数和映射结果集),而Mapper接口通过代理机制自动处理这些操作。转换步骤如下,我将逐步解释并给出代码示例(使用Java和MyBatis框架)。每一步都基于MyBatis最佳实践,确保可靠迁移。 #### 步骤1: 定义Mapper接口 Mapper接口代替了传统的DAO接口和实现类。定义一个Java接口,方法签名对应数据库操作(如select、insert),无需手动实现这些方法——MyBatis通过动态代理自动生成实现。接口方法名对应映射文件中的SQL语句ID,这减少了ID错误的可能。参考引用[^2],Mapper接口编程方式是MyBatis推荐的代理开发方法。 - **示例代码**(定义一个用户相关的Mapper接口): ```java public interface UserMapper { // 查询用户信息,无需编写实现类 User selectUserById(int id); // 插入用户信息 void insertUser(User user); } ``` - **关键点**: - 方法名如`selectUserById`应与后续的SQL映射ID匹配。 - 不再需要手动实现JDBC的`Connection`、`PreparedStatement`等逻辑,这提升了代码简洁性[^1][^3]。 #### 步骤2: 创建SQL映射文件或使用注解 在MyBatis中,SQL语句定义在XML映射文件或通过注解方式(如`@Select`)添加到接口上。传统JDBC的SQL代码需迁移到此,由MyBatis处理参数设置和结果映射,减少手动JDBC代码。参考引用[^3],MyBatis支持XML或注解配置,简化数据库操作。 - **XML映射方式示例**(在`UserMapper.xml`中定义SQL): ```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 namespace="com.example.mapper.UserMapper"> <!-- SQL语句定义,namespace对应Mapper接口全路径 --> <select id="selectUserById" resultType="com.example.model.User"> SELECT * FROM users WHERE id = #{id} </select> <insert id="insertUser" parameterType="com.example.model.User"> INSERT INTO users (name, email) VALUES (#{name}, #{email}) </insert> </mapper> ``` - **注解方式示例**(直接在接口上添加注解): ```java public interface UserMapper { @Select("SELECT * FROM users WHERE id = #{id}") User selectUserById(int id); @Insert("INSERT INTO users (name, email) VALUES (#{name}, #{email})") void insertUser(User user); } ``` - **关键点**: - XML文件中的`namespace`必须精确匹配Mapper接口的全限定名。 - 使用`#{param}`占位符自动处理参数绑定,避免了JDBC的`setInt()`或`setString()`重复代码[^1][^3]。 - 注解方式更简洁,但复杂SQL建议用XML,支持动态SQL(如`<if>`标签)[^2]。 #### 步骤3: 配置MyBatis以扫描Mapper接口 在应用中配置MyBatis来加载Mapper接口和映射文件。如果使用Spring框架,需通过配置文件定义`SqlSessionFactoryBean`和`MapperScannerConfigurer`。参考引用[^4],配置文件可定义Mapper包的扫描路径,确保自动代理生成。 - **纯MyBatis配置示例**(在`mybatis-config.xml`中): ```xml <configuration> <mappers> <!-- 指定Mapper接口或XML文件 --> <mapper class="com.example.mapper.UserMapper"/> <!-- 或指定包扫描 --> <package name="com.example.mapper"/> </mappers> </configuration> ``` - **Spring整合配置示例**(在`applicationContext.xml`中): ```xml <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="mapperLocations" value="classpath*:mapper/*.xml" /> <!-- 映射文件路径 --> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.mapper" /> <!-- Mapper接口包路径 --> </bean> ``` - **关键点**: - `mapperLocations`属性指向SQL映射文件的路径,`basePackage`用于扫描Mapper接口。 - 此步骤替代了传统JDBC的`DataSource`手动初始化,由框架管理资源[^4][^3]。 - 参考引用[^4]配置文件的包名设置(如`daoPackage=mapper`),确保路径一致。 #### 步骤4: 在业务层使用Mapper接口 替换原来的DAO调用:在Service类中直接注入Mapper接口,而不是实例化DAO实现。MyBatis动态生成代理实例,方法调用自动执行SQL操作,提高了代码的可读性和维护性。参考引用[^1],这种方式确保了运行时安全,无需硬编码ID。 - **示例代码**(Service层注入Mapper): ```java @Service public class UserService { @Autowired private UserMapper userMapper; // 直接注入Mapper接口 public User getUserById(int id) { return userMapper.selectUserById(id); // 调用Mapper方法 } public void addUser(User user) { userMapper.insertUser(user); } } ``` - **关键点**: - 不再需要`UserDAOImpl`类,减少了冗余代码(如JDBC的try-catch块)。 - 接口调用时,MyBatis自动验证SQL语句ID,降低了运行时错误风险[^1][^2]。 - 测试时,可轻松mock接口,提升了可测性。 #### 转换注意事项 - **迁移过程**:从JDBC转换为Mapper接口时,逐步迁移表操作: 1. 优先转换简单CRUD方法(如查询、插入)。 2. 复杂事务处理(如涉及多个SQL)需在Service层管理事务(Spring的`@Transactional`)。 - **性能与安全**:Mapper接口优化了SQL预编译,提高性能;同时,MyBatis的占位符方式减少了SQL注入风险。 - **常见问题解决**: - 如果报错`Could not find statement`,检查映射文件ID是否与接口方法名一致。 - 参考引用[^3],结合XML或注解灵活处理高级映射(如关联查询)。 通过这种转换,代码量可减少50%以上,同时提升了维护性和可靠性。MyBatis通过其持久层框架优势,将开发者从JDBC细节中解放出来[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值