Mybatis学习记录(二)--Mybatis开发DAO方式

mybatis开发dao的方法通常用两种,一种是传统DAO的方法,一种是基于mapper代理的方法,下面学习这两种开发模式.



写dao之前应该要对SqlSession有一个更加细致的了解

一.mybatis的SqlSession使用范围

  1. SqlSessionFactoryBuilder用于创建SqlSessionFacoty,SqlSessionFacoty一旦创建完成就不需要SqlSessionFactoryBuilder了,因为SqlSession是通过SqlSessionFactory生产,所以可以将SqlSessionFactoryBuilder当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。
  2. SqlSessionFactory是一个接口,接口中定义了openSession的不同重载方法,SqlSessionFactory的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理SqlSessionFactory。
  3. SqlSession中封装了对数据库的操作,如:查询、插入、更新、删除等。通过SqlSessionFactory创建SqlSession,而SqlSessionFactory是通过SqlSessionFactoryBuilder进行创建。
  4. SqlSession是一个面向用户的接口,sqlSession中定义了数据库操作,默认使用DefaultSqlSession实现类。

    具体执行过程如下:

    • 加载数据源等配置信息Environment environment = configuration.getEnvironment();
    • 创建数据库链接
    • 创建事务对象创建Executor,SqlSession所有操作都是通过Executor完成

      对应源码:

if (ExecutorType.BATCH == executorType) {
      executor = newBatchExecutor(this, transaction);
    } elseif (ExecutorType.REUSE == executorType) {
      executor = new ReuseExecutor(this, transaction);
    } else {
      executor = new SimpleExecutor(this, transaction);
    }
if (cacheEnabled) {
      executor = new CachingExecutor(executor, autoCommit);
    }

结论得出

每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它也是线程不安全的。因此最佳的范围是请求或方法范围。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。

打开一个 SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

二.传统DAO开发方法

传统的方法是建立dao接口定义方法,然后创建其实现类,实现dao中的方法.下面代码用的还是第一篇的例子

无论是哪种开发方法,mapper.xml都要写的,mapper映射也都需要在SqlMapperConfig.xml中配置的

