Mybatis04-使用注解开发

news2024/11/24 20:52:19

面向接口编程

面向接口编程

我们之前都学过面向对象编程,也学习过接口,但在真正的开发中,很多时候我们会选择面向接口编程

  • 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好

  • 在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了;

  • 而各个对象之间的协作关系则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。

关于接口的理解

  • 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

  • 接口的本身反映了系统设计人员对系统的抽象理解。

  • 接口应有两类:

    • 第一类是对一个个体的抽象,它可对应为一个抽象体(abstract class);
    • 第二类是对一个个体某一方面的抽象,即形成一个抽象面(interface);
    • 一个体有可能有多个抽象面。抽象体与抽象面是有区别的。

三个面向区别

  • 面向对象是指,我们考虑问题时,以对象为单位,考虑它的属性及方法 .

  • 面向过程是指,我们考虑问题时,以一个具体的流程(事务过程)为单位,考虑它的实现 .

  • 接口设计与非接口设计是针对复用技术而言的,与面向对象(过程)不是一个问题.更多的体现就是对系统整体的架构

利用注解开发

  1. UserMapper接口、

    @Select("select * from user")
    List<User> getUsers();
    
  2. 核心配置文件中绑定接口

    <!--绑定接口-->
    <mappers>
        <mapper class="com.study.dao.UserMapper"/>
    </mappers>
    
  3. 测试

    @Test
    public void getUsers(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
    
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    
        List<User> userList = mapper.getUsers();
    
        for (User user : userList) {
            System.out.println(user);
        }
    
        sqlSession.close();
    }
    

本质:反射机制实现

底层:动态代理

在这里插入图片描述

本质上利用了jvm的动态代理机制

在这里插入图片描述

在这里插入图片描述

注解增删改

改造MybatisUtils工具类的getSession( ) 方法,重载实现。

public static SqlSession getSqlSession() {
    return sqlSessionFactory.openSession(true); //事务自动提交
}

public static SqlSession getSession(boolean flag){
    return sqlSessionFactory.openSession(flag);
}

接口

package com.study.dao;

import com.study.pojo.User;
import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;

public interface UserMapper {

    @Select("select * from user")
    List<User> getUsers();

    //方法存在多个参数,所有的参数前面都要加上@Param("id")注
    @Select("select * from user where id=#{id}")
    User getUserByID(@Param("id")int id);


    @Update("update user set name=#{name},pwd=#{password} where id=#{id}")
    int updateUser(User user);

    @Insert("insert into user(id,name,pwd) values(#{id},#{name},#{password})")
    int addUser(User user);

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

在配置文件绑定Mapper接口

<mappers>
    <mapper class="com.study.dao.UserMapper"/>
</mappers>

测试代码同上

@Param注解

  1. 当在UserMapper中使用如下@param

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

    测试时报错:

    `org.apache.ibatis.exceptions.PersistenceException:

    Error updating database. Cause: org.apache.ibatis.binding.BindingException: Parameter ‘id’ not found. Available parameters are [uid, param1]`
    报错了,它说“id”没有找到,可用参数为“uid”

  2. 将SQL语句中的#{id}改为#{uid},也就是注解中的名字,正常运行:

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

    单个基本类型的形参时不使用@Param也能执行成功。

    那么其他更加复杂的情况呢,比如说,多个基本类型?引用类型?

    下面我们就来深入探讨一下@Param()究竟该怎么用。

  3. UserMapper接口

    @Select("select * from user where id=#{id} and name=#{username}")
    User getUserByID2(int id, String username);
    
  4. 测试

    @Test
    public void getUserById2(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        User user = mapper.getUserByID2(2, "张三");
        System.out.println(user);
        sqlSession.close();
    }
    

    报错:

    org.apache.ibatis.exceptions.PersistenceException: ###Error querying database.Cause: org.apache.ibatis.binding.BindingException: Parameter 'id' not found. Available parameters are [arg1, arg0, param1, param2]

    添加@Param后:

    @Select("select * from user where id=#{id} and name=#{username}")
    User getUserByID2(@Param("id")int id, @Param("username")String username);
    
  5. 测试正常运行。

