【MyBatis】开发dao方法

本文介绍了如何通过MyBatis将原始DAO和DAO实现类的模板方法抽象,使用Mapper接口和XML映射文件,减少代码重复,并讨论了其在扩展性和维护性上的优势。还关注了Mapper接口参数限制和解决方案。
摘要由CSDN通过智能技术生成

1. SqlSession使用范围

  • SqlSessionFactoryBuilder

通过SqlSessionFactoryBuilder创建会话工厂SqlSessionFactorySqlSessionFactoryBuilder当成一个工具类使用即可,不需要使用单例管理SqlSessionFactoryBuilder。在需要创建SqlSessionFactory时候,只需要new一次SqlSessionFactoryBuilder即可。

  • SqlSessionFactory

通过SqlSessionFactory创建SqlSession,使用单例模式管理sqlSessionFactory(工厂一旦创建,使用一个实例)。将来mybatis和spring整合后,使用单例模式管理sqlSessionFactory

  • SqlSession

SqlSession是一个面向用户(程序员)的接口。SqlSession中提供了很多操作数据库的方法:如:selectOne(返回单个对象)、selectList(返回单个或多个对象)。

SqlSession是线程不安全的,在SqlSesion实现类中除了有接口中的方法(操作数据库的方法)还有数据域属性。

SqlSession最佳应用场合在方法体内,定义成局部变量使用。

2. 原始dao方法

2.1 UserDao.java

package cn.edu.wtu.dao;

import cn.edu.wtu.po.User;

/**
 * @Package cn.edu.wtu.dao
 * @InterfaceName UserDao
 * @Description TODO
 * @Date 19/11/3 13:48
 * @Author LIM
 * @Version V1.0
 */
public interface UserDAO {
    /**
     * dao原始开发
     * 根据id查询用户信息
     * @param id
     * @return
     * @throws Exception
     */
    public User findUserById(int id) throws Exception;

    /**
     * 添加用户
     * @param user
     * @throws Exception
     */
    public void insertUser(User user) throws Exception;

    /**
     * 删除用户
     * @param id
     * @throws Exception
     */
    public void deleteUser(int id) throws Exception;
}

2.2 UserDaoImpl.java

package cn.edu.wtu.dao;

import cn.edu.wtu.po.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

/**
 * @Package cn.edu.wtu.dao
 * @ClassName UserDAOImpl
 * @Description TODO
 * @Date 19/11/3 13:48
 * @Author LIM
 * @Version V1.0
 */
public class UserDAOImpl<id> implements UserDAO {
  /** 原生态的dao
   * 需要向dao实现类里注入SqlSessionFactory
   * 通过构造方法
   */
  private SqlSessionFactory sqlSessionFactory;

  public UserDAOImpl(SqlSessionFactory sqlSessionFactory) {
    this.sqlSessionFactory = sqlSessionFactory;
  }

  @Override
  public User findUserById(int id) throws Exception {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user = sqlSession.selectOne("test.findUserById", id);
    // 关闭
    sqlSession.close();
    return user;
  }

  @Override
  public void insertUser(User user) throws Exception {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    sqlSession.insert("test.insertUser", user);
    // 提交
    sqlSession.commit();
    // 关闭
    sqlSession.close();
  }

  @Override
  public void deleteUser(int id) throws Exception {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    sqlSession.insert("test.deleteUser", id);
    sqlSession.commit();
    sqlSession.close();
  }
}

2.3 UserDaoImplTest.java

package cn.edu.wtu.dao;

import cn.edu.wtu.po.User;
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 java.io.IOException;
import java.io.InputStream;
import java.util.Date;

public class UserDAOImplTest {
  private SqlSessionFactory sqlSessionFactory;

  @Before
  public void setUp() throws IOException {
    InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
    // 创建会话工厂
    sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
  }

  @Test
  public void testFindUserById() throws Exception {
    User user = new UserDAOImpl<>(sqlSessionFactory).findUserById(1);
    System.out.println(user.toString());
  }

  @Test
  public void testInsertUser() throws Exception {
    User user = new User();
    user.setId(100);
    user.setUsername("张宇");
    user.setSex("2");
    user.setBirthday(new Date());
    user.setAddress("襄阳");
    new UserDAOImpl<>(sqlSessionFactory).insertUser(user);
  }

  @Test
  public void testDeleteUser() throws Exception {
    new UserDAOImpl<>(sqlSessionFactory).deleteUser(25);
  }
}

3. Mybatis的mapper接口(相当于dao接口)代理开发方法

3.1 UserMapper.java

package cn.edu.wtu.mapper;

import cn.edu.wtu.po.User;

import java.util.List;

/**
 * @Package cn.edu.wtu.mapper
 * @InterfaceName UserMapper
 * @Description TODO
 * @Date 19/11/3 13:51
 * @Author LIM
 * @Version V1.0
 */
public interface UserMapper {
  /** mapper代理开发和dao开发对比 mapper接口,相当于dao接口,
   * mybatis可以自动生成mapper接口实现类的代理对象
   */

    /**
     * 根据id查询用户信息
     * @param id
     * @return
     * @throws Exception
     */
  public User findUserById(int id) throws Exception;

