本章将对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;@Overridepublic 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;@Overridepublic 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 {@Testvoid contextLoads() {}@Autowiredprivate CommentMapper commentMapper;@Testpublic 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;@Overridepublic 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 //标识实体类主键。也可以在数据存储时指定idprivate String id;@Indexed //标识对应属性在redis数据库中生成二级索引。索引名称就是属性名private String firstname;@Indexedprivate String lastname;private Address address;private List<Family> familyList;@Overridepublic 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 {@Indexedprivate String type;@Indexedprivate String username;
省略get,set,构造函数,以及tostring
public class Address {@Indexedprivate String city;@Indexedprivate 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.编写单元测试进行测试:
@Autowiredprivate PersonRepository personRepository;@Testpublic 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知识请看官方文档。