    以上都是举得直接在接口中注解SQL语句的例子,在Mapper.xml文件中@Param()同样使用,只需要注意的是,使用@Param()注解,parameterType属性就不用再设置了。

三、总结

简单总结一下:

  1. sql的#{}中的参数就是@Param(“”)中设置的参数,而不是方法的形参

  2. 传入单个基本类型或String类型的时候,使用不使用@Param()注解都可以。

  3. 如果参数是 JavaBean , 则不能使用@Param。

  4. 需要传入多个参数时,有三种方法:JavaBean、@Param()注解、Map。个人认为优先使用JavaBean,当需要传入的数据较多但又不能完全将JavaBean利用起来的时候使用@Param()注解或Map。

  5. 单个基本类型,SQL对应的就是形参的名字;使用JavaBean,SQL中对应的就是JavaBean在结果集映射的属性(没有显性映射就是默认的属性);使用@Param(),SQL中对应的就是@Param()注解中的名字;使用Map,SQL中对应的就是Map的键名。

  6. 使用@Param()注解的时候,Mapper.xml文件无需再设置parameterType属性。

#{}和${}区别
{}中的参数即为Mapper接口中对应方法的形参

#{}

  1. #{} 的作用主要是替换**预编译**语句(PrepareStatement)中的占位符? 【推荐使用】

  2. 底层是preparedStatement

  3. 预编译

  4. 能防止sql注入,自动添加了‘ ’ 引号

例如:select * from user where username = #{name} //输入的参数lisa,就会自动加上引号,变成:select * from user where username = ‘lisa’

${}

  1. 不防注入,就是**字符串拼接**

  2. 只能${}的情况:order by、like 语句只能用${}了,用#{}会多个' '导致sql语句失效;此外动态拼接sql也要用${}

  3. #{} 这种取值是编译好SQL语句再取值

${} 这种是取值以后再去编译SQL语句

详细讲解:

1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:
order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111",
 如果传入的值是id,则解析成的sql为order by "id".
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,
如果传入的值是111,那么解析成sql时的值为order by user_id, 
 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
字符串替换
默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置
安全的值(比如?)。这样做很安全,很迅速也是首选做法
有时你只是想直接在sql语句中插入一个不改变的
字符串。比如,像ORDER BY,你可以这样来使用:ORDER BY ${columnName}
这里MyBatis不会修改或转义字符串。重要:接受从用户输出的内容并提供给语句中
不变的字符串,这样做是不安全的。这会导致潜在的sql注入攻击,因此你不应该
允许用户输入这些字段,或者通常自行转义并检查。

使用注解和配置文件协同开发,才是MyBatis的最佳实践!

Lombok

Lombok项目是一个java库,它可以自动插入到编辑器和构建工具中,增强java的性能。不需要再写getter、setter或equals方法,只要有一个注解,你的类就有一个功能齐全的构建器、自动记录变量等等。

Lombok是一个在Java开发过程中用注解的方式,简化了 JavaBean(实体类) 的编写,避免了冗余和样板式代码而出现的插件,让编写的类更加简洁。

1. 使用步骤

  1. 在IDEA中安装lombok插件:File —> Settings —> Plugins —> Browse repositories —> 搜索lombok
  2. 在pom.xml中导入lombok的maven依赖(包)
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.26</version>
    <scope>provided</scope>
</dependency>

  1. 在实体类上加注解即可

2.lombok常用注解

  • @Data : 自动生成set/get方法,toString方法,equals方法,hashCode方法,不带参数的构造方法
  • @NoArgsConstructor/@RequiredArgsConstructor/@AllArgsConstructor
    自动生成无参/有参构造方法
  • @Setter/@Getter : 自动生成set和get方法
  • @ToString : 自动生成toString方法
  • @EqualsAndHashcode : 从对象的字段中生成hashCode和equals方法

3.以下为不常用注解:

@NonNull : 用在成员方法或者构造方法的参数前面,会自动产生一个关于此参数的非空检查,如果参数为空,则抛出一个空指针异常

@CleanUp : 自动资源管理:不用再在finally中添加资源的close方法

@Value : 用于注解final类

@Builder : 产生复杂的构建器api类

@SneakyThrows : 异常处理(谨慎使用)

@Synchronized : 同步方法安全的转化

@Getter(lazy=true) :

@Log: 支持各种logger对象,使用时用对应的注解,如:@Log4j

4. 优缺点
优点:

  • 能通过注解的形式自动生成构造器、getter/setter、equals、hashcode、 toString等方法,提高了一定的开发效率

  • 让代码变得简洁,不用过多的去关注相应的方法

  • 属性做修改时,也简化了维护为这些属性所生成的getter/setter方法等

缺点:

  • 不支持多种参数构造器的重载

  • 虽然省去了手动创建getter/seter方法的麻烦,但大大降低了源代码的可读性和完整性,降低了阅读源代码的舒适度

总结

   Lombok虽然有很多优点,但Lombok更类似于一种IDE插件,项目也需要依赖相应的jar包。Lombok依赖jar包是因为编译时要用它的注解,为什么说它又类似插件?因为在使用时,eclipse或Intelli] DEA都需要安装相应的插件,在编译器编译时通过操作AST(抽象语法树)改变字节码生成,变向的就是说它在改变java语法。

   它不像spring的依赖注入或者mybatis的ORM一样是运行时的特性,而是编译时的特性,这里我个人最感觉不爽的地方就是对插件的依赖!因为Lombok只是省去了一些人丁生成代码的麻烦,但IDE都有快捷键来协助生成etter/setter等方法,也非常方便
    知乎上有位大神发表过对Lombok的一些看法:这是一种低级趣味的插件,不建议使用。JAva发展到今天,各种插件层出不穷,如何甄别各种插件的优劣?能从架构上优化你的设计的,能提高应用程序性能的,实现高度封装可扩展的..., 像1mbok这种,像这种插件,已经不仅仅是插件了,改变了你如何编写源码,事实上,少去了的代码你写上去又如何?如果JAVA家族到外充斥这样的东西,那只不过是一垃披着金属颜色的屎,迟早会被其它的语言取代。
   虽然话糙但理确实不糙,试想一个项目有非常多类似Lombok这样的插件,个人觉得真的会极大的降低阅读源代码的舒适度,虽然非常不建议在属性的getter/seter写一些业务代码,但在多年项目的实战中,有时通过给getter/setter加一点点业务代码,能极大的简化某些业务场景的代码。所谓取舍,也许就是这时的舍弃一定的规范,取得极大的方便。
   我现在非常坚信一条理念,任何编程语言或插件,都仅仅只是工具而已,即使工具再强大也在于用的人,就如同小米加步枪照样能前飞机大炮的道理一样。结合具体业务场景和项目实际情况,无需一味追求高大上的技术,适合的才是王道。
    Lombok有它的得天独厚的优点,也有它避之不及的缺点,熟知其优缺点,在实战中灵活运用才是王道

那只不过是一垃披着金属颜色的屎,迟早会被其它的语言取代。
虽然话糙但理确实不糙,试想一个项目有非常多类似Lombok这样的插件,个人觉得真的会极大的降低阅读源代码的舒适度,虽然非常不建议在属性的getter/seter写一些业务代码,但在多年项目的实战中,有时通过给getter/setter加一点点业务代码,能极大的简化某些业务场景的代码。所谓取舍,也许就是这时的舍弃一定的规范,取得极大的方便。
我现在非常坚信一条理念,任何编程语言或插件,都仅仅只是工具而已,即使工具再强大也在于用的人,就如同小米加步枪照样能前飞机大炮的道理一样。结合具体业务场景和项目实际情况,无需一味追求高大上的技术,适合的才是王道。
Lombok有它的得天独厚的优点,也有它避之不及的缺点,熟知其优缺点,在实战中灵活运用才是王道


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1803956.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

makefile与进度条

Linux项目自动化构建工具-make/makefile make是一个命令&#xff0c; makefile是一个文件&#xff0c;保存依赖关系和依赖方法。‘ touch Makefile/makefile mybin:mytest.c//依赖关系 目标文件&#xff1a;依赖文件列表 文件列表的文件之间以空格分隔 gcc -o mybin mytest.…