    /**
     * 根据用户名查询用户列表
     * @param name
     * @return
     * @throws Exception
     */
  public List<User> findUserByName(String name) throws Exception;

    /**
     * 添加用户
     * @param user
     * @throws Exception
     */
    public void insertUser(User user) throws Exception;

    /**
     * 删除用户
     * @param id
     * @throws Exception
     */
    public void deleteUser(int id) throws Exception;

    /**
     * 更新用户
     * @param user
     * @throws Exception
     */
    public void updateUser(User user) throws Exception;
}

3.2 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 namespace="cn.edu.wtu.mapper.UserMapper">

    <select id="findUserById" parameterType="int" resultType="cn.edu.wtu.po.User">
        select * from user where id=#{VALUE}
    </select>

    <select id="findUserByName" parameterType="java.lang.String" resultType="cn.edu.wtu.po.User">
        select * from user WHERE username LIKE '%${value}%'
    </select>

    <insert id="insertUser" parameterType="cn.edu.wtu.po.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            SELECT LAST_INSERT_ID()
        </selectKey>
        insert into user(username,birthday,sex,address) value(#{username},#{birthday},#{sex},#{address})
    </insert>

    <delete id="deleteUser" parameterType="cn.edu.wtu.po.User">
        delete from user where id = #{id}
    </delete>

    <update id="updateUser" parameterType="cn.edu.wtu.po.User">
        UPDATE user set username=#{username},birthday=#{birthday},sex=#{sex},address=#{address} where id=#{id}
    </update>
</mapper>

3.3 在测试之前需要在SqlMapConfig.xml中加载mapper.xml这个映射文件

在这里插入图片描述

3.4 UserMapperTest.java

package cn.edu.wtu.mapper;

import cn.edu.wtu.po.User;
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 java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @Package cn.edu.wtu.mapper
 * @ClassName UserMapperTest
 * @Description TODO
 * @Date 19/11/3 13:51
 * @Author LIM
 * @Version V1.0
 */
public class UserMapperTest {
    /**
     * mapper测试
     */
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void setUp() throws Exception {
        // 得到配置文件
        InputStream is = Resources.getResourceAsStream("SqlMapConfig.xml");
        // 创建会话工厂
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    }

    @Test
    public void testFindUserById() throws Exception {
        // 创建会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 创建UserMapper对象,mybatis自动调用
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = userMapper.findUserById(1);
        System.out.println(user.toString());
    }

    @Test
    public void testFindUserByName() throws Exception {
        // 创建会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 创建UserMapper对象,mybatis自动调用
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = userMapper.findUserByName("小明");
        System.out.println(list.toString());
    }

    @Test
    public void testInsertUser() throws Exception {
        // 创建会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 创建UserMapper对象,mybatis自动调用
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setUsername("张思");
        user.setSex("1");
        user.setBirthday(new Date());
        user.setAddress("武汉江夏区");
        userMapper.insertUser(user);
    }

    @Test
    public void testDeleteUser() throws Exception{
        // 创建会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 创建UserMapper对象,mybatis自动调用
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);

        userMapper.deleteUser(28);
    }

    @Test
    public void testUpdateUser() throws Exception{
        // 创建会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        // 创建UserMapper对象,mybatis自动调用
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        User user = new User();
        user.setUsername("张于");
        user.setSex("1");
        user.setBirthday(new Date());
        user.setAddress("武汉江夏区");
        userMapper.insertUser(user);
        userMapper.updateUser(user);
    }
}

4. 总结

4.1 原始dao开发问题

1.dao接口实现类方法中存在大量模板方法,设想能否将这些代码提取出来,大大减轻程序员的工作量。

2.调用sqlsession方法时将statement的id硬编码了

3.调用sqlsession方法时传入的变量,由于sqlsession方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

4.2 mapper开发

  • 只需要编写两个文件,mapper.java,mapper.xml。即可,不需要类来继承它

  • mapper开发只需要遵守几个规范即可

    • 在mapper.xml中namespace等于mapper接口地址
      在这里插入图片描述

    • mapper.java接口中的方法名和mapper.xml中statement的id一致
      在这里插入图片描述

    在这里插入图片描述

    • mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。
      在这里插入图片描述

    在这里插入图片描述

    • mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。

      在这里插入图片描述

      在这里插入图片描述

  • 其实,以上开发规范主要是对下边的代码进行统一生成:

      User user = sqlSession.selectOne("test.findUserById", id);
      sqlSession.insert("test.insertUser", user);
      ......
    

5. 一些问题总结

  • 代理对象内部调用selectOneselectList

    • 如果mapper方法返回单个pojo对象(非集合对象),代理对象内部通过selectOne查询数据库。
    • 如果mapper方法返回集合对象,代理对象内部通过selectList查询数据库。
  • mapper接口方法参数只能有一个是否影响系统开发

mapper接口方法参数只能有一个,系统是否不利于扩展维护?系统框架中,dao层的代码是被业务层公用的。即使mapper接口只有一个参数,可以使用包装类型的pojo满足不同的业务方法的需求。

注意:持久层方法的参数可以包装类型、map…等,service方法中建议不要使用包装类型(不利于业务层的可扩展)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮·建哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值