Mybatis工作原理及实现增删查改(一)

(一)什么是Mybatis

MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的持久层框架。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以对配置和原生Map使用简单的 XML 或注解,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

(二)Hebernate和Mybatis的区别

  • hibernate是全自动,但mybatis是半自动。hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql,而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。Mybatis可以配置动态SQL并优化SQL,通过配置决定SQL的映射规则,它还支持存储过程等。对于一些复杂的和需要优化性能的项目,使用Mybatis更加合适。
  • hibernate数据库移植性远大于mybatis。hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(oracle、mysql等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
  • hibernate拥有完整的日志系统,mybatis则欠缺一些。hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。

(三)MyBatis的优缺点

1.优点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql基本上可以实现我们不使用数据访问框架可以实现的所有功能,或许更多。
  • 解除sql与程序代码的耦合:通过提供DAL层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql。

2.缺点

  • 编写SQL语句时工作量很大,尤其是字段多、关联表多时,更是如此。
  • SQL语句依赖于数据库,导致数据库移植性差,不能更换数据库。
  • 框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写,工作量也比较大,而且不太容易适应快速数据库修改。
  • 二级缓存机制不佳

(三)Mybatis工作原理

如图所示:
Mybatis工作原理及实现增删查改(一)_第1张图片

Mybatis操作数据执行步骤:

1.SqlMapConfig.xml:是Mybatis全局配置文件,配置Mybatis运行环境等信息,主要用来配置数据库连接。

2.Mapper.xml映射文件:Mapper.xml文件即是SQL映射文件,该文件配置操作数据库的SQL语句,需要在SqlMapConfig.xml中加载才能执行。SqlMapConfig.xml可以加载多个配置文件,每个配置文件对应数据库中的一张表。

3.构造会话工厂SqlSessionFactory :通过SqlMapConfig.xml配置文件构建SqlSessionFactory对象。

4.创建SqlSession对象:通过会话工厂创建SqlSession对象,SqlSession对象用来操作数据库。

5.Excutor执行器:用来根据SqlSession传递的传参数动态的生成需要执行的SQL语句,同时负责查询缓存的维护。

6.MapperStatement对象:在执行Excutor接口的执行方法,包含一个MapperStatement类型的参数,该参数是对映射信息的封装,用于存储要映射的SQL语句的id、参数等等。Mapper.xml文件中的一个SQL语句对应一个MapperStatement对象,SQL的id就是MapperStatement的id.

7.输入参数映射。在执行方法时,MapperStatement对象会对用户执行SQL语句的输入参数进行定义,Exceutor执行器会通过MapperStatement对象在执行SQL前,将输入的Java对象映射到SQL语句中,这里对输入参数的映射类似JDBC编程中对preparedStatement对象设置参数的过程。

8.输出结果映射。在执行方法时,MapperStatement对象会对用户执行SQL语句的输出参数进行定义,Exceutor执行器会通过MapperStatement对象在执行SQL后,将输出结果映射到Java对象中,这里对输出结果映射到Java对象的过程雷士JBDC编程中对结果的解析处理过程。

(四)Mybatis实现对数据库的增删查改

Mybatis下载及使用
项目结构图
Mybatis工作原理及实现增删查改(一)_第2张图片Mybatis工作原理及实现增删查改(一)_第3张图片

1.创建数据表

CREATE TABLE `t_customer` (
  `id` int(32) NOT NULL AUTO_INCREMENT,
  `username` varchar(50) DEFAULT NULL,
  `jobs` varchar(50) DEFAULT NULL,
  `phone` varchar(16) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
INSERT INTO `t_customer` VALUES ('1', 'joy', 'doctor', '18990123432');
INSERT INTO `t_customer` VALUES ('2', 'jack', 'teacher', '18992823439');
INSERT INTO `t_customer` VALUES ('3', 'tom', 'student', '18390912376');

2.在项目的src文件夹下创建log4j.properties用于在控制台查看日志信息

# Global logging configuration
log4j.rootLogger=ERROR, stdout
# MyBatis logging configuration...
log4j.logger.com.wang=DEBUG
# Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

3.在com.wang.po包下创建Customer.java

package com.wang.po;
public class Customer {
    private Integer id;       
    private String username;  
    private String jobs;       
    private String phone;
----省略setter和getter----
    @Override
    public String toString() {
        return "Customer [id=" + id + ", username=" + username + 
                       ", jobs=" + jobs + ", phone=" + phone + "]";
    }
}

3.在com.wang.mapper包下创建CustomerMapper.xml用于配置SQL语句




<mapper namespace="com.wang.mapper.CustomerMapper">

    
    <select id="findCustomerById" parameterType="Integer"
        resultType="com.wang.po.Customer">
        select*from t_customer where id=#{id}
    select>

    
    <select id="findCustomerByName" parameterType="String"
        resultType="com.wang.po.Customer">
        select*from t_customer where username like concat('%',#{username},'%')
    select>

    
    <insert id="addCustomer" parameterType="com.wang.po.Customer">
        insert into t_customer(username,jobs,phone)values(#{username},
        #{jobs},#{phone})
    insert>

    
    <update id="updateCustomer" parameterType="com.wang.po.Customer">
         update t_customer set username=#{username},jobs=#{jobs}
         ,phone=#{phone} where id=#{id}
    update>
    
    <delete id="deleteCustomer" parameterType="Integer">
        delete from t_customer where id=#{id}
    delete>
mapper>

注:#{}和${}的区别是什么?

#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。

注:模糊查询like语句该怎么写?

方法01:使用Mysql中的concat()函数进行字符串拼接
select*from t_customer where username like concat('%',#{username},'%')

4.在Src文件夹下创建mybatis-config.xml用于配置连接数据库的信息



<configuration>
    
    <environments default="mysql">
        
        <environment id="mysql">
            
            <transactionManager type="JDBC" />
            
            <dataSource type="POOLED">
              <property name="driver" value="com.mysql.jdbc.Driver" />
              <property name="url" 
                            value="jdbc:mysql://localhost:3306/mybatis" />
              <property name="username" value="root" />
              <property name="password" value="root" />
            dataSource>
        environment>
    environments>
    
    <mappers>
        
        <mapper resource="com/wang/mapper/CustomerMapper.xml" />
    mappers>
configuration>

5.在com.wang.Test包下创建MybatisTest.java

注:

01.执行数据库|查询|:不需要提交事务

02.执行数据库|添加|删除|修改|等操作:需要提交事务
package com.wang.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
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 com.wang.po.Customer;

public class MybatisTest {
    @Test
    public void findCustomerById() throws Exception {
        // 1、读取配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 2、根据配置文件构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 3、通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 4、SqlSession执行映射文件中定义的SQL,并返回映射结果
        Customer customer = sqlSession.selectOne("com.wang.mapper" + ".CustomerMapper.findCustomerById", 1);
        // 打印输出结果
        System.out.println(customer.toString());
        // 5、关闭SqlSession
        sqlSession.close();
    }

    @Test
    public void findCustomerByName() throws IOException { // 1、读取配置文件
        // 1、读取配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 2、根据配置文件构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 3、通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        List customers = sqlSession.selectList("com.wang.mapper.CustomerMapper.findCustomerByName", "j");
        for (Customer customer : customers) {
            System.out.println(customer);
        }
        // 5、关闭SqlSession
        sqlSession.close();
    }

    @Test
    public void addCustomer() throws IOException {
        // 1、读取配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 2、根据配置文件构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 3、通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 创建customer封装数据
        Customer customer = new Customer();
        customer.setUsername("rose");
        customer.setJobs("student");
        customer.setPhone("18390994116");

        int rows = sqlSession.insert("com.wang.mapper.CustomerMapper.addCustomer", customer);
        if (rows > 0) {
            System.out.println("插入" + rows + "条数据");
        } else {
            System.out.println("数据插入失败!");
        }
        // 4.必须提交事务,否则数据无法插入到数据库
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void updateCustomer() throws IOException {
        // 1、读取配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 2、根据配置文件构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 3、通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 创建customer封装数据
        Customer customer = new Customer();
        customer.setId(5);
        customer.setUsername("rose01");
        customer.setJobs("student");
        customer.setPhone("18390994116");

        int rows = sqlSession.update("com.wang.mapper.CustomerMapper.updateCustomer", customer);
        if (rows > 0) {
            System.out.println("已经修改" + rows + "条数据");
        } else {
            System.out.println("数据修改失败!");
        }
        // 4.必须提交事务,否则数据无法插入到数据库
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void deleteCustomer() throws IOException {
        // 1、读取配置文件
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        // 2、根据配置文件构建SqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 3、通过SqlSessionFactory创建SqlSession
        SqlSession sqlSession = sqlSessionFactory.openSession();

        int rows = sqlSession.update("com.wang.mapper.CustomerMapper.deleteCustomer", 5);
        if (rows > 0) {
            System.out.println("已经删除" + rows + "条数据");
        } else {
            System.out.println("数据删除失败!");
        }
        // 4.必须提交事务,否则数据无法插入到数据库
        sqlSession.commit();
        sqlSession.close();
    }
}

(五)使用工具类创建SqlSession对象

使用工具类:提取公共代码封装在工具类中,目的简化代码的开发,提高编程效率。

package com.wang.utils;
import java.io.Reader;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
/**
 * 工具类
 */
public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory = null;
    // 初始化SqlSessionFactory对象
    static {
        try {
            // 使用MyBatis提供的Resources类加载MyBatis的配置文件
            Reader reader = 
                    Resources.getResourceAsReader("mybatis-config.xml");
            // 构建SqlSessionFactory工厂
            sqlSessionFactory = 
                    new SqlSessionFactoryBuilder().build(reader);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    // 获取SqlSession对象的静态方法
    public static SqlSession getSession() {
        return sqlSessionFactory.openSession();
    }
}

你可能感兴趣的:(Mybatis)