【Javascript系统学习】(二)

函数 定义函数 函数提升仅适用于函数声明&#xff0c;而不适用于函数表达式 函数声明 函数表达式 //例子1 const factorial function fac(n) {return n < 2 ? 1 : n * fac(n - 1); };console.log(factorial(3)); // 6 //factorial(n)、fac(n)、arguments.callee() ----…

【Python】解决Python报错:AttributeError: ‘list‘ object has no attribute ‘shape‘

​​​​ 文章目录 引言1. 错误详解2. 常见的出错场景2.1 使用列表代替NumPy数组2.2 错误的数据类型转换 3. 解决方案3.1 确保使用NumPy数组3.2 检查数据类型 4. 预防措施4.1 使用类型注解4.2 编写单元测试 结语 引言 在使用Python进行数据处理或科学计算时&#xff0c;可能会…

NodeJs实现脚本:将xlxs文件输出到json文件中

文章目录 前期工作和依赖笔记功能代码输出 最近有一个功能&#xff0c;将json文件里的内容抽取到一个xlxs中&#xff0c;然后维护xlxs文件。当要更新json文件时&#xff0c;就更新xlxs的内容并把它传回json中。这个脚本主要使用NodeJS写。 以下是完成此功能时做的一些笔记。 …

怎么换自己手机的ip地址

在互联网时代&#xff0c;IP地址已经成为了我们数字身份的一部分。无论是浏览网页、下载文件还是进行在线交流&#xff0c;我们的IP地址都在默默发挥着作用。然而&#xff0c;有时出于安全或隐私保护的考虑&#xff0c;我们可能需要更换手机的IP地址。那么&#xff0c;如何轻松…

工信部《工业和信息化领域数据安全风险评估实施细则(试行)》实行,行云管家数据产品助力企业数据安全

2024年6月1日&#xff0c;工信部颁布的《工业和信息化领域数据安全风险评估实施细则&#xff08;试行&#xff09;》&#xff08;以下简称《细则》&#xff09;开始实行&#xff0c;旨在引导工业和信息化领域数据处理者规范开展数据安全风险评估工作&#xff0c;提升数据安全管…

springboot3 一些听课笔记(1)

文章目录 一、日志框架二、springboot 自动配置三 、springweb3.13.2 自己编写一个messageconvert3.2.2 如果我们想让其支持yaml格式呢&#xff1f; 一、日志框架 springboot底层 默认使用logbacksjf4j作为日志框架。 1、每个 starter 场景&#xff0c;都会导入一个核心场景 …

3067. 在带权树网络中统计可连接服务器对数目 Medium

给你一棵无根带权树&#xff0c;树中总共有 n 个节点&#xff0c;分别表示 n 个服务器&#xff0c;服务器从 0 到 n - 1 编号。同时给你一个数组 edges &#xff0c;其中 edges[i] [ai, bi, weighti] 表示节点 ai 和 bi 之间有一条双向边&#xff0c;边的权值为 weighti 。再给…

驱动开发之设备树语法

目录 0.设备树由来 1.设备树概念 1.1.DTS、DTB 和 DTC 和 dtsi 概念 2.设备树语法 2.1.例子 2.2.设备节点 2.2.1.节点命名 2.2.2节点数据类型 2.2.3.根节点 2.2.4.属性介绍 2.2.4.1.compatible属性 2.2.4.2.name属性 2.2.4.3.status 属性 2.2.4.5.unit-address属性…

42【Aseprite 作图】梅花盆栽——拆解

1 花盆 是高度比较低的盆&#xff0c;只有一个下2&#xff1b;上面分两个 1 2 盆边缘颜色深&#xff0c;上面靠近外面的颜色浅&#xff0c;正面颜色稍微深一点&#xff0c;画两条竖的浅色线&#xff0c;作为装饰 2 花盆中的沙石 沙子颜色深一点&#xff0c;中间有浅一点的线…

C++学习/复习14--list的模拟实现(节点类/迭代器封装成类/list类/测试)

