【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方式,规整且低耦合,只有规模特别的小的项目才适合注解这种方式,注解方式就作为一个简单的了解吧。

目录
打赏
0
0
0
0
32
分享
相关文章
MyBatis-Plus高级用法:最优化持久层开发
MyBatis-Plus 通过简化常见的持久层开发任务,提高了开发效率和代码的可维护性。通过合理使用条件构造器、分页插件、逻辑删除和代码生成器等高级功能,可以进一步优化持久层开发,提升系统性能和稳定性。掌握这些高级用法和最佳实践,有助于开发者构建高效、稳定和可扩展的企业级应用。
57 13
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
MyBatis-Plus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。本文讲解了最新版MP的使用教程,包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段等核心功能。
【MyBatisPlus·最新教程】包含多个改造案例,常用注解、条件构造器、代码生成、静态工具、类型处理器、分页插件、自动填充字段
|
2月前
|
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
97 5
Mybatis使用注解方式实现批量更新、批量新增
Mybatis使用注解方式实现批量更新、批量新增
65 3
深入理解@TableField注解的使用-MybatisPlus教程
`@TableField`注解在MyBatis-Plus中是一个非常灵活和强大的工具,能够帮助开发者精细控制实体类与数据库表字段之间的映射关系。通过合理使用 `@TableField`注解,可以实现字段名称映射、自动填充、条件查询以及自定义类型处理等高级功能。这些功能在实际开发中,可以显著提高代码的可读性和维护性。如果需要进一步优化和管理你的MyBatis-Plus应用程
227 3
Mybatis使用注解方式实现批量更新、批量新增
Mybatis使用注解方式实现批量更新、批量新增
223 1
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
文章介绍了MyBatis的简单增删改查操作,包括创建数据表、实体类、配置文件、Mapper接口及其XML文件,并解释了`#{}`预编译参数和`@Param`注解的使用。同时,还涵盖了resultType与resultMap的区别,并提供了完整的代码实例和测试用例。
mybatis复习02,简单的增删改查,@Param注解多个参数,resultType与resultMap的区别,#{}预编译参数
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
94 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
IOC/DI配置管理DruidDataSource和properties、核心容器的创建、获取bean的方式、spring注解开发、注解开发管理第三方bean、Spring整合Mybatis和Junit
【Java笔记+踩坑】Spring基础2——IOC,DI注解开发、整合Mybatis,Junit
5、Mybatis-Plus 常用注解
这篇文章详细介绍了Mybatis-Plus中常用的注解,包括解决实体类与数据库表名不一致、字段不匹配的问题,主键生成策略的配置,以及逻辑删除的实现方法。
5、Mybatis-Plus 常用注解
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等