MyBatis原理浅析

简介

MyBatis是一个轻量级的ORM框架,它简化了对关系数据库的使用,开发人员可以在XML或注解中编写SQL来完成对数据库的操作。
如果完全使用XML方式,SQL语句可以集中维护,做到与Java代码完全隔离,便于对SQL调优。

原理及流程

  1. 加载配置:配置来源于两个地方,一是配置文件,一是Java代码的注解,将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
  2. SQL解析:当API接口层接收到调用请求时,会接收到传入SQL的ID和传入对象(可以是Map、JavaBean或者基本数据类型),Mybatis会根据SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参。
  3. SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
  4. 结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。

技术盏

反射、jdk动态代理、Ognl表达式引擎、缓存

反射和动态代理

解析是将SQL或存储过程定义表述为Mybatis中对应对象的过程,例如将执行的Sql标签( , …)解析为 MappedStatement ;输入参数定义标签解析为 ParameterMap ;结果列定义标签解析为 ResultMap

Mybatis支持将一个类的方法映射到一个 mapper 文件里的对应 statement sql,将方法名与DML SQL标签的id对应起来,这样我们就可以透明地使用 interface 的方式结合了面向对象的方式来与数据库操作,这样做更趋近于面向对象的编程风格。其中用到jdbc动态代理原理,用 MapperProxy 动态代理了需要执行的接口方法,主要代理逻辑在 MapperMethod 中实现,负责用接口的名称以及方法名称找到解析好的 MappedStatement 然后调用 SqlSession 中对应的执行逻辑执行。

缓存

Mybatis的一级缓存是SqlSession级别。第一次执行select时候会发现sqlsession缓存没有记录,会去数据库查找,然后把结果保存到缓存,第二次同等条件查询下,就会从缓存中查找到结果。另外为了避免脏读,每次执行更新新增删除时候会清空当前sqlsession缓存。

二级缓存是namespace级别的。同一个namespace下的搜寻语句共享一个二级缓存。如果开启了二级缓存,则先从二级缓存中查找,查找不到则委托为SimpleExecutor查找,而它则会先从一级缓存中查找,查找不到则从数据库查找。

mybaits的二级缓存一般不怎么使用,默认一级缓存是开启的。

基于注解方式的demo

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(100) DEFAULT NULL,
  `create_time` int(11) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-dependenciesartifactId>
                <version>1.4.3.RELEASEversion>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
 dependencyManagement>

 <dependencies>
        <dependency>
            <groupId>org.mybatis.spring.bootgroupId>
            <artifactId>mybatis-spring-boot-starterartifactId>
            <version>1.1.1version>
        dependency>
        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-dbcp2artifactId>
            <version>2.1.1version>
        dependency>
 dependencies>

application.properties

project.name=mybatis
server.port=7005
management.port=7006

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

logging.level.root=info

mybatis.xml


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    
    <bean id="propertyFileConfigForDB"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="location">
            <value>classpath:application.propertiesvalue>
        property>
    bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
    
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    bean>

    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    bean>

    
    <bean id="sqlSessionFactor" class="org.mybatis.spring.SqlSessionFactoryBean" primary="true">
        <property name="dataSource" ref="dataSource"/>
    bean>

    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.test.dao.*"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactor"/>
    bean>
beans>

主类上添加注解 @ImportResource({“classpath:mybatis.xml”}),以引入配置mybatis.xml

public class UserDo {
    public Long getId() {
        return id;
    }

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

    private Long id;
    private String user_name;
    private Long create_time;
    private Integer age;

    public UserDo() {}

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public Long getCreate_time() {
        return create_time;
    }

    public void setCreate_time(Long create_time) {
        this.create_time = create_time;
    }

    public Integer getAge() {
        return age;
    }

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




@MapperScan
public interface UserMapper {
    @Insert("insert into user (user_name,create_time,age) values ("
            + "#{user_name},#{create_time},#{age})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    Long insertUser(UserDo userDo);

    @Delete("delete from user where id = #{id}")
    Long deleteUser( Long id);

    @Update("update user set user_name=#{user_name}, create_time=#{create_time},"
      + " age=#{age} where id=#{id}")
    Long updateUser(UserDo userDo);

    @Select("select * from user where id=#{id}")
    UserDo selectUserById(Long id);
}



public interface UserService {
    Long createUser(User user);
    Long deleteUser(Long id);
    Long updateUser(User user);
    User selectUser(Long id);
}



@Service
public class UserServiceImpl implements UserService {
    private static Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);

    @Resource
    private UserMapper userMapper;

    @Override
    public Long createUser(User user) {
        try {
            return userMapper.insertUser(new UserDo(user));
        } catch (Exception ex) {
            logger.error("exception occurred: {}", ex);
        }

        return null;
    }

    @Override
    public Long deleteUser(Long id) {
        try {
            return userMapper.deleteUser(id);
        } catch (Exception ex) {
            logger.error("exception occurred: {}", ex);
        }
        return null;
    }

    @Override
    public Long updateUser(User user) {
        try {
            return userMapper.updateUser(new UserDo(user));
        } catch (Exception ex) {
            logger.error("exception occurred: {}", ex);
        }
        return null;
    }

    @Override
    public User selectUser(Long id){
        try {
            UserDo userDo =  userMapper.selectUserById(id);
            return new User(userDo);
        } catch (Exception ex) {
            logger.error("exception occurred: {}", ex);
        }
        return null;
    }
}

参考资料

http://www.mybatis.org/mybatis-3/zh/index.html

你可能感兴趣的:(数据库,Java)