天天看点

架构基础学习一 手写持久层框架及mybatis源码分析(4)

作者:上校马孔多在下雨

第三部分:Mybatis基本应⽤

3.1 快速⼊⻔

3.1.1 开发步骤:

  • 添加MyBatis的坐标
  • 创建user数据表
  • 编写User实体类
  • 编写映射⽂件UserMapper.xml
  • 编写核⼼⽂件SqlMapConfig.xml
  • 编写测试类

3.1.2 环境搭建:

导⼊MyBatis的坐标和其他相关坐标

<dependencies>
    <!--mybatis坐标-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.5</version>
    </dependency>
    <!--mysql驱动坐标-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.48</version>
        <scope>runtime</scope>
    </dependency>
    <!--单元测试坐标-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--⽇志坐标-->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.12</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>
    <dependency>
        <groupId>org.testng</groupId>
        <artifactId>testng</artifactId>
        <version>RELEASE</version>
        <scope>compile</scope>
    </dependency>
</dependencies>           

创建user数据表

架构基础学习一 手写持久层框架及mybatis源码分析(4)

编写User实体

public class User {
    private Integer id;
    private String username;
    private String password;
}           

编写UserMapper映射⽂件

<?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.tyf.mapper.UserMapper">
    <select id="findAll" resultType="com.tyf.pojo.User">
        select * from User
    </select>

    <insert id="add" parameterType="com.tyf.pojo.User">
        insert into user values(#{id},#{username},#{password})
    </insert>

    <delete id="delete" parameterType="com.tyf.pojo.User">
        delete from user where id = #{id}
    </delete>

    <delete id="update" parameterType="com.tyf.pojo.User">
        update user set username = #{username} where id = #{id}
    </delete>
</mapper>           

编写MyBatis核⼼⽂件

<?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>
    <!-- 加载外部的properties文件 -->
    <properties resource="jdbc.properties"/>
    <!-- 给实体类的全限定类名给别名 -->
   <!-- <typeAliases>
        <!– 给单独的实体起别名 –>
        <!–   <typeAlias type="com.lagou.pojo.User" alias="user"></typeAlias> –>
        <!– 批量起别名:该包下所有的类的本身的类名:别名还不区分大小写 –>
        <package name="com.lagou.pojo"/>
    </typeAliases>-->
    <!-- environments:运行环境 -->
    <environments default="development">
        <environment id="development">
            <!-- 当前事务交由JDBC进行管理 -->
            <transactionManager type="JDBC"/>
            <!-- 当前使用mybatis提供的连接池 -->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 引入映射配置文件 -->
    <mappers>
        <mapper resource="UserMapper.xml"/>
        <mapper resource="UserDao.xml"/>
    </mappers>
</configuration>           

编写测试代码

@Test
public void testSelect() throws IOException {
    //加载核⼼配置⽂件
    InputStream resourceAsStream = Resources.class.getResourceAsStream("/SqlMapConfig.xml");
    //InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");

    //获得sqlSession⼯⼚对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    //获得sqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //执⾏sql语句
    List<User> userList = sqlSession.selectList("userMapper.findAll");
    //打印结果
    System.out.println(userList);
    //释放资源
    sqlSession.close();
}           

jdbc文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root           

3.1.3 MyBatis的增删改查操作

MyBatis的插⼊数据操作: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 namespace="com.tyf.mapper.UserMapper">
    <insert id="add" parameterType="com.tyf.pojo.User">
        insert into user values(#{id},#{username},#{password})
    </insert>
</mapper>           

编写插⼊实体User的代码

@Test
public void testAdd() throws IOException {
    //加载核⼼配置⽂件
    InputStream resourceAsStream = Resources.class.getResourceAsStream("/SqlMapConfig.xml");
    //InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");

    //获得sqlSession⼯⼚对象
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    //获得sqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user = new User();
    user.setUsername("yyyy");
    user.setPassword("2222");
    int insert = sqlSession.insert("userMapper.add", user);
    //提交事务
    sqlSession.commit();
    //打印结果
    System.out.println(insert);
    //释放资源
    sqlSession.close();
}           

插⼊操作注意问题

插⼊语句使⽤insert标签

在映射⽂件中使⽤parameterType属性指定要插⼊的数据类型

Sql语句中使⽤#{实体属性名}⽅式引⽤实体中的属性值

插⼊操作使⽤的API是sqlSession.insert(“命名空间.id”,实体对象);

插⼊操作涉及数据库数据变化,所以要使⽤sqlSession对象显示的提交事务,即sqlSession.commit()

3.1.4 MyBatis的修改数据操作

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 namespace="com.tyf.mapper.UserMapper">
    <select id="findAll" resultType="com.tyf.pojo.User">
        select * from User
    </select>

    <insert id="add" parameterType="com.tyf.pojo.User">
        insert into user values(#{id},#{username},#{password})
    </insert>

    <delete id="delete" parameterType="com.tyf.pojo.User">
        delete from user where id = #{id}
    </delete>

    <delete id="update" parameterType="com.tyf.pojo.User">
        update user set username = #{username} where id = #{id}
    </delete>
</mapper>           
//加载核⼼配置⽂件
InputStream resourceAsStream = Resources.class.getResourceAsStream("/SqlMapConfig.xml");
//InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");

//获得sqlSession⼯⼚对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(2);
user.setUsername("666666");
int insert = sqlSession.update("userMapper.update", user);
//提交事务
sqlSession.commit();
//打印结果
System.out.println(insert);
//释放资源
sqlSession.close();           

修改操作注意问题

修改语句使⽤update标签

修改操作使⽤的API是sqlSession.update(“命名空间.id”,实体对象);

3.1.5 MyBatis的删除数据操作

//加载核⼼配置⽂件
InputStream resourceAsStream = Resources.class.getResourceAsStream("/SqlMapConfig.xml");
//InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");

//获得sqlSession⼯⼚对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
//获得sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = new User();
user.setId(6);
int insert = sqlSession.delete("userMapper.delete", user);
//提交事务
sqlSession.commit();
//打印结果
System.out.println(insert);
//释放资源
sqlSession.close();           

删除操作注意问题

删除语句使⽤delete标签

Sql语句中使⽤#{任意字符串}⽅式引⽤传递的单个参数

删除操作使⽤的API是sqlSession.delete(“命名空间.id”,Object);

3.1.6 MyBatis的映射⽂件概述

架构基础学习一 手写持久层框架及mybatis源码分析(4)

MyBatis核⼼配置⽂件层级关系

架构基础学习一 手写持久层框架及mybatis源码分析(4)

MyBatis常⽤配置解析

1)environments标签

数据库环境的配置,⽀持多环境配置

架构基础学习一 手写持久层框架及mybatis源码分析(4)

其中,事务管理器(transactionManager)常用类型有两种:

•JDBC:这个配置就是直接使⽤了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作⽤域。

•MANAGED:这个配置⼏乎没做什么。它从来不提交或回滚⼀个连接,⽽是让容器来管理事务的整个⽣命周期(⽐如 JEE 应⽤服务器的上下⽂)。 默认情况下它会关闭连接,然⽽⼀些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻⽌它默认的关闭⾏为。

2)mapper标签

该标签的作⽤是加载映射的,加载⽅式有如下⼏种:

•使⽤相对于类路径的资源引⽤,例如:

<mapper resource="org/mybatis/builder/AuthorMapper.xml"/>

•使⽤完全限定资源定位符(URL),例如:

<mapper url="file:///var/mappers/AuthorMapper.xml"/>

•使⽤映射器接⼝实现类的完全限定类名,例如:

<mapper class="org.mybatis.builder.AuthorMapper"/>

•将包内的映射器接⼝实现全部注册为映射器,例如:

<package name="org.mybatis.builder"/>

3.1.7 Mybatis相应API介绍

SqlSession⼯⼚构建器SqlSessionFactoryBuilder

常⽤API:SqlSessionFactory build(InputStream inputStream)

通过加载mybatis的核⼼⽂件的输⼊流的形式构建⼀个SqlSessionFactory对象

//加载核⼼配置⽂件
InputStream resourceAsStream = Resources.class.getResourceAsStream("/SqlMapConfig.xml");
//InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("SqlMapConfig.xml");

//获得sqlSession⼯⼚对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);           

其中, Resources ⼯具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、⽂件系统或⼀个 web URL 中加载资源⽂件。

SqlSession⼯⼚对象SqlSessionFactory

SqlSessionFactory 有多个个⽅法创建SqlSession 实例。常⽤的有如下两个

架构基础学习一 手写持久层框架及mybatis源码分析(4)

SqlSession会话对象

SqlSession 实例在 MyBatis 中是⾮常强⼤的⼀个类。在这⾥你会看到所有执⾏语句、提交或回滚事务和获取映射器实例的⽅法。

执⾏语句的⽅法主要有:

架构基础学习一 手写持久层框架及mybatis源码分析(4)

操作事务的⽅法主要有:

架构基础学习一 手写持久层框架及mybatis源码分析(4)

3.2 Mybatis的Dao层实现

3.2.1 传统开发⽅式

编写UserDao接⼝

package com.tyf.mapper;

import com.tyf.pojo.User;

import java.io.IOException;
import java.util.List;

public interface IUserDao {

    List<User> findAll() throws IOException;

}           

编写UserDaoImpl实现

package com.tyf.mapper;

import com.tyf.pojo.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @Author tyf
 * @DATE 2022/8/8 8:55
 **/
public class UserDaoImpl implements IUserDao{

    @Override
    public List<User> findAll() throws IOException {
        InputStream resourceAsStream =
                Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new
                SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        sqlSession.close();
        return userList;
    }
}           

测试传统⽅式

@Test
public void testTraditionDao() throws IOException {
    IUserDao userDao = new UserDaoImpl();
    List<User> all = userDao.findAll();
    System.out.println(all);
}           

3.2.2 代理开发⽅式

代理开发⽅式介绍

采⽤ Mybatis 的代理开发⽅式实现 DAO 层的开发,这种⽅式是我们后⾯进⼊企业的主流。

Mapper 接⼝开发⽅法只需要程序员编写Mapper 接⼝(相当于Dao 接⼝),由Mybatis 框架根据接⼝

定义创建接⼝的动态代理对象,代理对象的⽅法体同上边Dao接⼝实现类⽅法。

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

1) Mapper.xml⽂件中的namespace与mapper接⼝的全限定名相同

2) Mapper接⼝⽅法名和Mapper.xml中定义的每个statement的id相同

3) Mapper接⼝⽅法的输⼊参数类型和mapper.xml中定义的每个sql的parameterType的类型相同

4) Mapper接⼝⽅法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

编写UserMapper接⼝

架构基础学习一 手写持久层框架及mybatis源码分析(4)
@Test
public void testDao() throws IOException {
    InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> users = mapper.findAll();
    users.forEach(e-> System.out.println(e));
    sqlSession.close();
}           

继续阅读