第三章springboot数据访问

本章将对springboot的数据库访问进行讲解。

3.1 springboot 数据访问概述

SpringData是spring提供的一个用于简化数据库访问,支持云服务的开源框架。能让我们快速简单地访问数据库地数据。springboot采用整合springdata的方式统一处理数据访问层,通过添加大量的自动配置,引入各种数据访问的模板,以及统一的Repository接口,从而达到简化数据访问层的操作。

springdata提供啦多种类型数据库支持,springboot对其支持的数据库进行啦整合管理,提供对应的依赖启动器,如下表:

mybatis是操作数据库的框架,springboot没有给它的场景依赖,不过mybatis自己适配啦springboot,提供:mybatis-spring-boot-starter依赖启动器,实现数据访问操作。

3.2springboot整合mybatis

mybatis是优秀的持久层框架,支持定制化sql,存储过程以及高级映射,避免啦很多麻烦。mybatis可以用简单的xml或者注解配置和映射原生信息,将接口和java的pojos(普通java对象),映射成数据库的记录。

3.2.1 基础环境搭建

springboot与数据访问框架(mybatis)的整合非常简单,引入对应的依赖启动器,并且进行数据库相关参数设置就可以啦。下面我们来实操看:
1.数据准备

我们先新建springbootdata数据库,数据库里创建t_article和t_coomment,并且插入测试数据:

create DATABASE springbootdata;
USE springbootdata;
#创建t_article并插入相关数据
DROP TABLE IF EXISTS t_article;
#构建表t_article
CREATE TABLE t_article(
id int(20) NOT NULL AUTO_INCREMENT cOMMENT '文章id',
title varchar(200) DEFAULT NULL COMMENT '文章标题',
content longtext COMMENT '文章内容',
PRIMARY KEY(id)
)ENGINE=InnODB AUTO_INCREMENT=2 DEFAULT CHARSET=UTF8;

INSERT INTO t_article VALUES('1','Spring Boot基础入门','从入门到精通讲解.');
INSERT INTO t_article VALUES('2','Spring Cloud基础入门','从入门到精通讲解..');

#构建表t_comment
CREATE TABLE t_comment(
id int(20) NOT NULL AUTO_INCREMENT COMMENT '评论i',
content longtext COMMENT '评论内容',
author varchar(200) DEFAULT NULL COMMENT '评论作者',
a_id int(20) DEFAULT NULL COMMENT '关联的文章id',
PRIMARY KEY(id)
)ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO t_comment VALUES ('1','很全、很详细','狂奔的蜗牛','1');
INSERT INTO t_comment VALUES ('2','赞一个','tom','1');
INSERT INTO t_comment VALUES ('3','很详细','tom2','1');
INSERT INTO t_comment VALUES ('4','赞','张山','1');
INSERT INTO t_comment VALUES ('5','很不错','张扬','2');

2创建项目引入对应的启动器

创建springboot项目时,选中依赖启动器:mysql和mybatis,springweb。

编写数据库的实体类:

package com.waiguoyu.chapter02.domain;

public class Comment {
    private String content;
    public Integer id;
    public Integer aId;
    private String author;

