在Spring Boot中使用MyBatis访问数据库

MyBatis,这个对各位使用Java开发的开发者来说还是蛮重要的,我相信诸位在企业开发项目的时候,大多数采用的是Mybatis。使用MyBatis帮助我们解决各种问题,实际上这篇文章,基本上默认为可以跳过的一篇,但是为了Spring Boot的系列,我还是写了这篇文章。

MyBatis

作为一个在Hibernate之后出现的持久层框架,因为他支持自定义SQL,存储过程以及高级映射,MyBatis免除了几乎所有的JDBC代码,以及设置参数和获取结果集的工作。MyBatis可以通过简单的XML或者注解来配置和映射原始类型,接口,和Java POJO为数据库中记录。

MyBatis官网: https://mybatis.org/mybatis-3/zh/index.html

引入依赖

		<!--MyBatis依赖-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.1</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
        <dependency>
            <groupId>com.oracle.ojdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>19.3.0.0</version>
            <scope>compile</scope>
        </dependency>

这里说明一下,MyBatis的版本和Java JDK和Spring Boot的版本是有要求的:
2.1.x版本适用于:MyBatis 3.5+、Java 8+、Spring Boot 2.1+
2.0.x版本适用于:MyBatis 3.5+、Java 8+、Spring Boot 2.0/2.1
1.3.x版本适用于:MyBatis 3.4+、Java 6+、Spring Boot 1.5

配置Application文件

接下来,我们配置Spring Boot的自带的application配置文件:

# MySQL
#spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
#spring.datasource.username=root
#spring.datasource.password=123456
#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

server.port=1001
# Oracle
spring.datasource.url=jdbc:oracle:thin:@localhost:1521/orcl
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver

这是我的Oracle表结构:
在这里插入图片描述

MySQL表结构:

CREATE TABLE `User` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

接下来创建User表的映射对象,也是我们通用的实体类对象:

public class User {
    private Long id;
    private String name;
    private Integer age;
    
    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public User() {
    }
}

在有了实体类对象,并且和数据库的字段一一对应后,就可以在接口红定义相关对数据库表的操作了,这里举例,一个是查询,一个是插入,用于后续单元测试的验证。

@Mapper
public interface UserMapper {

    @Select("SELECT * FROM USER WHERE NAME = #{name}")
    User findByName(@Param("name") String name);

    @Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);

}

接下来创建一个单元测试类,插入一条数据,然后利用这条数据的相关属性进行查询,并且判断相关属性是否满足。
注意,测试结束后,对数据进行回滚操作,保证单元测试每次运行的数据环境独立。

@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class ApplicationTests {

    @Autowired
    private UserMapper userMapper;

    @Test
    @Rollback
    public void test() throws Exception {
        userMapper.insert("AAA", 20);
        User u = userMapper.findByName("AAA");
        Assert.assertEquals(20, u.getAge().intValue());
    }

}

对于注解配置进行说明介绍

@Mapper:用于标注Mapper接口,表示该接口是MyBatis的Mapper映射接口。在Spring Boot项目中,可以使用@MapperScan注解扫描指定包下的Mapper接口,并将其注册为Bean。

@Select:用于标注查询语句,指定SQL语句或调用Mapper XML文件中的对应SQL语句。可以通过value属性指定SQL语句,也可以通过provider属性指定动态SQL提供者类。

@Insert@Update@Delete:分别用于标注插入、更新和删除语句,使用方式与@Select类似。

@Result@Results:用于标注结果集映射关系。@Result用于标注单个字段或属性与结果集列的映射关系,@Results用于标注多个@Result。

@Param:用于标注方法参数,指定参数在SQL语句中的名称。在SQL语句中可以通过#{参数名}的方式引用该参数。

@Options:用于配置一些选项,例如设置主键生成策略、返回自增主键等。

@ResultMap:用于标注结果集映射配置的ID,可以在其他地方通过@ResultMap引用该结果集映射。

@One@Many:用于标注一对一和一对多的关联关系。

@CacheNamespace:用于开启二级缓存,将Mapper的查询结果缓存到内存中,提高查询性能。

