美文网首页
MyBatis系列(一)——MyBatis的介绍和CRUD

MyBatis系列(一)——MyBatis的介绍和CRUD

作者: moutory | 来源:发表于2021-04-01 15:32 被阅读0次

    前言

    MyBatis是一个第三方开发的一款优秀的持久层框架,它不仅解决了原始JDBC操作数据库的繁琐步骤,而且还提供了自定义 SQL、存储过程以及高级映射等功能来简化我们的开发。当前MyBatis已经成为了许多项目的选择使用的持久层框架,作为一个java开发人员,掌握和清楚Mybatis的使用和原理是很有必要的。本篇文章将作为MyBatis系列的首篇,来介绍MyBatis的产生背景和基本的CRUD操作,希望能给各位读者一个参考。

    想要了解更多MyBaits系列文章,可以从下面的传送门阅读:

    MyBatis系列(二)——MyBatis的动态代理和映射文件动态配置


    一、MyBatis的介绍

    (一)MyBatis的产生背景

    我们在前面的文章中曾经提到,java虽然给数据库厂商提供了操作数据库的接口,但原始的JDBC操作步骤还是十分的繁琐,需要我们手动写很多代码,这就引出了JDBC Template工具的出现来简化我们的开发,MyBatis也是在这种背景下产生的产物,但它比JDBC TemplateDBUtils等工具类不同的是,它支持的功能更加强大、更丰富,所以也成为了许多项目持久层框架的选择。

    口说无凭,下面我们就以常规的查询操作,来看一下原始的JDBC操作是什么样的吧
    /**
     *   该类用于演示使用JDBC原始API操作数据库案例
     */
    public class JdbcForSqlTest {
    
        public static User getUserById() throws Exception{
            // 注册mysql驱动
            Class.forName("com.mysql.jdbc.Driver");
            // 获取jdbc连接
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root.");
            // 传入sql语句,获取预处理对象
            PreparedStatement preparedStatement = connection.prepareStatement("select * from user where uid = ?");
            // 传入参数
            preparedStatement.setString(1,"1");
            // 执行sql
            ResultSet resultSet = preparedStatement.executeQuery();
            // 将resultSet 拆分为具体的对象
            User user = new User();
            while (resultSet.next()){
                user.setUid(resultSet.getInt("uid"));
                user.setUsername(resultSet.getString("username"));
                user.setPassword(resultSet.getString("password"));
            }
            // 释放资源
            resultSet.close();
            preparedStatement.close();
            connection.close();
            return user;
        }
    
        public static void main(String[] args) throws Exception {
            System.out.println(getUserById());
        }
    }
    

    我们从上面的代码中可以发现,原始的JDBC操作有着以下三个缺点:
    1. 没有线程池的概念,每次执行sql都要获取和销毁数据库连接资源,浪费系统资源
    2. sql语句没有实现解耦合,比如数据库的配置和sql语句都耦合在了代码上面,一旦配置或者sql语句需要变动,就要改java代码,而且也不方便复用。
    3. 操作繁琐 查询操作时,需要手动将结果集中的数据手动封装到实体中。插入操作时,需要手动将实体的数据设置到sql语句的占位符位置.

    那么,针对这些问题,MyBatis提出了以下的解决方案:
    • 使用数据库连接池初始化连接资源
    • 将sql语句和数据库配置抽取到xml配置文件中
    • 使用反射、内省等底层技术,自动将实体与表进行属性与字段的自动映射
    (二)MyBaits的简单演示Demo

    下面我们来简单演示一下同样的需求,使用MyBatis是怎么样解决的:

    1. 引入MyBatis依赖

    如果已经引入了驱动包的话这里就只需要引入MyBatis坐标就行

    <!-- 引入mysql驱动依赖 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>8.0.21</version>
            </dependency>
            <!-- 引入mybatis依赖 -->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.4.5</version>
            </dependency>
    
    2. 将数据库配置抽取为jdbc.properties文件
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test
    jdbc.username=root
    jdbc.password=root
    
    3. 创建UserMapper.xml文件

    UserMapper.xml用于存放我们抽取出来的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 namespace="userMapper">
    
        <select id="getUserById" parameterType="java.lang.Integer" resultType="com.qiqv.pojo.User">
            select * from user where uid = #{id}
        </select>
    </mapper>
    

    这里需要注意的有两点:

    1. mapper标签中的namespace属性,表示这个文件主要封装了哪个实体类的sql语句,我们需要保证每个mapper.xml文件的这个属性唯一。
    2. select 标签表示该标签下的是select查询语句
    4. 创建MyBatis核心配置文件sqlMapConfig.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>
    
        <!-- 获取jdbc.properties -->
        <properties resource="jdbc.properties" ></properties>
    
        <!-- 配置源环境 -->
         <environments default="developement">
            <environment id="developement">
                <transactionManager type="JDBC"></transactionManager>
                <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="com/qiqv/mapper/UserMapper.xml"></mapper>
        </mappers>
    </configuration>
    

    在这个配置文件中,我们引入了jdbc.properties文件和UserMapper.xml,同时在enviroment标签中配置了事务管理器为JDBC,使用MyBatis的数据库连接池。

    5. 编写实际的sql代码
    public class MyBatisForSqlTest {
    
        public static User getUserById() throws IOException {
            // 将核心配置文件转为流对象
            InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
            // 创建sqlSessionFactoryBuild对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            // 获取连接对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            // 执行sql语句
            List<User> user = sqlSession.selectList("userMapper.getUserById", 1);
           // 关闭资源
            sqlSession.close();
            return user.get(0);
        }
    
        public static void main(String[] args) throws IOException {
            System.out.println(getUserById());
        }
    }
    

    我们可以看到,使用MyBatis之后,我们的结果集和参数的数据封装、sql和数据库的配置参数、数据库连接池的问题就都得到了解决。看起来似乎我们做多了很多步骤,但实际上当MyBaits的框架搭好后,我们后面开发起来就不需要这么麻烦了。

    结果演示

    二、MyBatis的配置文件概述

    (一)映射文件

    在第一节中,我们使用了UserMapper.xml来封装我们的sql语句,下面我们就对这个配置文件来做一下基本的介绍吧。除开xml文件的约束头之外,我们日常开发中基本上都是在mapper标签中添加和修改各式的sql语句,根据不同类型的sql语句,对应也有着selectupdateinsertdelete标签使用。
    同时,虽然映射文件没有强制的命名规范,但我们一般还是会按照 pojo对象名 + Mapper.xml的命名规则来定义映射文件

    image.png
    (二)核心配置文件
    1. MyBatis核心配置文件层级关系
    MyBatis核心配置文件层级关系图
    2. MyBatis常用配置解析
    2.1 environments标签

    MyBaits允许我们在environments标签中定义多套环境,比如开发环境、测试环境等,我们可以根据需要修改选择运行环境。

    enviroment标签的具体配置

    其中,事务管理器(transactionManager)类型有两种:
    JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
    MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE 应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false 来阻止它默认的关闭行为。

    其中,数据源(dataSource)类型有三种:
    UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。(相当于没用连接池)
    POOLED:这种数据源的实现利用“池”的概念将 JDBC 连接对象组织起来。
    JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

    2.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"/>

    我们一般使用第一种和第四种方式比较多

    2.3 Properties标签

    实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件


    使用properties标签
    2.4 typeAlias标签

    见名知义,typeAlias标签的作用是设置别名。我们在第一节的例子的映射文件中,使用了resultTypeparamterType两个属性来定义结果类型和返回值类型,我们需要填入对应类的全路径包名

    未使用别名之前,需要用全路径包名
    但每次都要写类的全路径十分麻烦,别名的存在就帮我们解决了这个问题
    MyBaits中,已经帮我们定义好了一些常用的别名
    别名 数据类型
    string String
    long Long
    int lnteger
    double Double
    boolean Boolean
    ... ...

    我们也可以在核心配置文件中定义我们自己的别名

      <!--  配置别名 -->
        <typeAliases >
            <typeAlias type="com.qiqv.pojo.User" alias="user"></typeAlias>
         </typeAliases>
    

    这样我们原先映射文件中的sql标签就可以使用别名了


    使用别名效果

    三、MyBatis的CRUD操作

    (一)新增操作

    映射文件中新增sql语句

       <insert id="insertUser" parameterType="user">
            insert into user values (#{uid},#{username},#{password})
        </insert>
    

    java代码如下:

    public class UserDaoImpl implements UserDao {
        public boolean addUser(User user) throws IOException {
            InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = factory.openSession();
            int result = sqlSession.insert("userMapper.insertUser",user);
            System.out.println(result);
            sqlSession.commit();
            sqlSession.close();
            return result>0;
        }
    }
    

    这里需要注意的是,如果没有开启自动提交事务的话,需要手动执行commit方法

    (二)修改操作

    映射文件中新增sql语句

        <update id="updateUser" parameterType="user">
            update user set username = #{username} where uid=#{uid};
        </update>
    

    java代码如下:

    public class UserDaoImpl implements UserDao {
        public boolean updateUser(User user)throws Exception  {
            InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = factory.openSession();
            int result = sqlSession.update("userMapper.updateUser",user);
            sqlSession.commit();
            sqlSession.close();
            return result>0;
        }
    }
    
    (三)删除操作

    映射文件中新增sql语句

        <delete id="delUser" parameterType="int">
            delete from user where uid=#{id};
        </delete>
    

    java代码如下:

    public class UserDaoImpl implements UserDao {
        public boolean deleteUser(Integer uid)throws Exception  {
            InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = factory.openSession();
            int result = sqlSession.delete("userMapper.delUser",uid);
            sqlSession.commit();
            sqlSession.close();
            return result>0;
        }
    }
    
    (四)查询操作

    映射文件中新增sql语句

       <select id="getAllUser" resultType="user">
           select * from user
       </select>
    

    java代码如下:

    public class UserDaoImpl implements UserDao {
          public List<User> getAllUser() throws Exception {
            InputStream is = Resources.getResourceAsStream("sqlMapConfig.xml");
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = factory.openSession();
            List<User> users = sqlSession.selectList("userMapper.getAllUser");
            System.out.println(users);
            sqlSession.close();
            return users;
        }
    }
    

    至此,本篇文章中我们对MyBatis的入门介绍已经结束了,实际上MyBaits的入门操作并不难。我们在开发过程中遇到的问题往往也不仅仅是简单的单表操作,MyBaits的还有许多方法来帮助我们更好地解决DAO层的问题,想要了解更多可以参考本系列的其他文章。

    相关文章

      网友评论

          本文标题:MyBatis系列(一)——MyBatis的介绍和CRUD

          本文链接:https://www.haomeiwen.com/subject/gqazhltx.html