Spring Boot访问数据库

news2024/11/25 2:50:08

SpringBoot访问数据库时,我们可以使用以下三种,JdbcTemplate、Spring Boot Data Jpa、mybatis。

JdbcTemplate是Spring自己提供的,但是其操作不方便,甚至有些繁琐,在实际应用中也是很少会使用,所以这里就不过多介绍了,感兴趣的小伙伴可以自行百度了解。

Spring Boot Data Jpa是基于Hibernate框架来实现的,Hibernate是一个全自动的框架,曾经也和mybatis一样流行,不过Hibernate不方便自定义sql,这便使得其无法满足如今的互联网环境,所以也是渐渐没落了,所以这里也是不过多介绍了,感兴趣的小伙伴可以自行百度了解。

mybatis是一个半自动框架,需要开发者自定义sql,这也使得其可以开发出性能很高的应用,所以现在它也已经成为了目前Java持久层最流行的框架,所以我们这个篇章主要介绍Spring Boot中关于mybatis的使用。

Spring Boot整合Mybatis框架

Spring Boot的默认配置中是不包含mybatis框架的,但是mybatis开发社区自己开发了Spring Boot的启动包。
首先,我们在项目中添加mybatis的依赖以及mysql数据库的依赖,如下所示:

		<!--mysql数据库依赖-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--mybatis依赖-->
        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>

这样,我们就可以在项目中使用mysql数据库以及mybatis框架了。

mybatis的配置

mybatis框架的配置文件主要包括两大部分,一个是基础配置文件,还有一个就是映射文件。其中映射文件也可以通过注解的方式配置,但是因为注解的功能以及可读性的限制,所以这里我们不采用注解的方式,而是采用xml方式来处理映射文件。

mybatis操作的核心是SqlSession接口对象,它是由SqlSessionFactory对象来创建的,SqlSessionFactory这个对象的作用也就是为了创建SqlSession接口对象,作用单一,所以在mybatis应用的生命周期中应该只存在一个SqlSessionFactory对象,并且一般都会使用单例模式。

构建SqlSessionFactory对象是需要通过配置类Configuration来完成的,可以在Spring Boot的application.properties文件中配置。下面让我们来看看都可以配置哪些内容。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

mybatis别名的使用

为了避免在mybatis的映射文件中书写POJO类的全限定名称(很长,不方便),mybatis提出了别名的概念,就是在mybatis的世界中,给某个POJO类取一个别名,这样mybatis就可以根据这个别名来找到对应的POJO类了。
首先我们创建一个User类,并且采用@Alias注解设置其别名为“user”,代码如下:

@Data
@Accessors(chain = true)
@Alias("user")
public class User {

    private Long id;

    private String userName;

    private SexEnum sex;

}

自定义typeHandler

注意,性别这里,我们采用了枚举类型,所以需要对这个属性开发我们自己的typeHandler来完成从数据库到POJO类的转换,代码如下:

@MappedJdbcTypes(value = JdbcType.INTEGER)
@MappedTypes(value = SexEnum.class)
public class SexTypeHandler extends BaseTypeHandler<SexEnum> {
    /**
     * 设置非空性别参数
     */
    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, SexEnum sexEnum, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, sexEnum.getSex());
    }

    /**
     * 根据列名读取性别
     */
    @Override
    public SexEnum getNullableResult(ResultSet resultSet, String s) throws SQLException {
        int sex = resultSet.getInt(s);
        return SexEnum.getBySex(sex);
    }

    /**
     * 根据下标读取性别
     */
    @Override
    public SexEnum getNullableResult(ResultSet resultSet, int i) throws SQLException {
        int sex = resultSet.getInt(i);
        return SexEnum.getBySex(sex);
    }

    /**
     * 根据存储过程读取性别
     */
    @Override
    public SexEnum getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return null;
    }
}

在mybatis中,对于typeHandler的要求是需要实现TypeHandler接口,而抽象类BaseTypeHandler也是实现了TypeHandler接口,并且还扩展了其他功能,所以这里我们直接继承抽象类BaseTypeHandler即可。

另外,我们用@MappedJdbcTypes(value = JdbcType.INTEGER)注解设置了性别属性在数据库中的类型,@MappedTypes(value = SexEnum.class)注解设置性别属性在POJO类中的类型。这样,它们就可以互相转换了。

配置映射文件

下面我们创建映射文件UserMapper.xml,内容如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzm.mapper.UserMapper">

    <select id="getById" parameterType="long" resultType="user">
        select id,user_name as userName,sex from zzm_sp_learn_user_info where id = #{id}
    </select>
</mapper>

namespace中对应的com.zzm.mapper.UserMapper接口如下:

@Repository
public interface UserMapper {
    User getById(long id);
}

有了上面的内容,我们在application.properties文件中添加以下配置:

#mybatis映射文件位置配置
mybatis.mapper-locations=classpath:mapper/*.xml
#mybatis扫描别名的包,和@Alias注解联合使用
mybatis.type-aliases-package=com.zzm.pojo
#mybatis的typehandler扫描包配置
mybatis.type-handlers-package=com.zzm.typehandler

#日志配置
logging.level.root=DEBUG
logging.level.org.springframework=DEBUG
logging.level.org.org.mybatis=DEBUG

将日志级别设置为DEBUG是为了方便调试。

对于mybatis的配置到这里就可以了,mybatis-spring-boot-starter已经提供了其他的默认配置,所以这里我们只需要修改我们需要的配置即可,这便是Spring Boot的魅力,以最少的配置进行开发。
下面我们一起看看怎么在Spring Boot中整合它。

Spring Boot中整合mybatis

Spring Boot装配mybatis接口主要有以下几种方式:

  • MapperFactoryBean 针对于一个接口配置
  • MapperScannerConfigurer 扫描装配
  • @MapperScan 扫描装配,和@Repository注解配合使用(相比前两种,这个更加简便,所以实际应用中推荐用这个)
  • @Mapper

下面让我们依次看一下这几种的使用。

MapperFactoryBean

MapperFactoryBean一次只能向SpringBoot装配一个mybatis接口,所以这里只是简单介绍。用法如下:

@Bean
    public MapperFactoryBean<UserMapper> initUserMapper(){
        MapperFactoryBean<UserMapper> mapperFactoryBean = new MapperFactoryBean<>();
        mapperFactoryBean.setMapperInterface(UserMapper.class);
        mapperFactoryBean.setSqlSessionFactory(sqlSessionFactory);

        return mapperFactoryBean;
    }

MapperScannerConfigurer

实际中,我们的mybatis接口不可能只有一个,而这个类可以配置mybatis接口的扫描规则,实现批量装配的效果。用法如下:

@Bean
    public MapperScannerConfigurer mapperScannerConfigurerInit(){
        MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
        mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        mapperScannerConfigurer.setBasePackage("com.zzm.*");
        mapperScannerConfigurer.setAnnotationClass(Repository.class);

        return mapperScannerConfigurer;
    }

如代码所示,我们配置了mybatis接口的装配规则如下:

  • 扫描的包路径为“com.zzm.*”;
  • 只有被@Repository注解修饰的接口才会被装配;

@MapperScan 扫描装配

@MapperScan 它是MapperScannerConfigurer 的注解版本,因为SpringBoot推荐使用注解开发,所以这里也推荐大家实际应用中使用这个。
用法如下:

@SpringBootApplication
@Slf4j
@MapperScan(basePackages = {"com.zzm.*"}, annotationClass = Repository.class)
public class Application {
	......
}

这里配置的扫描规则和MapperScannerConfigurer配置的是一样的。

@Mapper

这个注解和@Repository注解功能都是一样的,都是将mybaits的接口交由Spring管理,但是相比于@Repository注解,@Mapper注解更加方便。

使用时,仅需要用@Mapper注解修饰需要装配的mubaits接口就可以了,不再需要上述的配置,如下所示:

@Mapper
public interface UserMapper {
    User getById(long id);
}

@SpringBootApplication
@Slf4j
public class Application {
	.......
}

关于@Repository和@Mapper的区别,可参考如下:

@Repository@Mapper
Spring提供的注解mybatis提供的注解
需要配置扫描地址不需要配置扫描地址,通过xml里面的namespace里面的接口地址,生成了Bean后注入到Service层中

接下来我们创建测试controller和service(这两个很简单,这里就不过多介绍了),访问测试地址,可以看到效果如下:
在这里插入图片描述
数据库中的数据如下:
在这里插入图片描述
细心的小伙伴可能已经发现,用户信息中的性别属性值,在我们调用接口查询时自动转换成了枚举类型,而这个工作就是我们前面配置的自定义类型转换器SexTypeHandler 实现的。
而此时的mybatis映射文件中也需要配置我们的自定义类型转换器,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zzm.mapper.UserMapper">

    <resultMap id="baseMap" type="user">
        <result column="id" property="id" javaType="long" jdbcType="BIGINT"/>
        <result column="user_name" property="userName" javaType="String" jdbcType="VARCHAR"/>
        <result column="sex" property="sex" javaType="sexEnum" jdbcType="SMALLINT" typeHandler="sexTypeHandler"/>
    </resultMap>

    <select id="getById" parameterType="long" resultMap="baseMap">
        select id,user_name,sex from zzm_sp_learn_user_info where id = #{id}
    </select>
</mapper>

mybatis插件

这里我们介绍一下mybatis的插件机制。比如我们如果想在保存或者更新用户信息时,想同时更新对应的创建时间、更新时间、创建人、更新人等信息,那需要怎么做呢?

当然,我们可以在代码中或者sql中完成这个工作,但是如果有很多不同类的数据也需要保存这些信息呢?比如学校信息、课程信息、学生信息…等,如果每个类都要在代码中或者sql中完成这个工作,那无疑会造成大量的重复代码。
所以针对于这个场景,我们就可以采用mybatis的插件机制来完成了。
首先我们在用户表中添加更新人和更新时间两个字段,它俩会在用户信息新增或者保存时同步更新。
在这里插入图片描述

定义一个mybatis插件

接下来我们定义一个mybatis插件:

@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class,Object.class})
})
@Slf4j
public class MyPlugin implements Interceptor {

    Properties properties;

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.warn("插件拦截方法......");
        for(Object obj : invocation.getArgs()){
            if(obj instanceof User){
                User user = (User) obj;
                user.setUpdatedBy(123456L);
                user.setUpdateTime(new Date());
            }
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

这里我们设置了拦截mybatis的update方法(即数据的保存和更新都会被拦截到),并且将方法的参数也传了进来。
在方法intercept中,我们拦截了user对象,并且将其更新时间和更新人分别赋值,这样,mybatis在保存数据到数据库时,也会将更新时间和更新人同步保存。

注册插件到Spring

定义好了插件,还需要将其注册到Spring容器中,注册代码如下:

@SpringBootApplication
@Slf4j
public class Application {

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        log.warn("启动成功......");
    }

    @PostConstruct
    public void initMybatis(){
        Interceptor plugin = new MyPlugin();
        Properties properties = new Properties();
        properties.setProperty("k1","v1");
        properties.setProperty("k2","v2");
        properties.setProperty("k3","v3");

        plugin.setProperties(properties);

        sqlSessionFactory.getConfiguration().addInterceptor(plugin);
    }

可以看到,我们在注册插件时,还传递了k1,k2,k3三个属性值,这样,我们就可以在插件中使用这三个值了

最后,启动应用,访问测试接口,测试效果如下:
在这里插入图片描述

在这里插入图片描述
好了,今天就先到这里了,眼过千遍不如手过一遍,赶紧去自己尝试一下吧。。。。拜拜

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

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

相关文章

使用MobaXterm在Windows系统远程Ubuntu系统

使用场景 通常大部分办公软件都安装在Windows系统上&#xff0c;使用Windows系统办公更便捷&#xff0c;并且大多办公软件在Ubuntu系统上不兼容&#xff0c;即使进行处理&#xff0c;使用体验也不好&#xff0c;下面针对在同一局域网使用Windows远程Ubnuntu进行ssh、VNC和打开…

Nature -- 空间表观组学与转录组学联合分析,揭示基因表达的精准调控

为充分理解组织中单细胞的基因表达调控&#xff0c;需要在单细胞水平以空间分辨率的方式集成不同分子信息的不同层面&#xff0c;包括表观基因组和转录组数据。虽然单细胞多组学方法可以捕捉来自不同分子层的信息&#xff0c;但是空间组学方法到目前为止主要局限于一层分子。张…

MATLAB的无人机遥感数据预处理与农林植被性状估算实践

在新一轮互联网信息技术大发展的现今&#xff0c;无人机、大数据、人工智能、物联网等新兴技术在各行各业都处于大爆发的前夜。为了将人工智能方法引入农业生产领域。首先在种植、养护等生产作业环节&#xff0c;逐步摆脱人力依赖&#xff1b;在施肥灌溉环节构建智慧节能系统&a…

ASP.NET core WebApi Cors跨域解决

前言 我用了最新版的Asp.net webapi &#xff0c;在csdn上面搜跨域如何解决的时候&#xff0c;发现csdn上面对于.NET技术讨论不是很多。没办法&#xff0c;只能面向官方文档和GitHub编程了。 项目类型确认 NuGet包引入 前面两个已经放弃维护了&#xff0c;我们就不用了。用最…

使用Actor-Critic的DDPG强化学习算法控制双关节机械臂

在本文中&#xff0c;我们将介绍在 Reacher 环境中训练智能代理控制双关节机械臂&#xff0c;这是一种使用 Unity ML-Agents 工具包开发的基于 Unity 的模拟程序。 我们的目标是高精度的到达目标位置&#xff0c;所以这里我们可以使用专为连续状态和动作空间设计的最先进的Deep…

【uni-app】errMsg : navigateTo:fail can not navigateTo a tabbar page报错解决方案

文章目录 前言一、报错二、解决方案更改api 总结 前言 大家好&#xff0c;今天在进行uni-app项目开发时&#xff0c;在进行页面跳转的时候报了一个错误&#xff0c;一开始觉得只是个小报错就没有仔细看这个报错&#xff0c;直接就到页面检查看是不是跳转没写好&#xff0c;但是…

Spring IOC:详解【依赖注入数值问题 依赖注入方式】

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 Maven版本&#xff1a;apache-maven-3.6.3 Mybatis版本&#xff1a;3.5.6 spring版本&#xff1a;5.3.1 文章目录 Spring系列专栏文章目录一、Spring依赖注入数值问题1.1 字面量数值问…

计算机网络 | 广播与组播

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

Jetpack之livedata原理分析

1.LiveData是什么&#xff1f; 只有在生命周期处于started和resumed时。livedata才会更新观察者 2.Livedata的各种使用方式 1.更新数据 class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceSta…

Python数据分析实战【十四】:python的三种排序方法:sort、sorted、sort_values案例学习【文末源码地址】

文章目录 一、List.sort()排序案例一&#xff1a;按照列表中的元素进行排序案例二&#xff1a;按照销售额数据进行排列 二、sorted()排序案例一&#xff1a;sorted()对列表进行排序案例二&#xff1a;sorted()对字典进行排序案例三&#xff1a;sorted()对列表中的字典元素排序 …

【AI大模型】国产AI技术再创新高,讯飞星火认知大模型中文能力已经超越ChatGPT?

文章目录 前言SparkDesk讯飞星火认知大模型简介语言理解知识问答逻辑推理数学题解答代码理解与编写亲自体验写在最后 前言 5月6日&#xff0c;讯飞星火认知大模型成果发布会在安徽合肥举行。科大讯飞董事长刘庆峰、研究院院长刘聪发布讯飞星火认知大模型&#xff0c;现场实测大…

(一)ArcGIS空间数据的转换与处理——投影变换

ArcGIS空间数据的转换与处理——投影变换 原始数据往往由于在数据结构、数据组织、数据表达等方面与用户需求不一致而要进行转换与处理。本节主要介绍 ArGIS 中数据的投影变换内容。 目录 ArcGIS空间数据的转换与处理——投影变换 1.概述2.定义投影3.投影变换3.1栅格数据的投…

Python数据分析实战【十四】:Python的三种排序方法:sort()、sorted()和sort_values()【文末源码地址】

文章目录 一、List.sort()排序案例一&#xff1a;按照列表中的元素进行排序案例二&#xff1a;按照销售额数据进行排列 二、sorted()排序案例一&#xff1a;sorted()对列表进行排序案例二&#xff1a;sorted()对字典进行排序案例三&#xff1a;sorted()对列表中的字典元素排序 …

计算机网络 | 基于TCP的C/S模型代码实现

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和…

QT QGraphicsView 提升到 QChartView报错 解决方案

QT QGraphicsView 提升到 QChartView报错 解决方案 本文主要描述, 使用QT提供的QChartView来绘制图表,提升QGraphicsView控件继承QChartView后,然后将QGraphicsView提升到我们自己写的类,怎么才能确保提升后编译不报错. [问题描述] 使用QGraphicsView显示图表的时候,我们需要将…

基于Leaflet的乡镇行政区划在WebGIS中的可视化工具实践

前言 在构建WebGIS的应用系统中&#xff0c;通常会遇到以下的建设需求。功能点如下&#xff1a; 实现影像地图的展示&#xff0c;可以放大、缩小和浏览地图。地图的拖拽范围需要控制在合理的经纬度范围内。在影像地图侧边实现某乡镇级行政区的信息展示&#xff0c;包括名称&…

Java中的深拷贝和浅拷贝

目录 &#x1f34e;引出拷贝 &#x1f34e;浅拷贝 &#x1f34e;深拷贝 &#x1f34e;总结 引出拷贝 现在有一个学生类和书包类&#xff0c;在学生类中有引用类型的书包变量&#xff1a; class SchoolBag {private String brand; //书包的品牌private int size; //书…

使用Vue+vue-router+路由守卫实现路由鉴权功能实战

目录 一、本节介绍和上节回顾 1. 上节介绍 2. Vue + SpringBoot前后端分离项目实战的目录

探秘C语言:字符分类与转换函数,让你的程序更加精准和优美

本篇博客会讲解C语言ctype.h这个头文件中的2类好用的库函数&#xff0c;分别是字符分类函数和字符转换函数。 字符分类函数 字符分类函数&#xff0c;指的是判断一个字符是不是属于某个类别&#xff0c;如果属于这个类别&#xff0c;返回非0数&#xff1b;如果不属于这个类别…

MGA元宇宙创世大会 中国2022

MGA元宇宙创世大会 中国2022 主办方:MGA元宇宙创世联盟 协办方&#xff1a;增强现实核心技术产业联盟 元宇宙创世大会中国2022将包含两场主题峰会&#xff0c;一个是虚拟现实与增强现实峰会&#xff0c;一个是NFT与区块链峰会。涵盖元宇宙最重要的两大支撑技术&#xff08;VR/…