一、节点类 1.匿名对象 **在C中&#xff0c;匿名对象主要是通过构造函数直接生成的未命名对象实例&#xff0c;通常产生于以下三种情况&#xff1a;将对象作为值传递给函数、进行类型转换以及在函数需要返回一个对象时**。以下是对这三种情况的详细介绍&#xff1a; 1. **传…

全链路性能测试:Nginx 负载均衡的性能分析和调优

为什么性能测试很多同学觉得是一个比较难以自学上岸的测试领域,是因为真正做全链路的性能测试是比较难的。所谓的全链路就是在项目的整个链路上任何一环节都有可能存在性能测试瓶颈,我们都需要能够通过分析性能的监控指标找到对应的问题。 我们今天要讲的Nginx负载均衡就是…

基于协同过滤推荐的在线课程选修系统

基于协同过滤推荐的在线课程选修系统 demo 网站查看 http://course.qsxbc.com/all_course/ 点我查看 效果 功能 登录注册、点赞收藏、评分评论&#xff0c;课程推荐&#xff0c;热门课程&#xff0c;个人中心&#xff0c;可视化&#xff0c;后台管理&#xff0c;课程选修 …

【设计模式】JAVA Design Patterns——Servant(服务模式)

&#x1f50d;目的 仆人类被用于向一组类提供一些行为&#xff0c;区别于在每个类定义行为-或者当我们无法排除 公共父类中的这种行为&#xff0c;这些行为在仆人类被定义一次 &#x1f50d;解释 真实世界例子 国王、王后和其他宫廷皇室成员需要仆人为他们提供饮食、准备饮料等…

semaphore | 使用web界面的ansible来批量运维 linux、windows主机

Ansible 的现代化 UI &#xff0c;可以轻松管理和运行 Ansible playbook&#xff0c;功能强大&#xff0c;操作简单&#xff0c;支持中文。 文章目录 一、系统功能说明二、系统安装2.1 直接安装2.2 docker 安装 三、系统使用3.1 建立存储库3.2 编写代码3.3 建立主机配置3.3 建立…

Qt Window Dialog 无标题栏 ,无边框,可拖动

1.效果&#xff1a; 2. 主要实现步骤&#xff1a; 设置窗口 flag&#xff1a; this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); 创建变量存储位置 QPoint m_dragPosition; 对鼠标左键按下和移动事件做处理 void DraggableDialog::mousePre…

R语言探索与分析18-基于时间序列的汇率预测

一、研究背景与意义 汇率是指两个国家之间的货币兑换比率&#xff0c;而且在国家与国家的经济交流有着举足轻重的作用。随着经济全球化的不断深入&#xff0c;在整个全球经济体中&#xff0c;汇率还是一个评估国家与国家之间的经济状况和发展水平的一个风向标。汇率的变动会对…

嵌入式Linux系统编程 — 3.3 chown、fchown 和 lchown 函数更改文件属主

目录 1 文件属主 1.1 文件属主概念 1.2 如何查看文件属主 1.3 有效用户 ID 和有效组 ID 2 chown 函数 2.1 chown命令 2.2 chown函数 2.3 getuid 和 getgid函数 3 fchown函数 3.1 fchown函数简介 3.2 示例代码 4 lchown函数 1 文件属主 1.1 文件属主概念 Linux…

“中新美”三重身份,能帮SHEIN解决上市问题吗?

一家公司的海外上市之路能有多复杂&#xff1f;辗转多地的SHEIN&#xff0c;可能是当前最有话语权回答这个问题的公司。最近&#xff0c;它又有了新消息。 在上市信息多次更改后&#xff0c;伦敦正在成为SHEIN最有可能的“着陆”点。巴伦周刊援引英国天空新闻报道称&#xff0…

可以抛弃纸质礼金簿了,以后登记礼金可以用这款小程序

可以抛弃纸质礼金簿了&#xff0c;以后登记礼金可以用这款小程序 小程序介绍使用主要技术代码来源项目演示首页和我的关于和设置收礼功能送礼功能我的家庭和数据统计 总结 大家好&#xff0c;这里是程序猿代码之路&#xff0c;先说说为什么想搞这一个小程序呢&#xff0c;主要是…