注解使用对象相对应的 XML描述
@Insert @Update @Delete @Select 方法<insert><update><delete><select>这四个注解分别代表将会被执行的 SQL 语句。它们用字符串数组(或单个字符串)作为参数。如果传递的是字符串数组,字符串之间先会被填充一个空格再连接成单个完整的字符串。这有效避免了以 Java 代码构建 SQL 语句时的“丢失空格”的问题。然而,你也可以提前手动连接好字符串。属性有:value,填入的值是用来组成单个 SQL 语句的字符串数组。
@Options方法映射语句的属性这个注解提供访问大范围的交换和配置选项的入口,它们通常在映射语句上作为属性出现。Options 注解提供了通俗易懂的方式来访问它们,而不是让每条语句注解变复杂。属性有:useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=FORWARD_ONLY, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty="id", keyColumn="", resultSets=""。值得一提的是, Java 注解无法指定 null 值。因此,一旦你使用了 Options 注解,你的语句就会被上述属性的默认值所影响。要注意避免默认值带来的预期以外的行为。注意: keyColumn 属性只在某些数据库中有效(如 Oracle、PostgreSQL等)。请在插入语句一节查看更多关于 keyColumn 和 keyProperty 两者的有效值详情。
@MapKey方法这是一个用在返回值为 Map 的方法上的注解。它能够将存放对象的 List 转化为 key 值为对象的某一属性的 Map。属性有: value,填入的是对象的属性名,作为 Map 的 key 值。
@SelectKey方法<selectKey>这个注解的功能与 <selectKey> 标签完全一致,用在已经被 @Insert @InsertProvider@Update @UpdateProvider 注解了的方法上。若在未被上述四个注解的方法上作 @SelectKey 注解则视为无效。如果你指定了 @SelectKey 注解,那么 MyBatis 就会忽略掉由 @Options 注解所设置的生成主键或设置(configuration)属性。属性有:statement 填入将会被执行的 SQL 字符串数组,keyProperty 填入将会被更新的参数对象的属性的值,before 填入 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。resultType 填入 keyProperty 的 Java 类型和用 Statement、 PreparedStatementCallableStatement 中的 STATEMENT、 PREPARED 或 CALLABLE 中任一值填入 statementType。默认值是 PREPARED。
@Param参数N/A如果你的映射方法的形参有多个,这个注解使用在映射方法的参数上就能为它们取自定义名字。若不给出自定义名字,多参数(不包括 RowBounds 参数)则先以 “param” 作前缀,再加上它们的参数位置作为参数别名。例如 #{param1}, #{param2},这个是默认值。如果注解是 @Param(“person”),那么参数就会被命名为 #{person}。
@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider方法<insert> <update> <delete> <select>允许构建动态 SQL。这些备选的 SQL 注解允许你指定类名和返回在运行时执行的 SQL 语句的方法。(自从MyBatis 3.4.6开始,你可以用 CharSequence 代替 String 来返回类型返回值了。)当执行映射语句的时候,MyBatis 会实例化类并执行方法,类和方法就是填入了注解的值。你可以把已经传递给映射方法了的对象作为参数,“Mapper interface type” 和 “Mapper method” 会经过 ProviderContext (仅在MyBatis 3.4.5及以上支持)作为参数值。(MyBatis 3.4及以上的版本,支持多参数传入)属性有: type, method。type 属性需填入类。method 需填入该类定义了的方法名。注意 接下来的小节将会讨论类,能帮助你更轻松地构建动态 SQL。

这里就围绕@Param,Map聊聊。

@Param

我们在实际开发过程中,如果将SQL语句嵌套在接口的时候,我们经常使用的方式就是这种:

@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);

这种方式,我们都很少理解,@Param中定义的name对应了SQL中的#{name},age对应了SQL中的#{age}。

Map

除了以@Param注入,我们也可以通过Map<String,Object> 对象作为传递参数的容器:

@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name,jdbcType=VARCHAR}, #{age,jdbcType=INTEGER})")
int insertByMap(Map<String, Object> map);

得到如上代码,那么我们应该如何注入呢?

Map<String, Object> map = new HashMap<>();
map.put("name", "CCC");
map.put("age", 40);
userMapper.insertByMap(map);

如上,我们通过对map中填入同名的内容就可以实现了。

使用对象注入

除去Map方式注入值外,我们也可以直接java对象直接作为查询条件的传参,比如我们可以直接使用User对象:

@Insert("INSERT INTO USER(NAME, AGE) VALUES(#{name}, #{age})")
int insertByUser(User user);

利用MyBatis实现增删改查

MyBatis针对不同的数据库操作,分别提供了不同的注解进行配置:

public interface UserMapper {

    @Select("SELECT * FROM user WHERE name = #{name}")
    User findByName(@Param("name") String name);

    @Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
    int insert(@Param("name") String name, @Param("age") Integer age);

    @Update("UPDATE user SET age=#{age} WHERE name=#{name}")
    void update(User user);

    @Delete("DELETE FROM user WHERE id =#{id}")
    void delete(Long id);
}

之后我们可以利用创建一个Test测试类,来实现我们的功能是否正常实现:

@Transactional
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {

	@Autowired
	private UserMapper userMapper;

	@Test
	@Rollback
	public void testUserMapper() throws Exception {
		// insert一条数据,并select出来验证
		userMapper.insert("AAA", 20);
		User u = userMapper.findByName("AAA");
		Assert.assertEquals(20, u.getAge().intValue());
		// update一条数据,并select出来验证
		u.setAge(30);
		userMapper.update(u);
		u = userMapper.findByName("AAA");
		Assert.assertEquals(30, u.getAge().intValue());
		// 删除这条数据,并select验证
		userMapper.delete(u.getId());
		u = userMapper.findByName("AAA");
		Assert.assertEquals(null, u);
	}
}

返回结果绑定

对于增、删、改操作相对的数据也就变化较小,但是对于查我们就需要考虑的比较多了,怎么查,多表查,子查,并且查询的结果也不在是我们经常碰到的实体类对象了,往往需要返回一个与数据库实体不同的包装类,那么对于这样的情况,我们可以通过@Result和@Result注解进行绑定。

@Results({
    @Result(property = "name", column = "name"),
    @Result(property = "age", column = "age")
})
@Select("SELECT name, age FROM user")
List<User> findAll();

@Result中的property属性对应User对象中的成员名,column对应SELECT出的字段名。在该配置中故意没有查出id属性,只对User对应中的name和age对象做了映射配置,这样可以通过下面的单元测试来验证查出的id为null,而其他属性不为null:

@Test
@Rollback
public void testUserMapper() throws Exception {
	List<User> userList = userMapper.findAll();
	for(User user : userList) {
		Assert.assertEquals(null, user.getId());
		Assert.assertNotEquals(null, user.getName());
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

什么是代理IP池?如何判断IP池优劣?

代理池充当多个代理服务器的存储库&#xff0c;提供在线安全和匿名层。代理池允许用户抓取数据、访问受限制的内容以及执行其他在线任务&#xff0c;而无需担心被检测或阻止的风险。代理池为各种在线活动&#xff08;例如网页抓取、安全浏览等&#xff09;提高后勤保障。 读完…

使用Python的requests库采集充电桩LBS位置经纬度信息

目录 一、引言 二、采集数据的流程 1、获取充电桩的URL地址 2、发送HTTP请求获取数据 3、解析数据获取经纬度信息 4、存储数据 三、代码实现 四、注意事项和优化建议 五、充电桩数据的后续利用 六、总结 一、引言 随着电动汽车的普及&#xff0c;充电设施的建设也日…

【JavaEESpring】Spring Web MVC⼊⻔

Spring Web MVC 1. 什么是 Spring Web MVC1.1 什么是 MVC ?1.2 是什么 Spring MVC? 2. 学习 Spring MVC2.1 建立连接2.2 请求2.3 响应 3. 相关代码链接 1. 什么是 Spring Web MVC 官⽅对于 Spring MVC 的描述是这样的&#xff1a; 1.1 什么是 MVC ? MVC 是 Model View C…

OpenCV实现手势虚拟拖拽

前言&#xff1a; Hello大家好&#xff0c;我是Dream。 今天来学习一下如何使用OpenCV实现手势虚拟拖拽&#xff0c;欢迎大家一起前来探讨学习~ 一、主要步骤及库的功能介绍 1.主要步骤 要实现本次实验&#xff0c;主要步骤如下&#xff1a; 导入OpenCV库。通过OpenCV读取摄…

中文编程软件视频推荐,自学编程电脑推荐,中文编程开发语言工具下载

中文编程软件视频推荐&#xff0c;自学编程电脑推荐&#xff0c;中文编程开发语言工具下载 给大家分享一款中文编程工具&#xff0c;零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#xff0c;而且可以开发大型的软件…

使用create-react-app脚手架创建react项目

查看npx版本&#xff1a; npx -v使用如下命令创建项目时&#xff1a; npx create-react-app demo报错&#xff1a; 解决&#xff1a; 以管理员身份运行cmd 然后再次创建项目&#xff0c;又报错&#xff1a; 经查得知&#xff1a;发生此错误是因为用户名中有空格&#xff0c;…

商城免费搭建之java商城 开源java电子商务Spring Cloud+Spring Boot+mybatis+MQ+VR全景+b2b2c

1. 涉及平台 平台管理、商家端&#xff08;PC端、手机端&#xff09;、买家平台&#xff08;H5/公众号、小程序、APP端&#xff08;IOS/Android&#xff09;、微服务平台&#xff08;业务服务&#xff09; 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis 3. 前端框架…

IPv6详解

目录: 第一部分 IPv6的诞生背景和引起的主要变化 第二部分 IPv6数据报的基本首部和扩展首部 第三部分 IPv6地址 第四部分 IPv4向IPv6过渡 第一部分 IPv6的诞生背景和引起的主要变化 一.IPv6的诞生背景 IPv4存在设计缺陷: IPv4的设计者最初并没有想到该协议会在全球范围内广…

NFS文件系统共享服务器实战

架设一台NFS服务器&#xff0c;并按照以下要求配置 准备 两台Linux虚拟机一台作为服务端server&#xff0c;一台作为客户端client server IPV4&#xff1a;192.168.110.136/24 client IPV4&#xff1a;192.168.110.134/24 两台服务器都需要关闭防火墙和seLinux 服…

element-ui中el-table数据合并行和列,应该怎么解决

最近接到一个任务,要实现一个数据报表,涉及到很多合并问题,一开始想着原生会简单点,实际上很麻烦,最后还是用elemen-ui中table自带的合并方法. 最终的效果是要做成这种:1.数据处理,后端返回来的数据是,一个大对象,包含三个数组,既然合并,肯定是要处理成一个数组,并且要把相同的…

Zabbix之部署代理服务器

一、部署代理服务器 分布式监控的作用 分担server的几种式压力解决多机房之间的网络延时问题 1、搭建proxy主机 1.1 关闭防火墙&#xff0c;修改主机名 systemctl disbale --now firewalld setenforce 0 hostnamectl set-hostname zbx-proxy su1.2 设置zabbix下载源 rpm …

FreeRTOS源码阅读笔记2--list.c

list.c中主要完成列表数据结构的操作&#xff0c;有列表和列表项的初始化、列表的插入和移除。 2.1列表初始化vListInitialise() 2.1.1函数原型 void vListInitialise( List_t * const pxList ) pxList&#xff1a;列表指针&#xff0c;指向要初始化的列表。 2.1.2函数框架…

执行mysql-community-libs-8.1.0-1.el8.x86_64.rpm报错依赖检测失败

目录 1.错误信息 2.解决方法 1.错误信息 我是在VMware虚拟机18上的Centos8上的&#xff0c;安装MySQL8.1.0&#xff0c;执行mysql-community-libs-8.1.0-1.el8.x86_64.rpm报错 [rootlocalhost mysql8.1.0]# rpm -ivh mysql-community-libs-8.1.0-1.el8.x86_64.rpm 警告&…

SpringBoot前后端分离整合cas(客户端)

SpringBoot前后端分离整合cas&#xff08;客户端&#xff09; cas认证详细流程&#xff1a; 前后端分离&#xff1a;项目前端使用nginx启动&#xff0c;后端是springBoot服务&#xff1b; nginx可以统一管理Cookie&#xff0c;避免出现跨域问题。 添加依赖 <dependency&g…

C语言常见面经详细总结

1、递归函数定义没有问题&#xff0c;递归深层次后易引发什么问题&#xff1f; &#xff08;1&#xff09;影响执行效率 &#xff08;2&#xff09;栈溢出。 因为每一次调用函数是&#xff0c;栈区都要给函数分配空间&#xff0c;而且上一次调用并没有结束&#xff0c;调用的…

挑战100天 AI In LeetCode Day07(热题+面试经典150题)

挑战100天 AI In LeetCode Day07&#xff08;热题面试经典150题&#xff09; 一、LeetCode介绍二、LeetCode 热题 HOT 100-92.1 题目2.2 题解 三、面试经典 150 题-93.1 题目3.2 题解 一、LeetCode介绍 LeetCode是一个在线编程网站&#xff0c;提供各种算法和数据结构的题目&am…

2023年下半年架构案例真题及答案

案例的考点&#xff1a; 大数据架构 Lambda架构和Kappa架构 jwt特点 数据持久层&#xff0c;Redis数据丢失&#xff0c;数据库读写分离方案 Hibernat架构 SysML七个关系&#xff0c;填需求图 大数据的必选题&#xff1a; 某网作为某电视台在互联网上的大型门户入口&#…

Python高级语法----深入理解Python协程

文章目录 什么是协程?Python中的协程基本示例协程和事件循环总结Python协程是一种非常强大的并发编程概念,让你能够高效地处理多任务。协程在Python中的使用已经变得越来越流行,特别是在异步编程中。本文将用通俗易懂的语言来介绍协程的概念,并提供实际的代码示例和执行结果…

‘vite‘ is not recognized as an internal or external command

标题翻译后就是&#xff1a;‘vite‘ 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文 运行一个由 Vite 构建的 Vue3 项目&#xff0c;之前还好好的能正常跑&#xff0c; 但拉取新代码之后再次执行 npm run dev 就提示 ‘vite’ 不是内部或外部命令&#xff0…

粤嵌实训医疗项目(小组开发)--day05

目录 一、医生功能模块 ------------前端实现------------ ------------后端接口------------ 功能一&#xff1a;分页查询医生基础信息&#xff08;介绍MybatisPlus如何使用分页&#xff09; 功能二&#xff1a;根据搜索栏名称查找对应医生&#xff08;讲解自定义查询集&…