1.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">
<!--命名空间,用于隔离sql语句,后面会讲另一层非常重要的作用。-->
<mapper namespace="test">
    <!--根据id查询出用户信息(查询一条数据)-->
    <select id="findUserById" parameterType="int" resultType="com.aust.model.User">
        SELECT * FROM user WHERE id=#{id}
    </select>
    <!--根据名称进行模糊查询(查询出多条数据)-->
    <select id="findUserByName" parameterType="java.lang.String" resultType="com.aust.model.User">
        SELECT * from user WHERE nickname LIKE ‘%${value}%‘
    </select>
    <!--插入一个用户-->
    <insert id="insertUser" parameterType="com.aust.model.User">
      <selectKey keyProperty="id" resultType="java.lang.Integer" order="AFTER" >
          SELECT last_insert_id()
      </selectKey>
        INSERT INTO user(username,password,nickname,status) VALUE (#{username},#{password},#{nickname},#{status})
    </insert>
    <!--删除一个用户-->
    <delete id="deleteUser" parameterType="int">
      DELETE FROM user WHERE id =#{id}
    </delete>
    <!--更新用户-->
    <update id="updateUser" parameterType="com.aust.model.User">
      UPDATE user SET username=#{username},password=#{password},nickname=#{nickname} WHERE id = #{id}
    </update>
</mapper>

2.配置mapper映射

在SqlMapperConfig,xml中配置即可

  <!--配置mappeer映射-->
    <mappers>
        <mapper resource="mapper/User.xml"/>
    </mappers>

3.实现dao接口

public interface UserDao {
    //根据id查询用户
    public User findUserById(int id);
    //根据姓名模糊查询用户
    public List<User> findUserByName(String name);
    //插入一个用户,返回主键
    public int insertUser(User user);
    //删除一个用户
    public boolean deleteUser(int id);
    //更新一个用户
    public boolean updateUser(User user);
}

4.实现dao接口的实现类

public class UserDaoImp implements UserDao{
    private SqlSessionFactory factory;

    //通过构造注入SqlSessionFactory,后期整合spring,全部交给spring管理
    public UserDaoImp(SqlSessionFactory factory) {
        this.factory = factory;
    }

    @Override
    public User findUserById(int id) {
        //放在方法体内创建,保证线程安全
        SqlSession session = factory.openSession();
        User user = session.selectOne("test.findUserById",id);
        session.close();
        return user;
    }

    @Override
    public List<User> findUserByName(String name) {
        //放在方法体内创建,保证线程安全
        SqlSession session = factory.openSession();
        List<User> users = session.selectList("test.findUserByName",name);
        session.close();
        return users;
    }

    @Override
    public int insertUser(User user) {
        //放在方法体内创建,保证线程安全
        SqlSession session = factory.openSession();
        session.insert("test.insertUser",user);
        //一定要提交,不然是失败
        session.commit();
        session.close();
        return user.getId();
    }

    @Override
    public boolean deleteUser(int id) {
        //放在方法体内创建,保证线程安全
        SqlSession session = factory.openSession();
        int i = session.delete("test.deleteUser",id);
        //一定要提交,不然是失败
        session.commit();
        session.close();
        return i>0;
    }

    @Override
    public boolean updateUser(User user) {
        //放在方法体内创建,保证线程安全
        SqlSession session = factory.openSession();
        int i = session.delete("test.updateUser",user);
        //一定要提交,不然是失败
        session.commit();
        session.close();
        return i>0;
    }
}

5.写junit测试

    SqlSessionFactory factory  = null;

    @Before
    public void init(){
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("SqlMapperConfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        factory = new SqlSessionFactoryBuilder().build(is);
    }

    //测试取出单个
    @Test
    public void findUserByIdTest(){
        UserDaoImp daoImp = new UserDaoImp(factory);
        User user = daoImp.findUserById(2);
        System.out.println(user);
    }

    //测试取出多个
    @Test
    public void findUserByNameTest(){
        UserDaoImp daoImp = new UserDaoImp(factory);
        List<User> users = daoImp.findUserByName("张");
        System.out.println(users);
    }

    //测试插入数据
    @Test
    public void insertUserTest(){
        UserDaoImp daoImp = new UserDaoImp(factory);
        User u = new User();
        u.setUsername("niuli1");
        u.setPassword("123456");
        u.setNickname("牛李");
        u.setStatus(2);
        int index = daoImp.insertUser(u);
        System.out.println(index);

    }

以上五步就是传统DAO开发方法

6.原始DAO开发方法存在的问题

  1. Dao方法体存在重复代码:通过SqlSessionFactory创建SqlSession,调用SqlSession的数据库操作方法
  2. 调用sqlSession的数据库操作方法需要指定statement的id,这里存在硬编码,不得于开发维护。

二.基于Mapper代理接口

1.实现原理

Mapper接口开发方法只需要程序员编写Mapper接口(相当于Dao接口),由Mybatis框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法。换句话说也就是不用程序员自己编写DAO接口的实现类了

2.UserMapper接口

接口定义有如下特点:

1、Mapper接口方法名和Mapper.xml中定义的statement的id相同

2、Mapper接口方法的输入参数类型和mapper.xml中定义的statement的parameterType的类型相同

3、Mapper接口方法的输出参数类型和mapper.xml中定义的statement的resultType的类型相同

public interface UserMapper {

    //根据id查询用户
    public User findUserById(int id);
    //根据姓名模糊查询用户
    public List<User> findUserByName(String name);
    //插入一个用户,返回受影响的行数
    public int insertUser(User user);
    //删除一个用户,返回受影响的行数
    public int deleteUser(int id);
    //更新一个用户,返回受影响的行数
    public int updateUser(User user);
}

3.UserMapper.xml

Mapper接口开发需要遵循以下规范:

1、Mapper.xml文件中的namespace与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">
<!--命名空间,基于Mapper代理的话要是Mapper代理类路径。-->
<mapper namespace="com.aust.dao.UserMapper">

    <!--其余内容和上面的User.xml一样-->

</mapper>

4.配置Mapper映射

无论哪种方式都需要配置映射

  <!--配置mappeer映射-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>

5.写junit测试

  @Before
    public void init(){
        InputStream is = null;
        try {
            is = Resources.getResourceAsStream("SqlMapperConfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        factory = new SqlSessionFactoryBuilder().build(is);
    }

    //测试取出单个
    @Test
    public void findUserByIdTest(){
        //获取sqlsession
        SqlSession session = factory.openSession();
        //创建mapper代理
        UserMapper mapper = session.getMapper(UserMapper.class);
        //利用mapper代理查询
        User u = mapper.findUserById(2);
        session.close();
        System.out.println(u);
    }

    //测试取出多个
    @Test
    public void findUserByNameTest(){
        SqlSession session = factory.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> users = mapper.findUserByName("张");
        session.close();
        System.out.println(users);
    }

    //测试插入数据
    @Test
    public void insertUserTest(){
        SqlSession session = factory.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        User u = new User();
        u.setUsername("niuli1");
        u.setPassword("123456");
        u.setNickname("牛李");
        u.setStatus(2);
        int index = mapper.insertUser(u);
        System.out.println(index);//获取受影响的行数
        System.out.println(u.getId());//获取返回的自增主键

    }

6.总结

  1. selectOne和selectList动态代理对象调用sqlSession.selectOne()和sqlSession.selectList()是根据mapper接口方法的返回值决定,如果返回list则调用selectList方法,如果返回单个对象则调用selectOne方法。
  2. mybatis官方推荐使用mapper代理方法开发mapper接口,程序员不用编写mapper接口实现类
  3. 可以发现使用Mapper代理的方式,在Mapper接口中输入参数必须只能是一个,但是怎么才能满足多样查询呢?mybatis建议输入参数可以使用pojo包装对象或map对象,保证dao的通用性.
时间: 2024-11-14 06:33:51

Mybatis学习记录(二)--Mybatis开发DAO方式的相关文章

MyBatis 学习记录5 MyBatis的二级缓存

主题 之前学习了一下MyBatis的一级缓存,主要涉及到BaseExecutor这个类. 现在准备学习记录下MyBatis二级缓存. 配置二级缓存与初始化发生的事情 首先二级缓存默认是不开启的,需要自己配置开启. 如上图,需要在configuration里去开启. 其次在需要用到二级缓存的Mapper的配置里做一些操作,如下图,增加一个cache节点 至此就可以在UserMapper上开启二级缓存了. 当MaBatis初始化的时候,需要解析各种XML配置来生成SQLSessionFactory,

Mybatis学习记录(三)--Mybatis配置文件详解

关于mybatis的配置文件,主要有两个,一个是SqlMapperConfig.xml文件一个是mapper.xml文件,分别对这两个进行深入全面学习. 一.SqlMapperConfig.xml文件 1.标签概况 在SqlMapperConfig.xml中主要有以下标签,其中环境集合environments和spring整合后废除不用.objectFactory和plugins不经常使用. properties(属性) settings(全局配置参数) typeAliases(类型别名) ty

MyBatis学习笔记二:MyBatis生产中使用环境搭建

这里是在上一个环境的基础上修改的,这里就不在给出所有的配置,只给出哪里修改的配置 1.修改POJO对象为注解方式 2.创建Dao层接口 package com.orange.dao; import com.orange.model.Person; public interface PersonDao { // 这里的返回值和方法名必须和PersonMapper.xml中定义的执行语句的id一致 public Person selectPerson(); } 3.修改PersonMapper.xm

mybatis学习笔记二mybatis结合spring mvc实现(用户登录,数据查询)

接着上次的来,我做了一个用户登录的例子 UserController: package com.yihaomen.controller; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.spring

MyBatis学习总结(二)——使用MyBatis对表执行CRUD操作(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(二)--使用MyBatis对表执行CRUD操作 上一篇博文MyBatis学习总结(一)--MyBatis快速入门中我们讲了如何使用Mybatis查询users表中的数据,算是对MyBatis有一个初步的入门了,今天讲解一下如何使用MyBatis对users表执行CRUD操作.本文中使用到的测试环境是上一篇博文中的测试环境. 一.使用MyBatis对表执行CRUD操作--基于XML的实现 1.定义sql映射xml文件 userMa

MyBatis学习总结(一)——MyBatis快速入门(转载)

孤傲苍狼 只为成功找方法,不为失败找借口! MyBatis学习总结(一)--MyBatis快速入门 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 二.mybatis快速入门 2.1.准备

【转】MyBatis学习总结(一)——MyBatis快速入门

[转]MyBatis学习总结(一)——MyBatis快速入门 一.Mybatis介绍 MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架.MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录. 二.mybatis快速入门 2.1.准备开发环境 1.创建测试项目,普通jav

mybatis学习笔记(14)-mybatis整合ehcache

mybatis学习笔记(14)-mybatis整合ehcache mybatis学习笔记14-mybatis整合ehcache 分布缓存 整合方法掌握 整合ehcache 加入ehcache的配置文件 ehcache是一个分布式缓存框架 分布缓存 我们系统为了提高系统并发,性能.一般对系统进行分布式部署(集群部署方式) 不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发.所以要使用分布式缓存对缓存数据进行集中管理. mybatis无法实现分布式缓存,需要和其它分布式缓存框架进行整合.

Spring Boot学习记录(二)--thymeleaf模板

Spring Boot学习记录(二)–thymeleaf模板 标签(空格分隔): spring-boot 自从来公司后都没用过jsp当界面渲染了,因为前后端分离不是很好,反而模板引擎用的比较多,thymeleaf最大的优势后缀为html,就是只需要浏览器就可以展现页面了,还有就是thymeleaf可以很好的和spring集成.下面开始学习. 1.引入依赖 maven中直接引入 <dependency> <groupId>org.springframework.boot</gr