文档章节

MyBatis 由浅入深(实践篇)-2

HansenGuan
 HansenGuan
发布于 2017/09/07 17:42
字数 2207
阅读 7
收藏 1

MyBatis 开发 DAO(Data Access Object)

两种思路:

  • 原始 Dao 开发方法(分别编写 Dao 接口 和 接口实现类 DaoImpl)
  • 借助 MyBatis,使用 mapper 接口(相当于Dao 接口)代理开发

预期功能

使用 Dao接口 实现 单表 的 CRUD

示例程序

原始 Dao 开发

思路: 设计Dao 接口,在 Dao 实现类中注入 SqlsessionFactory 在方法体中通过 SqlsessionFactory 创建 Sqlsession 执行对应的 sql

1.设计Dao 接口

import cn.guan.mybatis.example2.User;

/**
 * User Dao 接口定义
 * @Created 2017/9/7.
 */
public interface UserDao {

    //根据id查询用户信息
    User findUserById(int id) throws Exception;

    //添加用户信息
    void addUser(User user) throws Exception;

    //删除用户信息
    void deleteUser(int id) throws Exception;

}

2.Dao 接口实现

import cn.guan.mybatis.example2.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

/**
 * User Dao 实现类
 * @Created 2017/9/7.
 */
public class UserDaoImpl implements UserDao{

    //需要在 Dao 实现类中注入 SqlsessionFactory
    //这里通过构造方法注入
    private SqlSessionFactory sqlSessionFactory;

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

    @Override
    public User findUserById(int id) throws Exception {
        //在方法体内通过 SqlsessionFactory 创建 Sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        User user = sqlSession.selectOne("test.findUserById", id);
        sqlSession.close();
        return user;
    }

    @Override
    public void addUser(User user) throws Exception {
        //在方法体内通过 SqlsessionFactory 创建 Sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //执行插入的操作
        sqlSession.insert("test.insetrUser", user);
        //提交事务
        sqlSession.commit();
        //释放资源
        sqlSession.close();
    }

    @Override
    public void deleteUser(int id) throws Exception {
        //在方法体内通过 SqlsessionFactory 创建 Sqlsession
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.delete("test.deleteUserById", id);
        //提交事务
        sqlSession.commit();
        sqlSession.close();
    }
}

3.功能测试

import cn.guan.mybatis.example2.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.InputStream;
import java.text.SimpleDateFormat;

/**
 * 原始 dao 测试
 * @Created 2017/9/7.
 */
