mybatis执行原理分析

Mybatis是对JDBC的封装,解决JDBC硬编码和频繁创建连接的问题,是一个半自动ORM框架。在SpringBoot中,通过添加依赖、配置数据库连接和Mapper,可以方便地集成Mybatis。Mapper接口和XML配置文件用于定义SQL操作,Mybatis通过动态代理实现接口方法调用到SQL执行的转换。
摘要由CSDN通过智能技术生成

Mybatis产生的背景

如果使用过JDBC操作关系型数据库,就会知道数据库连接配置、sql语句、参数、结果解析的过程存在硬编码的问题,同时每次执行sql就会创建一个数据库的连接,也存在连接频繁创建和销毁的问题。Mybatis就是对JDBC的封装,也解决了JDBC存在的这些问题,它是一个半自动的ORM(关系对象映射)的框架。

什么是ORM?

对象关系映射是指java的对象与数据库表中字段的映射,因为数据类型、列的名称与对象名称有对应的命名约定,所以数据库中查询的数据到java对象以及查询参数到列字段转换的过程,mybatis是一个半自动的对象关系映射框架,因为sql语句还是需要手动编写。

springboot如何集成

配置依赖

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.1</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

配置数据库连接

spring:
  application:
    name: test-service
  redis:
    host: localhost
    port: 6379
  datasource:
    url: jdbc:mysql://localhost:3306/order?useUnicode=true&rewriteBatchedStatements=true
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: order
    password: ***
 mybatis:
 #配置别名
  type-aliases-package: com.person.mybatis.dao
  #配置扫描映射文件的路径
  mapper-locations: classpath:mapper/*Mapper.xml

查询操作示例

配置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">
<mapper namespace= "com.person.mybatis.mapper.OrderMapper">
    <insert id="addOrder" parameterType= "com.person.mybatis.dao.Order">
         INSERT INTO t_order (user_id,commodity_code,count,amount) VALUES (# {userId}, # {commodityCode}, # {count}, # {amount})
   </insert>

    <select id="getOrderById" parameterType="int" resultType="com.person.mybatis.dao.Order">
      SELECT * FROM t_order WHERE id=#{id}
    </select>

</mapper>

Mapper 接口

@Mapper
public interface OrderMapper {
    Order getOrderById(Integer id);

    int addOrder(Order order);
}

实体类

@Data
public class Order {
    private Integer id;
    private String userId;
    private String commodityCode;
    private Integer count;
    private Integer amount;

}

控制器

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @GetMapping("getOrder/{id}")
    public Order getOrder(@PathVariable("id") Integer id) {
       return  orderService.getOrderById(id);
    }
}

@Service
public class OrderService {
	 @Autowired
	 private OrderMapper orderMapper;
	
	 public Order getOrderById(Integer id){
	     return orderMapper.getOrderById(id);
	 }
	 public int addOrder(Order order){
	     return orderMapper.addOrder(order);
	 }
}

添加 mapper 扫描配置

@SpringBootApplication
@MapperScan("com.person.mybatis.mapper")
public class HelloWordMainApplication {...}

mybatis 执行sql的原理分析

我们执行的是接口OrderMapper中的方法,在实际调用时是接口的代理实现类,根据statementId获取方法对应的sql语句,并根据xml中配置进行参数类型转换,并调用执行器执行sql。
从扫描注解查看

@Import({MapperScannerRegistrar.class})
@Repeatable(MapperScans.class)
public @interface MapperScan {...}
// 导入了类MapperScannerRegistrar实现了接口ImportBeanDefinitionRegistrar
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware {
	void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class);
        builder.addPropertyValue("processPropertyPlaceHolders", true);
        Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
        if (!Annotation.class.equals(annotationClass)) {
            builder.addPropertyValue("annotationClass", annotationClass);
        }
        ...
        //将定义注入到容器中
        registry.registerBeanDefinition(beanName, builder.getBeanDefinition());
   }
}

具体分析类这个类MapperScannerConfigurer,最终了解到,将带有注解@Mapper类的类型改为MapperFacatoryBean
在这里插入图片描述
获取bean时,调用getObject()方法

 public T getObject() throws Exception {
        return this.getSqlSession().getMapper(this.mapperInterface);
 }
 public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
   MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
    if (mapperProxyFactory == null) {
        throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
    } else {
        try {
            return mapperProxyFactory.newInstance(sqlSession);
        } catch (Exception var5) {
            throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
        }
    }
}
//看到了代理类的实现
public T newInstance(SqlSession sqlSession) {
      MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
      return this.newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

MapperProxy中的invoke()

// PlainMethodInvoker.invoke()方法
 public Object execute(SqlSession sqlSession, Object[] args) {
        Object result;
        Object param;
        //根据sql的类型判断,执行的方法
        switch(this.command.getType()) {
        case INSERT:
            param = this.method.convertArgsToSqlCommandParam(args);
            //调用执行器Excutor中的执行方法,在封装结果
            result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
            break;
            //代码太多了,省略
            ...
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值