你好MyBatis 入门篇

时间:2022-07-24
本文章向大家介绍你好MyBatis 入门篇,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

运行环境

IDEA 2018 + Maven + Mysql 5.1.44 + MyBatis 3.4.6

POM文件
   <dependencies>
        <!--MyBatis JAR-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>
        <!--MySQL JAR-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.44</version>
        </dependency>
    </dependencies>

从JDBC谈起

首先我们先去准备以下数据,做一个User表,以下我们就根据user表来表述整个MyBatis的入门篇 跟着搭建环境的小伙伴可以直接复制这段sql执行

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`  (
  `id` int(8) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `sex` varchar(5) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` int(4) NULL DEFAULT NULL,
  `phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

INSERT INTO `user` VALUES (1, '张三', '男', 18, '189----5487');
INSERT INTO `user` VALUES (2, '皇甫', '男', 24, '123----7536');

SET FOREIGN_KEY_CHECKS = 1;

对于传统的jdbc操作而言 我们通常都是怎么去连接数据库呢?先总结一下步骤

  1. 加载驱动
  2. 获取连接
  3. 准备sql
  4. 发送sql
  5. 填充参数
  6. 执行sql
  7. 执行查询的情况下获取结果集
  8. 关闭资源

那我们就根据传统JDBC去编写代码吧,进而引申出它的缺点以及为什么会有MyBatis的出现

package com.huangfu;
import java.sql.*;
/**
 * 传统jdbc的测试方案
 * 注意,再跟着练习的时候 请看清楚导包的名字 mysql jar包有重复包名,新手容易混淆
 * @author 皇甫
 */
public class TestJdbc {
    /**
     * 测试查询语句
     * @param args
     */
    public static void main(String[] args) throws SQLException {
        //数据库连接引用
        Connection connection = null;
        //sql执行器的引用
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            //驱动加载
            Class.forName("com.mysql.jdbc.Driver");
            //获取连接
            String url = "jdbc:mysql://localhost:3306/testmybatis";
            String userName = "root";
            String password = "hr";
            connection = DriverManager.getConnection(url, userName, password);
            //准备sql
            final String SQL = "select * from user where id=?";
            //发送sql
            preparedStatement = connection.prepareStatement(SQL);
            //填充参数
            preparedStatement.setInt(1, 1);
            //执行sql
            resultSet = preparedStatement.executeQuery();
            //处理结果集
            while (resultSet.next()){
                System.out.println("id:"+resultSet.getInt("id"));
                System.out.println("name:"+resultSet.getString("name"));
                System.out.println("sex:"+resultSet.getString("sex"));
                System.out.println("age:"+resultSet.getInt("age"));
                System.out.println("phone:"+resultSet.getString("phone"));
                System.out.println("------------------------------------------");
            }
        }catch (Exception e){
            e.printStackTrace();
        } finally {
            // 关闭连接,释放资源
            if (resultSet != null) {
                resultSet.close();
            }
            if (preparedStatement != null) {
                preparedStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
}
以上的jdbc缺点是什么呢,看一下下面图解分析?

思考一个问题,我们能不能将驱动加载和sql,从java代码中分离出来,写进配置文件里面呢,加载驱动和获取连接利用工厂模式获取呢?我们可以将驱动加载获取连接发送sql执行sql关闭资源;封装成一个JDBCUtil工具类;当然,这里有兴趣的同学可以自己封装一下,成功了别忘了告诉我这个好消息。

MyBatis

此时,我们上面所说的封装成工具类什么的,一个优秀的开源框架MyBatis全部都帮我们做到了,它将连接信息,以及SQL等全部都放入了配置文件,再配置文件中我们只需要关注SQL语句就OK了; MyBatis 是一款优秀的持久层框架,它支持定制化 SQL存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

MyBatis架构图

以上我们可以看出,其实MyBatis很简单

  • MyBatisConfig.xml是一个全局的配置文件,一个项目内只能有一个。
  • Mapper.xml是映射文件,可以有多个
  • SqlSessionFactory见名知意,是一个SqlSession工厂,用于获取sqlSession;获取方式为new SqlSessionFactoryBuilder.build(inputStream)
  • SqlSession 用于操作SQL的CRUD(增删改查 )
  • Executor执行器 执行sql
  • Mapped Statement 在配置文件中配置
初识MyBatis

在Resources文件夹的根目录建立MyBatisConfig.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>
    <!--配置默认使用那个环境变量  以id作为标志-->
    <environments default="test">
        <!--配置连接环境-->
        <environment id="test">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/testmybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="hr"/>
            </dataSource>
        </environment>
        <!--配置多个连接环境,至于使用谁在environments指定-->
        <environment id="development">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/testmybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="hr"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

为了方便,建立映射数据库的实体类

package com.huangfu.entity;

/**
 * 构建实体类
 * @author 皇甫
 */
public class User {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private String phone;

    public User(Integer id, String name, String sex, Integer age, String phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.phone = phone;
    }

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", sex='" + sex + ''' +
                ", age=" + age +
                ", phone='" + phone + ''' +
                '}';
    }
}

在Resources文件夹建立Mapper文件夹,在创建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" >
<!--namespace 暂时可以随意写 保证命名空间唯一-->
<mapper namespace="myUser">
    <!--ID保证唯一 resultType指定返回值类型-->
    <select id="selectUser" resultType="com.huangfu.entity.User">
        select * from user where id=#{id}
    </select>
</mapper>

将Mapper文件注入到全局配置文件 ,此时查看完整的 mybatis-config.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>
    <!--配置默认使用那个环境变量  以id作为标志-->
    <environments default="test">
        <!--配置连接环境-->
        <environment id="test">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/testmybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="hr"/>
            </dataSource>
        </environment>
        <!--配置多个连接环境,至于使用谁在environments指定-->
        <environment id="development">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/testmybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="hr"/>
            </dataSource>
        </environment>
    </environments>
    <!--将Mapper文件在这里注册-->
    <mappers>
        <!--resource书写mapper所在文件的路径-->
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

准备工作完成,开始测试我们的使用是否正确

public class TestMyBatis {
    /**
     * 先将全局配置文件读入到内存
     * 获取SqlSessionFactory
     * 获取Session
     */
    private InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
    private SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    private SqlSession sqlSession = sqlSessionFactory.openSession();

    public TestMyBatis() throws IOException {
    }

    /**
     * 测试查询
     * @throws IOException
     */
    @Test
    public void selectUser() throws IOException {
        try{
            //指定哪一个Mapper文件下的哪一个语句
            //myUser对应Mapper文件中namespace的id名字  selectUser对应select id的名字
            //第二个参数 1 代表 #{id}   即要给#{id} 传值为1
            User user = sqlSession.selectOne("myUser.selectUser", 1);
            System.out.println(user);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(sqlSession !=null){
                sqlSession.close();
            }
            if(is != null){
                is.close();
            }
        }
    }
}

运行测试 User{id=1, name='张三', sex='男', age=18, phone='189----5487'}

查看何时执行的sql

导入日志jar包

        <!--导入日志JAR-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>

在Resources根目录创建文件 log4j.properties 并将下列日志文件复制进去

log4j.rootLogger=DEBUG,A1
log4j.logger.org.apache=DEBUG
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS} [%t] [%c]-[%p] %m%n

再次运行查询,我们会看到控制台打印日志文件如下

目录结构
完整的演示一下MyBatis的增删改查

1.书写实体类

package com.huangfu.entity;

/**
 * 构建实体类
 * @author 皇甫
 */
public class User {
    private Integer id;
    private String name;
    private String sex;
    private Integer age;
    private String phone;

    public User(Integer id, String name, String sex, Integer age, String phone) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.phone = phone;
    }

    public User() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", sex='" + sex + ''' +
                ", age=" + age +
                ", phone='" + phone + ''' +
                '}';
    }
}

2.书写mybatis-config.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>
    <!--配置默认使用那个环境变量  以id作为标志-->
    <environments default="test">
        <!--配置连接环境-->
        <environment id="test">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/testmybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="hr"/>
            </dataSource>
        </environment>
        <!--配置多个连接环境,至于使用谁在environments指定-->
        <environment id="development">
            <!--事务管理器使用JDBC-->
            <transactionManager type="JDBC"/>
            <!--数据源   连接池使用该POOLED-->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/testmybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="hr"/>
            </dataSource>
        </environment>
    </environments>
    <!--将Mapper文件在这里注册-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

3.书写Dao接口,映射到指定mapper

package com.complete;

import com.huangfu.entity.User;

/**
 * 用户的增删改查
 * @author 皇甫
 */
public interface UserDao {
    /**
     * 查询用户 根据ID
     * @param id
     * @return
     */
    public User findOneUserById(Integer id);

    /**
     * 修改用户
     * @param user
     */
    public void updateUser(User user);

    /**
     * 增加一个用户
     * @param user
     */
    public void addUser(User user);

    /**
     * 删除一个用户
     * @param id
     */
    public void deleteUserById(Integer id);
}

书写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" >
<!--namespace 暂时可以随意写 保证命名空间唯一-->
<mapper namespace="myUser">
    <!--ID保证唯一 resultType指定返回值类型-->
    <!--查询-->
    <select id="selectUser" resultType="com.huangfu.entity.User">
        select * from user where id=#{id}
    </select>
    <!--插入-->
    <insert id="insertUser" parameterType="com.huangfu.entity.User">
        insert into
          user(id,name,sex,age,phone)
        values
          (#{id},#{name},#{sex},#{age},#{phone})
    </insert>
    <!--修改-->
    <update id="updateUser" parameterType="com.huangfu.entity.User">
        update user set
          name=#{name},sex=#{sex},age=#{age},phone=#{phone}
        where
          id=#{id}
    </update>
    <!--删除-->
    <delete id="deleteUser">
        delete from user where id=#{id}
    </delete>
</mapper>

我为了简单,简易封装一个工具类,你们可以按照上面写的,不封装,一个一个写也行

package com.complete.util;

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;

/**
 * MyBatis简易工具类
 * @author 皇甫
 */
public class MyBatisUtil {
    private static InputStream is = null;
    private static  SqlSessionFactory sqlSessionFactory = null;
    static {
        try {
            is = Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    private static SqlSession sqlSession = sqlSessionFactory.openSession();

    public static SqlSession openSqlSession(){
        return sqlSession;
    }
    public static void closeSqlSession(){
        sqlSession.close();
    }
}

书写Dao实现类

package com.complete.dao.impl;

import com.complete.dao.UserDao;
import com.complete.util.MyBatisUtil;
import com.huangfu.entity.User;
import org.apache.ibatis.session.SqlSession;

/**
 *
 * @author 皇甫
 */
public class UserDaoImpl implements UserDao {
    private  SqlSession sqlSession = null;

    public UserDaoImpl() {
        sqlSession = MyBatisUtil.openSqlSession();
    }

    public User findOneUserById(Integer id) {
        User user = sqlSession.selectOne("myUser.selectUser", id);
        MyBatisUtil.closeSqlSession();
        return user;
    }

    public void updateUser(User user) {
        try{
            sqlSession.update("myUser.updateUser", user);
            //事务控制
            sqlSession.commit();
            System.out.println("修改成功");
        }catch (Exception e){
            sqlSession.rollback();
            e.printStackTrace();
        }finally {
            MyBatisUtil.closeSqlSession();
        }
    }

    public void addUser(User user) {
        try{
            sqlSession.insert("myUser.insertUser",user);
            //事务控制
            sqlSession.commit();
            System.out.println("插入成功");
        }catch (Exception e){
            sqlSession.rollback();
            e.printStackTrace();
        }finally {
            MyBatisUtil.closeSqlSession();
        }

    }

    public void deleteUserById(Integer id) {
        try{
            sqlSession.insert("myUser.deleteUser",id);
            //事务控制
            sqlSession.commit();
            System.out.println("删除成功");
        }catch (Exception e){
            sqlSession.rollback();
            e.printStackTrace();
        }finally {
            MyBatisUtil.closeSqlSession();
        }
    }
}

测试运行

package com.huangfu.testmybatis;

import com.complete.dao.UserDao;
import com.complete.dao.impl.UserDaoImpl;
import com.huangfu.entity.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.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * 测试MyBatis
 * @author 皇甫
 */
public class MyBatisTest {

    private UserDao ud = new UserDaoImpl();
    @Test
    public void testSelectUser(){
        User user = ud.findOneUserById(1);
        System.out.println(user);
    }
    @Test
    public void testInsertUser(){
        User user = new User(4, "赵六", "女", 20, "165----9574");
        ud.addUser(user);
    }
    @Test
    public void testUpdateUser(){
        User user = new User(2, "皇甫", "男", 20, "165----9574");
        ud.updateUser(user);
    }
    @Test
    public void testDeleteUser(){
        ud.deleteUserById(1);
    }
}