【MyBatis学习笔记 五】MyBatis注解开发实现方式

简介: 【MyBatis学习笔记 五】MyBatis注解开发实现方式

上一篇Blog我们详细分析了MyBatis的执行原理,我们可以感受到其实实际的方法执行是通过动态代理而非方法本身实现的,那么既然基于动态代理可以实现,那么基于注解的实现方式貌似看起来更加直观,因为注解是可以直接加在方法上的。本篇Blog来学习下如何通过注解进行MyBatis的实现。

MyBatis注解开发流程

因为我们使用了注解开发,所以PersonMapper文件就不需要了,而且我们知道其实该配置文件最终被获取的也是接口的全限定名,所以我们确保核心配置文件能找到该接口即可:

1 调整核心配置文件

我们首先调整核心配置文件,注释掉之前的mapper文件引用,加入类的引用,需要注意两种引入方式如果引入同一个接口则不能并存:

我们调整一下注释:

<?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核心配置文件-->
<configuration>
    <!--导入properties文件-->
    <properties resource="properties/db.properties"/>
    <settings>
        <setting name="logImpl" value="log4j"/>
    </settings>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
<!-- <mapper resource="mappers/personMapper.xml"/>-->
        <mapper class="com.example.MyBatis.dao.mapper.PersonDao"/>
    </mappers>
</configuration>

此时运行单元测试还是会报错,为什么呢,因为我们只引入了命名空间,并没有在任何方法上添加注释

2 接口方法增加注解

我们把CRUD都尝试一下,因为效果和xml配置类似,只不过将xml中的sql语句直接转移到了方法上,所以效果不再展示:

package com.example.MyBatis.dao.mapper;
import com.example.MyBatis.dao.model.Person;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
public interface PersonDao {
    @Select("select *  from person")
    List<Person> getPersonList();
    @Select("select * from person where password=#{password} and username = #{username}")
    Person getPersonByUsername(@Param("username")String username, @Param("password")String password);
    Person getPersonByMap(Map<String,Object> map);
    @Insert("insert into person (id,username,password,age,phone,email,hobby) values (#{id},#{username},#{password},#{age},#{phone},#{email},#{interests}")
    int addPerson(Person person);
    @Update(" update person set username=#{username},phone=#{phone} where id=#{id}")
    int updatePerson(Person person);
    @Delete("  delete from person where id = #{id}")
    int deletePerson(@Param("id")int id);
    List<Person> getPersonListLike(@Param("username")String username);
    List<Person> getPersonListPage(Map<String,Integer> map);
}

3 测试类进行测试

测试效果就不再展示了,测试方法和之前是一样的,没有变化,这里我们只看获取时测试,通过这个来说明一个问题:

@Test
    public void testGetPersonList(){
        //1.获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //2.执行SQL
        PersonDao personDao = sqlSession.getMapper(PersonDao.class);
        List<Person> personList = personDao.getPersonList();
        for (Person person : personList) {
            System.out.println(person);
        }
        //关闭sqlSession
        sqlSession.close();
    }

返回结果如下,兴趣爱好返回为null,那是因为结果集的数据表字段和我们类的属性不匹配导致的。

所以其实注解开发方式是不支持结果集映射的。

MyBatis注解实现

和所有注解一样,添加注解后就一定需要对注解进行处理,在builder的时候,通过注解获取上下文的读取和使用如下:

private class AnnotationWrapper {
        private final Annotation annotation;
        private final String databaseId;
        private final SqlCommandType sqlCommandType;
        AnnotationWrapper(Annotation annotation) {
            this.annotation = annotation;
            if (annotation instanceof Select) {
                this.databaseId = ((Select)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.SELECT;
            } else if (annotation instanceof Update) {
                this.databaseId = ((Update)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.UPDATE;
            } else if (annotation instanceof Insert) {
                this.databaseId = ((Insert)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.INSERT;
            } else if (annotation instanceof Delete) {
                this.databaseId = ((Delete)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.DELETE;
            } else if (annotation instanceof SelectProvider) {
                this.databaseId = ((SelectProvider)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.SELECT;
            } else if (annotation instanceof UpdateProvider) {
                this.databaseId = ((UpdateProvider)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.UPDATE;
            } else if (annotation instanceof InsertProvider) {
                this.databaseId = ((InsertProvider)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.INSERT;
            } else if (annotation instanceof DeleteProvider) {
                this.databaseId = ((DeleteProvider)annotation).databaseId();
                this.sqlCommandType = SqlCommandType.DELETE;
            } else {
                this.sqlCommandType = SqlCommandType.UNKNOWN;
                if (annotation instanceof Options) {
                    this.databaseId = ((Options)annotation).databaseId();
                } else if (annotation instanceof SelectKey) {
                    this.databaseId = ((SelectKey)annotation).databaseId();
                } else {
                    this.databaseId = "";
                }
            }
        }
        Annotation getAnnotation() {
            return this.annotation;
        }
        SqlCommandType getSqlCommandType() {
            return this.sqlCommandType;
        }
        String getDatabaseId() {
            return this.databaseId;
        }
    }

构建查询语句的时候就直接用注解里的参数和内容:

private SqlSource buildSqlSource(Annotation annotation, Class<?> parameterType, LanguageDriver languageDriver, Method method) {
        if (annotation instanceof Select) {
            return this.buildSqlSourceFromStrings(((Select)annotation).value(), parameterType, languageDriver);
        } else if (annotation instanceof Update) {
            return this.buildSqlSourceFromStrings(((Update)annotation).value(), parameterType, languageDriver);
        } else if (annotation instanceof Insert) {
            return this.buildSqlSourceFromStrings(((Insert)annotation).value(), parameterType, languageDriver);
        } else if (annotation instanceof Delete) {
            return this.buildSqlSourceFromStrings(((Delete)annotation).value(), parameterType, languageDriver);
        } else {
            return (SqlSource)(annotation instanceof SelectKey ? this.buildSqlSourceFromStrings(((SelectKey)annotation).statement(), parameterType, languageDriver) : new ProviderSqlSource(this.assistant.getConfiguration(), annotation, this.type, method));
        }
    }

上一篇Blog我们提到的执行原理中,执行具体的sql语句由从Mapper中获取对应方法调整为从当前方法上的注解获取配置sql内容,源码位置对应如下:

总结一下

其实注解开发很简单,和xml的原理是一样的,都是在通过动态代理生成Mapper对象后进行方法调用,不同的是xml方式,需要通过绑定的方法id找到对应的内容进行执行,而注解方式则直接寻找当前方法上的注解进行执行。注解不支持结果集映射是个缺陷,而且如果代码量复杂在方法上打注解也不是一种好的方式,基于我们想要让代码和sql分离的原则,我还是更愿意使用xml方式,规整且低耦合,只有规模特别的小的项目才适合注解这种方式,注解方式就作为一个简单的了解吧。

相关文章
|
7天前
|
Java 数据库连接 数据格式
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
|
22天前
|
SQL Java 数据库连接
Spring Boot联手MyBatis,打造开发利器:从入门到精通,实战教程带你飞越编程高峰!
【8月更文挑战第29天】Spring Boot与MyBatis分别是Java快速开发和持久层框架的优秀代表。本文通过整合Spring Boot与MyBatis,展示了如何在项目中添加相关依赖、配置数据源及MyBatis,并通过实战示例介绍了实体类、Mapper接口及Controller的创建过程。通过本文,你将学会如何利用这两款工具提高开发效率,实现数据的增删查改等复杂操作,为实际项目开发提供有力支持。
54 0
|
1月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(7、使用注解开发)
这篇文章讲述了如何使用MyBatis框架的注解方式进行开发,包括在接口上使用注解定义SQL语句,并通过动态代理实现对数据库的增删改查操作,同时强调了接口需要在核心配置文件中注册绑定。
|
3月前
|
Java 数据库连接 数据库
Springboot整合mybatis注解版(202005)
Springboot整合mybatis注解版(202005)
|
3月前
|
SQL XML Java
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
后端数据库开发JDBC编程Mybatis之用基于XML文件的方式映射SQL语句实操
57 3
|
3月前
|
Java 数据库连接 API
后端开发之用Mybatis简化JDBC的开发快速入门2024及数据库连接池技术和lombok工具详解
后端开发之用Mybatis简化JDBC的开发快速入门2024及数据库连接池技术和lombok工具详解
48 3
|
3月前
|
SQL Java 数据库连接
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
2万字实操案例之在Springboot框架下基于注解用Mybatis开发实现基础操作MySQL之预编译SQL主键返回增删改查
56 2
|
3月前
|
缓存 NoSQL Java
在 SSM 架构(Spring + SpringMVC + MyBatis)中,可以通过 Spring 的注解式缓存来实现 Redis 缓存功能
【6月更文挑战第18天】在SSM(Spring+SpringMVC+MyBatis)中集成Redis缓存,涉及以下步骤:添加Spring Boot的`spring-boot-starter-data-redis`依赖;配置Redis连接池(如JedisPoolConfig)和连接工厂;在Service层使用`@Cacheable`注解标记缓存方法,指定缓存名和键生成策略;最后,在主配置类启用缓存注解。通过这些步骤,可以利用Spring的注解实现Redis缓存。
67 2
|
2月前
|
数据库
MybatisPlus3---常用注解,驼峰转下滑线作为表明 cteateTime 数据表中的 cteate_time,@TableField,与数据库字段冲突要使用转义字符“`order`“,is
MybatisPlus3---常用注解,驼峰转下滑线作为表明 cteateTime 数据表中的 cteate_time,@TableField,与数据库字段冲突要使用转义字符“`order`“,is
|
3月前
|
XML Java 数据库连接
MyBatis第二课,灰度发布,@Results注解,使用xml书写mysql
MyBatis第二课,灰度发布,@Results注解,使用xml书写mysql