public class UserDaoImplTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws Exception
    {
        //创建sqlSessionFactory
        //Mybatis 配置文件
        String resource = "mybatis-config.xml";
        //得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入Mybatis的配置文件信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() throws Exception
    {
        //创建UserDao的对象
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        //调用UserDao方法
        User user = userDao.findUserById(1);
        System.out.println(user);
    }

    @Test
    public void testAddUser(){
        //创建UserDao的对象
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        try {
            User user = new User();
            user.setUsername("赵六");
            //为了设置生日的日期输入
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd");
            user.setBirthday(sdf.parse("2005-01-12"));
            user.setSex("男");
            user.setAddress("湖南长沙");

            userDao.addUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testDeleteUser(){
        //创建UserDao的对象
        UserDao userDao = new UserDaoImpl(sqlSessionFactory);
        try {
            userDao.deleteUser(3);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

4.思考 原始Dao开发中存在一些问题,如下

  1. Dao方法体存在重复代码:通过 SqlSessionFactory 创建 SqlSession,调用 SqlSession 的数据库操作方法
  2. 调用 sqlSession 的数据库操作方法需要指定 statement 的id,这里存在硬编码,不得于开发维护
  3. 调用 sqlSession 的数据库操作方法时传入的变量,由于 sqlsession 方法使用泛型,即使变量类型传入错误,在编译阶段也不报错,不利于程序员开发。

使用 Mybatis 的 mapper 接口开发 Dao

思路: 编写 *mapper.xml 映射文件,设计 mapper 接口(相当于 Dao 接口),遵循 MyBatis mapper 接口开发规范,框架自动生成 mapper 接口类的代理对象,自动调用 *mapper.xml 中对应的 sql

mapper 接口开发规范:

  1. 在 *mapper.xml 中定义 namespace 等于 mapper 接口地址
  2. 在 mapper 接口(Dao 接口)中的方法名要与 *mapper.xml 中 statement 的 id 一致。
  3. 在 mapper 接口(Dao 接口)中的输入参数类型要与 *mapper.xml 中 parameterType 指定的参数类型一致。
  4. 在 mapper 接口(Dao 接口)中的返回值类型要与 *mapper.xml 中 resultType 指定的类型一致。

实现:
1.设计 mapper 接口

import cn.guan.mybatis.example2.User;

import java.util.List;

/**
 * User Mapper 接口定义
 * @Created 2017/9/7.
 */
public interface UserMapper {

    //根据id查询用户信息
    User findUserById(int id) throws Exception;

    //根据id查询用户信息
    List<User> findUserByUsername(String username) throws Exception;

    //添加用户信息
    void insertUser(User user) throws Exception;

    //删除用户信息
    void deleteUserById(int id) throws Exception;

}

2.编写 *mapper.xml 并添加到全局配置文件(mybatis-config.xml)中

user-mapper.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 进行分类化管理,用于隔离 sql 语句-->
<!--命名空间设置为 mapper 接口地址  -->
<mapper namespace="cn.guan.mybatis.example3.UserMapper">
    <!-- 根据id获取用户信息 -->
    <select id="findUserById" parameterType="int" resultType="cn.guan.mybatis.example2.User">
        select * from tb_user where id = #{id}
    </select>

    <select id="findUserByUsername" parameterType="java.lang.String" resultType="cn.guan.mybatis.example2.User">
        select * from tb_user where username like '%${value}%'
    </select>

    <!-- 添加用户 -->
    <insert id="insertUser" parameterType="cn.guan.mybatis.example2.User">
        <selectKey keyProperty="id" order="AFTER" resultType="java.lang.Integer">
            select LAST_INSERT_ID()
        </selectKey>
        insert into tb_user(username, birthday, sex, address)
        values(#{username}, #{birthday}, #{sex}, #{address})
    </insert>

    <!--删除用户-->
    <delete id="deleteUserById" parameterType="int">
        delete from tb_user where id = #{id}
    </delete>

    <!--根据id更新用户-->
    <update id="updateUserById" parameterType="cn.guan.mybatis.example2.User">
        update tb_user set username = #{username}, birthday = #{birthday}, sex = #{sex}, address = #{address} where id = #{id}
    </update>

</mapper>

user-mapper.xml 配置到全局配置 mybatis-config.xml 中,项目运行时加载 user-mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 和spring整合后 environments配置将废除-->
    <environments default="development">
        <environment id="development">
            <!-- 使用jdbc事务管理,事务由 Mybatis 控制-->
            <transactionManager type="JDBC" />
            <!-- 数据库连接池,由Mybatis管理,db_mybatis,Mysql用户名root,123456 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://localhost:3306/db_mybatis?characterEncoding=utf-8" />
                <property name="username" value="root" />
                <property name="password" value="123456" />
            </dataSource>
        </environment>
    </environments>

    <!--加载 mapper 文件 路径-->
    <mappers>
        <mapper resource="mapperDir2/user-mapper.xml" />
    </mappers>
</configuration>

3.功能测试

import cn.guan.mybatis.example2.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.text.SimpleDateFormat;
import java.util.List;

/**
 * 测试 MyBatis mapper 接口实现 Dao 
 * @Created 2017/9/7.
 */
public class UserMapperTest {

    private SqlSessionFactory sqlSessionFactory;

    @Before
    public void init() throws Exception
    {
        //创建sqlSessionFactory
        //Mybatis 配置文件
        String resource = "mybatis-config.xml";
        //得到配置文件流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //创建会话工厂,传入Mybatis的配置文件信息
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    @Test
    public void testFindUserById() throws Exception
    {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper的方法
        User user = userMapper.findUserById(4);
        System.out.println(user);
    }

    @Test
    public void testFindUserByUsername(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        //调用UserMapper的方法
        try {
            List<User> users = userMapper.findUserByUsername("赵");
            System.out.println(users == null ? "[null]":users.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testAddUser(){
        //设置 sqlSession 开启自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        try {
            User user = new User();
            user.setUsername("赵六一");
            //为了设置生日的日期输入
            SimpleDateFormat sdf = new SimpleDateFormat ("yyyy-MM-dd");
            user.setBirthday(sdf.parse("2001-01-12"));
            user.setSex("男");
            user.setAddress("湖南岳阳");

            userMapper.insertUser(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testDeleteUser(){
        //设置 sqlSession 开启自动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //创建usermapper对象,mybatis自动生成代理对象
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        try {
            userMapper.deleteUserById(7);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

4.思考

mapper 解决的问题: 遵循 mapper 接口开发规范,就会由 MyBatis 对 SqlSession 接口方法的调用进行统一生成

sqlSession.selectOne()
sqlSession.selectList()
sqlSession.insert()
sqlSession.delete()
sqlSession.update()
···

5.注意事项

mapper 接口方法参数只能有一个

MyBatis sql 执行过程分析

面向用户的关键对象分析

1.SqlSessionFactoryBuilder
SqlSessionFactoryBuilder 用于创建 SqlSessionFacoty,SqlSessionFacoty 一旦创建完成就不需要SqlSessionFactoryBuilder 了,因为 SqlSession 是通过 SqlSessionFactory 生产,所以可以将SqlSessionFactoryBuilder 当成一个工具类使用,最佳使用范围是方法范围即方法体内局部变量。

2.SqlSessionFactory
SqlSessionFactory 是一个接口,接口中定义了 openSession 的不同重载方法,SqlSessionFactory 的最佳使用范围是整个应用运行期间,一旦创建后可以重复使用,通常以单例模式管理 SqlSessionFactory。

3.SqlSession
SqlSession 中封装了对数据库的操作,如:查询、插入、更新、删除等。
SqlSession 是通过 SqlSessionFactory 创建 ,而 SqlSessionFactory 是通过 SqlSessionFactoryBuilder 进行创建。
SqlSession 是一个面向用户的接口, sqlSession 中定义了数据库操作,默认使用 DefaultSqlSession 实现类。

SQL 执行过程

1.加载配置信息(mybatis-config.xml、*mapper.xml)

mybatis-config.xml 全局配置

  • 数据源信息
<environments ···>
	<!--数据源环境配置-->
	<environment ···>
		<!--事务管理器-->
		<transactionManager ··· />
		<!--数据源配置-->
		<dataSource ···>
			<property ··· />
			···
		</dataSource>		
	</environment>
</environments>
  • mapper 接口 与 sql 的映射文件地址
<!-- *mapper.xml 文件地址 -->
<mappers>
	<mapper ··· />
	···
</mappers>
  • *mapper.xml 中为 mapper 接口对应 sql 定义,参数、返回数据与 java 对象的映射关系
<mapper namespace="命名空间">
	<insert ···>
	<delete ···>
	<update ···>
	<select ···>
	<sql ···>
	···
</mapper>

通过查看 mybatis 的 config 文件的 dtd 文件 (http://mybatis.org/dtd/mybatis-3-mapper.dtd) 可知 mybatis-config.xml 中 configuration 下支持的标签如下所示

configuration (properties?, settings?, typeAliases?, typeHandlers?, objectFactory?, objectWrapperFactory?, >reflectorFactory?, plugins?, environments?, databaseIdProvider?, mappers?)

2.创建数据库链接
3.创建事务对象
4.创建 Executor (执行器)
5.SqlSession的实现类即 DefaultSqlSession,此对象中对操作数据库实质上用的是 Executor

注: 由于篇幅原因,这里只是简短介绍了执行流程,后面会详细分析

注意事项

SqlSession 的实例不能共享使用,它是线程不安全的,因此每个线程都应该有它自己的 SqlSession 实例。因此最佳的范围是请求或方法范围(定义局部变量使用)。绝对不能将SqlSession实例的引用放在一个类的静态字段或实例字段中。打开一个SqlSession;使用完毕就要关闭它。通常把这个关闭操作放到 finally 块中以确保每次都能执行关闭。

SqlSession session = sqlSessionFactory.openSession();
try {
     // do work
} finally {
    session.close();
}

参考链接: http://blog.csdn.net/column/details/13905.html

© 著作权归作者所有

共有 人打赏支持
HansenGuan
粉丝 0
博文 3
码字总数 8997
作品 0
广州
程序员
学以致用——CSDN概要数据(积分、篇数、访问总量)的多元线性回归分析

“学以致用最根本的是要把理论的知识和实际的应用要联合起来,由浅入深地达到熟能生巧的目的,学到的东西要经常揣摩,真正地理解其含义(包括使用的方法,注意的事项)然后按照理论的要求在实...

hpdlzu80100
2017/12/29
0
0
泥沙砖瓦浆木匠/springboot-learning-example

springboot-learning-example spring boot 实践学习案例,是 spring boot 初学者及核心技术巩固的最佳实践。 推荐 springcloud-learning-example spring cloud 实践学习案例 https://github...

泥沙砖瓦浆木匠
2017/03/29
0
0
软件测试职业发展规划浅谈

很多刚刚迈入测试行业或已进入测试行业有一段时间的同学,对自己的发展路线仍然迷茫,不知道该如何在测试行业发展或者不知如何很好的规划自己的职业生涯。虽然前一段做过一次公开课,详细的介...

hblxp321
2014/06/17
0
0
系统的学习大数据分布式计算spark技术

我们在学习一门技术的时候一定要以系统的思维去学习,这样的话,不仅对你的提高有很大的帮助,也可以让你高效的使用这个技术。 对于学习spark,当然也是要以系统的思维去全面的学习。这篇博客...

tangweiqun
2017/09/24
0
0
史上最简单的 MyBatis 教程

1 前言   MyBatis 源于 Apache 的一个开源项目 iBatis,而 iBatis 一词则来源于“internet”和“abatis”的组合,2010年这个项目由 Apache Software Foundation 迁移到了 Google Code,并且...

qq_35246620
2017/02/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

虚拟机学习之二:垃圾收集器和内存分配策略

1.对象是否可回收 1.1引用计数算法 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时候计数器值为0的对象就是不可能...

贾峰uk
23分钟前
0
0
smart-doc功能使用介绍

smart-doc从8月份底开始开源发布到目前为止已经迭代了几个版本。在这里非常感谢那些敢于用smart-doc去做尝试并积极提出建议的社区用户。因此决定在本博客中重要说明下smart-doc的功能,包括使...

上官胡闹
昨天
2
0
JavaEE——Junit

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 Junit Junit又名单元测试,Junit是用来测试Jav...

凯哥学堂
昨天
1
0
读《美丽新世界》

一、背景 十一国庆节从重庆回深圳的时候,做得绿皮车,路上看了两本书:李笑来的《韭菜的自我修养》和禁书《美丽新世界》。 上篇文章已经分享了 读《韭菜的自我修养》,这篇文章来记录一下《...

tiankonguse
昨天
1
0
archlinux下基于Jenkins,docker实现自动化部署(持续交互)

本文永久更新地址:https://my.oschina.net/bysu/blog/2250954 【若要到岸,请摇船:开源中国 不最醉不龟归】 -----------------------------------第一部分Jenkins的安装与使用-----------...

不最醉不龟归
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部