    @Override
    public String toString() {
        return "Comment{" +
                "content='" + content + '\'' +
                ", id=" + id +
                ", aId=" + aId +
                ", author='" + author + '\'' +
                '}';
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getaId() {
        return aId;
    }

    public void setaId(Integer aId) {
        this.aId = aId;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

package com.waiguoyu.chapter02.domain;

import java.util.List;

public class Article {
    private Integer id;
    private String title;
    private String content;
    
    private List<Comment> commentsList;

    @Override
    public String toString() {
        return "Article{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", content='" + content + '\'' +
                ", commentsList=" + commentsList +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public List<Comment> getCommentsList() {
        return commentsList;
    }

    public void setCommentsList(List<Comment> commentsList) {
        this.commentsList = commentsList;
    }
}

这两个类中的属性分别对应数据库表中的字段。

3.编写配置文件

在全局配置文件中编写对应的mysql数据库连接配置:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springbootdata?useUnicode=true&characterEncoding=utf8
//数据库账号密码吗
spring.datasource.username=root
spring.datasource.password=root

这里的账号密码是 自己电脑数据库的账号密码。

数据库源选择配置:这里使用阿里巴巴的Druid数据源。引入启动依赖:

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.8</version>
        </dependency>

这个数据源启动器已经初始化啦一些运行参数,如果需要修改运行参数,要在配置文件中需改:

#添加并配置第三方数据源
spring.datasource,type = com.alibaba.druid.pool.DruidDataSource
spring.datasource.initialSize=20
spring.datasource.minIdle=10
spring.datasource.maxActive=100

上面实例啦修改数据源的:类型,初始化连接数,最小空闲数,最大连接数属性。如果需要修改其他的可以参照这样修改。

添加上述配置之后,springboot无法识别,需要编写自定义配置类,将这些属性注入到Druid数据源属性中。

注入方式完成啦第二章的目标就可以会啦:

import com.alibaba.druid.pool.DruidDataSource;
import com.waiguoyu.chapter02.mapper.CommentMapper;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration//标识该类为配置类,相当于创建啦xml配置文件
public class DataSourceConfig {

    @Bean//向xml文件里面注入一个实例对象
    @ConfigurationProperties(prefix = "spring.datasource")//将全局配置文件中以spring.datasouce开头的注入到 该方法的 返回的 对象的属性中
    public DataSource getDataSource() {
        return new DruidDataSource();

    }


}

上边不配置这些操作也可以进行,只是为啦模拟实际开发而已。

3.2.2 使用注解的方式整合mybatis

上面是环境搭建,在这里才是整合。

第一步:创建Mapper接口文件:

创建mapper包,然后创建对数据库表进行数据操作的接口:CommentMapper,

import com.waiguoyu.chapter02.domain.Comment;
import org.apache.ibatis.annotations.*;


@Mapper//标识该类是mybatis接口文件,并且保证springboot能够扫描到它
public interface CommentMapper {
    //接口内部通过注解和sql语句完成对表的增删改查

    @Select("SELECT * FROM t_comment WHERE id= #{id}")
    public Comment findById(Integer id);
    @Insert("INSERT INTO t_comment(content,author,a_id)" + "values (#{content},#{author},#{aId})")
    public int insertComment(Comment comment);
    @Update("UPDATE t_comment set content = #{content} WHERE id = #{id}")
    public int updateComment(Comment comment);
    @Delete("DELETE FROM t_comment WHERE id=#{id}")
    public int deleteComment(Integer id);

}

注意:如果接口或者业务过多,需要重复添加大量的@Mapper注解,我们可以在sprin gboot启动类上添加:@MapperScan("xxx")注解,这样就不需要逐个添加@Mapper注解啦。xxx表示需要指定的具体包名。例如:

第二步:编写单元测试进行接口测试

在测试类引入Cm+ommentMapper接口,测试如下:

package com.waiguoyu.chapter02;

import com.waiguoyu.chapter02.domain.Comment;
import com.waiguoyu.chapter02.mapper.CommentMapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
class Chapter02ApplicationTests {

    @Test
    void contextLoads() {
    }
    @Autowired
    private CommentMapper commentMapper;

    @Test
    public void slectCommenttest(){
        Comment comment = commentMapper.findById(1);
        System.out.println(comment);
    }
}

到这里就映入成功啦。

测试结果有一个数据没有映射成功,因为编写的实体类那个属性使用驼峰命名法,将数据表中的a_id设计成啦aId属性,所有无法正常映射。解决这个问题:

在springboot全局配置文件添加驼峰命名匹配映射配置就可以啦:

#开启驼峰命名匹配映射
mybatis.configuration.mapUnderscoreToCamelCase=true

3.2.3 使用配置文件的方式整合Mybatis

通过案例来演示如何使用配置文件xml的方式整和mybatis

1.创建Mapper接口文件,用于操作数据库表:t_article

import com.waiguoyu.chapter02.domain.Article;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface ArticleMapper {
    //查询数据
    public ArticleMapper selectArticle(Integer id);

    //更新数据操作
    public int updataArticle(Article article);
}

这里声明啦查询和更新操作两个方法。

2.创建xml文件,创建一个统一映射文件ArticleMapper.xml:

这里是mybatis映射文件中的具体写法,详细请看mybaits官方文档。

3.配置xml映射文件路径:

上面的xml文件springboot无法扫描到,需要在全局配置文件里面添加这个映射文件路径的配置,同时还要添加实体类别名映射路径:

如果xml文件里面映射文件中实体类的数据映射配置,使用的是全路径名称,就不需要配置别名路径。

4.编写测试类进行测试:

实际开发中会混合使用这两种整合mybatis的方式。

3.3 springboot整合jpa

jpa:java持久化api,持久化规范,它提供:对象/关系映射 的 工具,管理java中的关系型数据库。

目的:简化持久化开发工作,整合orm(对象/关系映射)技术。

3.3.1 springData jap介绍

它是spring在Orm框架和jpa规范的基础上封装的一套jpa应用框架,让开发者用较少的代码完成数据的操作。我们先熟悉spring data jpa 的基本使用进行简单介绍

1.编写orm实体类

使用实体类前先编写实体类和数据表进行映射,并配置好映射关系,应为spring data jpa针对orm关系的数据进行的操作。

2.编写Repository接口

根据不同的 表数据操作 编写对应的Repository接口,并且根据需求编写对应的数据操作方法。

package com.waiguoyu.chapter02.mapper;


import com.waiguoyu.chapter02.domain.Discuss;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

public interface DiscussRepository extends JpaRepository<Discuss, Integer> {

    //基本的查询方法,不用注解,方法名是jpa支持的 方法名关键字 查询方法,方法的作用:查询author非空的Discuss数据
    public List<Discuss> findByAuthorNotNull();


    //该方法通过@Query注入sql语句,用于通过分页查询,查询discuss数据
    @Query("SELECT c from t_comment c where c.aId=?1")
    public List<Discuss> getDiscussPaged(Integer aid, Pageable pageable);


    //与上面的方法同,nativeQuery = true 用来定义:编写原生的sql语句,
    @Query(value = "SELECT * from t_comment where c.aId=?1",nativeQuery = true)
    public List<Discuss> getDiscussPaged2(Integer aid, Pageable pageable);



    @Transactional//支持事务管理,也就是要么都成功,如果更新数据不成功就退回全部操作,防止数据的丢失
    @Modifying//支持数据变更
    //通过注解注入sql语句,更新和删除需要配合使用上面两个注解。
    @Query("update t_comment c set c.author = ?1 where c.id=?2")
    public int updateDiscuss(String author,Integer id);

    @Transactional
    @Modifying
    @Query("delete t_comment c where c.id=?1")
    public int deleteDiscuss(Integer id);


}

下面对编写这种Repository接口进行具体的讲解:

1.编写这类接口时,必须继承 XXRepository<T,ID>接口,T:表示要操作的实体类,ID表示实体类的主键的类型。上面的案例继承啦:JpaRepository接口。

下面讲解JpaRepository继承结构中的涉及到的接口:

1.repository接口没有方法,是spring Data JPA提供的用于自定义repository接口的顶级父接口。

2.CrudRepository接口:继承啦repository接口,包含一些基本的CRUD方法(比如)

3.PagingAndSortingRepository 接口继承CrudRepository接口,并且提供啦分页和排序两个方法。

4.QueryByExampleExecutor接口:能够进行条件封装查询,能通过Example实例执行复杂的条件查询。

5.JpaRepository接口:同时继承PagingAndSortingRepository 接口和QueryByExampleExecutor接口,并且还拥有一些数据操作方法,自定义Repository接口文件时一般会直接继承JpaRepository接口。

简而言之就是:JpaRepository接口接口有:一些基本的CRUD方法,分页和排序两个方法。能够进行条件封装查询,能通过Example实例执行复杂的条件查询。

使用springdatajpa进行数据操作时,可以有多种实现方式,下面进行说明:

下图就是对应的springData Jpa中支持的方法名关键字对应的sql语句:

在自定义的Repository接口方法中,数据变更的操作方法上必须使用那两个注解(代码案例讲解那),不然会报错,如果在调用Repository接口的方法的service类上已经添加啦事务处理的注解

就不用在Repository接口上添加啦。

jpa还支持使用Example实例进行复杂的条件查询,spring Data Jpa的基本使用进行了解,详细可以去官方文档进行学习。

3.3.2 使用springboot整合jpa

了解完jpa之后,我们具体来整合jpa

1.在pom文件添加其依赖:

 <!--springdatajpa的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

2.编写ORM实体类:

package com.waiguoyu.chapter02.domain;


import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import org.springframework.data.annotation.Id;




//定义springboot data jpa 实体类,将该类与数据库表进行映射

@Entity(name="t_comment")//标注一个 与数据库做映射的 实体类,用name属性指定映射的数据库表
public class Discuss {
    @Id//可以用在类属性或者get方法上,用于绑定数据库表的主键
    @GeneratedValue(strategy = GenerationType.AUTO)//与@id一起使用,确定主键的生成策略,比如TABLE;用一个特定的数据库表格来保存主键
    // IDENTITY:主键自增,SEQUENCE:不支持主键自增的主键的生成策略,AUTO:由jpa自主选择前三个策略中的一个
    private Integer id;
    private String content;
    private String author;

    @Column(name = "a_id")//标注属性,当类属性和数据库表的对应字段名字不一样,就是用它来绑定
    private Integer AId;

    @Override
    public String toString() {
        return "Discuss{" +
                "id=" + id +
                ", content='" + content + '\'' +
                ", author='" + author + '\'' +
                ", AId=" + AId +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public Integer getAId() {
        return AId;
    }

    public void setAId(Integer AId) {
        this.AId = AId;
    }
}

3.编写respositry接口,类同上边得案例。

4.编写单元测试:

5.整体得测试:

3.4springboot整合redis

非关系型数据库的整合。

3.4.1redis介绍

redis介绍另看文章,接下来就i安装redis。

redis只需要解压缩好文件,运行redis-server.exe就启动可以啦。

再去下载redis desktop manager客户端连接用户端就可以啦。打开客户端根据下面的操作进行即可。

3.4.2 使用springboot整合redis

1.添加springbootdataredis依赖:

  <!--redis的依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

2.编写对应的实体类:

package com.waiguoyu.chapert03.domain;



import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import org.springframework.data.redis.core.index.Indexed;

import java.util.List;

@RedisHash("persons")//指定操作实体类在redis数据库中的存储空间,该类的数据操作都存储在redis数据库中名为persons的存储空间下
public class Person {
    @Id //标识实体类主键。也可以在数据存储时指定id
    private String id;
    @Indexed //标识对应属性在redis数据库中生成二级索引。索引名称就是属性名
    private String firstname;
    @Indexed
    private String lastname;
    private Address address;
    private List<Family> familyList;

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", firstname='" + firstname + '\'' +
                ", lastname='" + lastname + '\'' +
                ", address=" + address +
                ", familyList=" + familyList +
                '}';
    }

    public Person() {
    }

    public Person(String id, String firstname, String lastname, Address address, List<Family> familyList) {
        this.id = id;
        this.firstname = firstname;
        this.lastname = lastname;
        this.address = address;
        this.familyList = familyList;
    }

    public String getId() {
        return id;
    }

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

    public List<Family> getFamilyList() {
        return familyList;
    }

    public void setFamilyList(List<Family> familyList) {
        this.familyList = familyList;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }
}

import org.springframework.data.redis.core.index.Indexed;

public class Family {
    @Indexed
    private String type;
    @Indexed
    private String username;
省略get,set,构造函数,以及tostring

public class Address {
    @Indexed
    private String city;
    @Indexed
    private String country;

3.编写Repository接口:

springboot给常用数据库提供啦一些自动化配置,

这些操作与上一节的一样。可以使用方法名关键字进行数据操作。

package com.waiguoyu.chapert03.repository;

import com.waiguoyu.chapert03.domain.Person;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;

import java.util.List;
//继承的CrudRepository接口定义啦很多查询方法,jpaRepository是springboot的jpa特有的,如果想使用这个接口操作redis数据库,可以同时导入redis和
//jpa依赖。
public interface PersonRepository extends CrudRepository<Person, Long> {
    List<Person> findByLastName(String lastName);
    Page<Person> findPersonByLastName(String lastName, Pageable page);
    List<Person> findByFirstNameAAndLastname(String firstName, String lastName);
    List<Person> findByAddress_City(String city);
    List<Person> findByFamilyList_Username(String username);
    
}

4.连接redis数据库:

在配置文件配置信息:

复制代码
#服务器连接密码默认为空
spring.data.redis.password=
#redis服务器地址
spring.data.redis.host=localhost
#连接的端口号
spring.data.redis.port=6379

也可以单独添加相关配置,跟之前的一样。

4.编写单元测试进行测试:

@Autowired
    private PersonRepository personRepository;
    @Test
    public void savePerson() {
        Person person = new Person("张","有才");
        Person person1 = new Person("张","有才123");
        Address address=new Address("北京","chinen");
        person.setAddress(address);
        //创建并添加家庭成员
        List<Family> families=new ArrayList<>();
        Family fan=new Family("父亲","母亲");
        families.add(fan);
        person.setFamilyList(families);
//        向redis数据库添加数据
        Person save=personRepository.save(person);
        Person save2=personRepository.save(person1);
        System.out.println(save);
        System.out.println(save2);

    }
bug:我这里打的代码连接不上redis数据库。

目前就是redis整合springboot以及进行数据库操作的方式啦。想了解更多redis知识请看官方文档。

3.5 本章小结

相关推荐
代码调试1 小时前
Springboot校园失物招领平台
java·spring boot
静水楼台x1 小时前
springboot参数校验
spring boot
camellias_2 小时前
SpringBoot(二十三)SpringBoot集成JWT
java·spring boot·后端
tebukaopu1482 小时前
springboot如何获取控制层get和Post入参
java·spring boot·后端
昔我往昔2 小时前
SpringBoot 创建对象常见的几种方式
java·spring boot·后端
武昌库里写JAVA2 小时前
机器学习笔记2 - 机器学习的一般流程
spring boot·spring·毕业设计·layui·课程设计
q567315232 小时前
用 PHP或Python加密字符串,用iOS解密
java·python·ios·缓存·php·命令模式
啊松同学3 小时前
【Java】设计模式——工厂模式
java·后端·设计模式
枫叶_v3 小时前
【SpringBoot】20 同步调用、异步调用、异步回调
java·spring boot·后端