学习SpringBoot
数据层解决方案
SQL
数据源技术
Spring Boot 提供了多种内嵌数据库支持,主要特点:
- 无需安装独立数据库
- 配置简单
- 启动快速
- 数据存储在内存中
常用内嵌数据源连接池技术
1. HikariCP(默认,推荐)
特点
- Spring Boot 2.x 默认连接池
- 性能最优
- 轻量级
- 稳定可靠
2. Tomcat JDBC Connection Pool
特点
- Spring Boot 1.x 默认连接池
- 性能稳定
- 功能完善
- 与 Tomcat 集成度高
3. Commons DBCP2
特点
- Apache 基金会维护
- 历史悠久
- 稳定可靠
- 配置灵活
持久化技术
1. JDBC (Java Database Connectivity)
1.1 基本概念
JDBC 是 Java 访问数据库的标准 API,Spring Boot 通过 JdbcTemplate
简化了 JDBC 的使用。
2. JPA (Java Persistence API)
2.1 基本概念
JPA 是 Java 持久化的标准规范,Hibernate 是其最流行的实现。
3. MyBatis
3.1 基本概念
MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。
4. Spring Data JPA
4.1 基本概念
Spring Data JPA 是 Spring 基于 JPA 规范的一套持久层解决方案。
步骤①:导入jdbc对应的坐标
<!-- pom.xml -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
步骤②:配置数据源
在配置文件中设置数据库连接信息
步骤③:自动配置JdbcTemplate对象
@SpringBootTest
class Springboot15SqlApplicationTests {@Testvoid testJdbcTemplate(@Autowired JdbcTemplate jdbcTemplate) {// JdbcTemplate 会自动被注入到方法参数中// 不需要先声明为类的字段}
}
这种方式是 Spring Test 框架提供的特性,允许:直接在测试方法参数中注入 Spring Bean
不需要在类级别声明字段
适用于单个测试方法需要特定 Bean 的情况等价 @SpringBootTest
class Springboot15SqlApplicationTests {@Autowired // 字段注入private JdbcTemplate jdbcTemplate;@Testvoid testJdbcTemplate() {// 使用类级别的 jdbcTemplate}
}
数据库技术
常用内嵌数据库
1. H2 Database
特点
- 纯 Java 编写的关系型数据库
- 支持内存和文件模式
- 提供 Web 控制台
- 完整支持 SQL 标准
2. HSQLDB (HyperSQL Database)
特点
- 轻量级关系型数据库
- 支持 SQL 标准
- 内存和文件模式
- 事务支持完善
3. SQLite
特点
- 轻量级嵌入式数据库
- 无服务器架构
- 单文件存储
- 支持大部分 SQL 标准
4. Apache Derby
特点
- Java 编写的关系型数据库
- 支持嵌入式和网络模式
- 完全支持 JDBC 和 SQL 标准
- 事务支持完善
以H2 Database为例
步骤①:导入H2数据库对应的坐标
<!-- H2内嵌数据库 -->
<dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><scope>runtime</scope>
</dependency>
步骤②:将application.yml
文件中的数据库配置修改为H2数据库的配置
# Spring框架配置
spring:# 数据源配置datasource:# H2数据源配置driver-class-name: org.h2.Driver# 内存模式数据库,应用关闭后数据会丢失url: jdbc:h2:mem:testdb# 用户名username: sa# 密码(H2默认密码为空)password: # H2控制台配置(可选)h2:console:enabled: true # 启用H2控制台path: /h2-console # 访问路径# MyBatis-Plus框架配置
mybatis-plus:# 全局配置global-config:# 数据库配置db-config:# 表名前缀,所有实体类对应的表名会自动添加此前缀table-prefix: tbl_# 主键ID生成策略为自增id-type: auto# MyBatis-Plus配置configuration:# 设置SQL日志实现类,将SQL语句输出到控制台log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
"设置enabled属性为false"是指关闭H2控制台,而不是完全禁用H2数据库。
H2控制台与H2数据库的区别:
- H2数据库本身是数据存储服务
- H2控制台是H2数据库提供的Web管理界面,用于查看和管理数据库
环境分离的最佳实践:
更好的做法是为不同环境(开发、测试、生产)创建不同的配置文件:
application-dev.yml
:开发环境配置(使用H2)application-prod.yml
:生产环境配置(使用MySQL)
NoSQL
SpringBoot整合Redis
步骤①:添加 Redis 依赖
首先,需要在 pom.xml
文件中添加 Spring Boot Data Redis 的依赖:
<!-- Spring Boot Data Redis 启动器 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!-- 连接池依赖(Lettuce 默认使用 Netty 连接池) -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId>
</dependency>
or
步骤②:配置 Redis 连接
在 application.yml
或 application.properties
文件中配置 Redis 连接信息, 这里加了Lettuce:
# application.yml
spring:redis:host: localhost # Redis 服务器地址port: 6379 # Redis 服务器端口password: # Redis 服务器密码(如果没有密码可以不配置)database: 0 # Redis 数据库索引(默认为0)timeout: 3000ms # 连接超时时间(毫秒)lettuce:pool:max-active: 8 # 连接池最大连接数(使用负值表示没有限制)max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)max-idle: 8 # 连接池中的最大空闲连接min-idle: 0 # 连接池中的最小空闲连接
步骤③:使用 Redis 模板
Spring Boot 提供了 RedisTemplate
和 StringRedisTemplate
两个模板类来操作 Redis。
配置 Redis 序列化器
默认情况下,RedisTemplate
使用的是 JdkSerializationRedisSerializer,这会导致存储的数据是二进制格式,不便于阅读。建议使用 JSON 序列化:
@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(connectionFactory);// 使用 Jackson2JsonRedisSerializer 来序列化和反序列化 redis 的 value 值Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper objectMapper = new ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);// 使用 StringRedisSerializer 来序列化和反序列化 redis 的 key 值template.setKeySerializer(new StringRedisSerializer());template.setValueSerializer(jackson2JsonRedisSerializer);// 设置 hash key 和 value 序列化模式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;}
}
步骤④: 使用 RedisTemplate
@Service
public class RedisService {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;/*** 设置缓存* @param key 键* @param value 值*/public void set(String key, Object value) {redisTemplate.opsForValue().set(key, value);}/*** 设置缓存并设置过期时间* @param key 键* @param value 值* @param time 时间(秒)*/public void set(String key, Object value, long time) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);}/*** 获取缓存* @param key 键* @return 值*/public Object get(String key) {return key == null ? null : redisTemplate.opsForValue().get(key);}/*** 删除缓存* @param key 键*/public void delete(String key) {redisTemplate.delete(key);}/*** 批量删除缓存* @param keys 键集合*/public void delete(Collection<String> keys) {redisTemplate.delete(keys);}/*** 指定缓存失效时间* @param key 键* @param time 时间(秒)*/public void expire(String key, long time) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}/*** 获取过期时间* @param key 键* @return 时间(秒),返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在* @param key 键* @return true 存在 false不存在*/public boolean hasKey(String key) {return redisTemplate.hasKey(key);}
}
StringRedisTemplate
StringRedisTemplate
是 Spring Data Redis 提供的一个专门用于操作字符串类型数据的模板类,它是 RedisTemplate
的一个特化版本。
1. StringRedisTemplate 与 RedisTemplate 的区别
1.1 序列化方式不同
StringRedisTemplate:
- 默认使用
StringRedisSerializer
对 key 和 value 进行序列化 - key 和 value 都会被当作字符串处理
- 存储的数据是可读的文本格式,便于调试和查看
- 默认使用
RedisTemplate:
- 默认使用
JdkSerializationRedisSerializer
对 value 进行序列化 - key 默认使用
StringRedisSerializer
,value 默认使JdkSerializationRedisSerializer
- 存储的数据是二进制格式,不便于直接阅读
- 默认使用
使用 StringRedisTemplate
进行 Redis 操作的单元测试示例
//类定义和注解
@SpringBootTest
public class StringRedisTemplateTest {
//依赖注入@Autowiredprivate StringRedisTemplate stringRedisTemplate;@Testvoid get(){
//获取字符串操作对象,专门用于操作 Redis 中的字符串类型数据ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();
//从 Redis 中获取键为 "name" 的值。String name = ops.get("name");System.out.println(name);}
}
redis客户端选择
步骤①:添加 Jedis 依赖
<!-- Spring Data Redis -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency><!-- Jedis 客户端 -->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId>
</dependency>
步骤②:配置 Redis 连接,根据需要设置对应的配置
# application.yml
spring:redis:host: localhost # Redis 服务器地址port: 6379 # Redis 服务器端口password: # Redis 服务器密码(如果没有密码可以不配置)database: 0 # Redis 数据库索引(默认为0)timeout: 3000ms # 连接超时时间(毫秒)jedis:pool:max-active: 8 # 连接池最大连接数(使用负值表示没有限制)max-wait: -1ms # 连接池最大阻塞等待时间(使用负值表示没有限制)max-idle: 8 # 连接池中的最大空闲连接min-idle: 0 # 连接池中的最小空闲连接
lettcus与jedis区别
SpringBoot整合MongoDB
MongoDB 是一个流行的 NoSQL 数据库,使用文档存储模式,非常适合处理半结构化和非结构化数据。
步骤①:添加 MongoDB 依赖
<!-- Spring Data MongoDB 启动器 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
or
步骤②: 配置 MongoDB 连接
在 application.yml
或 application.properties
文件中配置 MongoDB 连接信息:
# application.yml
spring:data:mongodb:# MongoDB 连接地址uri: mongodb://localhost:27017/testdb# 或者使用以下方式分别配置# host: localhost# port: 27017# database: testdb# username: admin# password: password# authentication-database: admin
步骤③:使用 MongoTemplate:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.regex.Pattern;@Service
public class MongoTemplateService {@Autowiredprivate MongoTemplate mongoTemplate;/*** 保存文档* @param user 用户对象* @return 保存后的用户对象*/public User save(User user) {return mongoTemplate.save(user);}/*** 批量保存文档* @param users 用户列表* @return 保存后的用户列表*/public List<User> saveAll(List<User> users) {return mongoTemplate.insert(users, User.class);}/*** 根据ID查询文档* @param id 用户ID* @return 用户对象*/public User findById(String id) {return mongoTemplate.findById(id, User.class);}/*** 根据条件查询文档* @param username 用户名* @return 用户对象*/public User findByUsername(String username) {Query query = new Query(Criteria.where("username").is(username));return mongoTemplate.findOne(query, User.class);}/*** 根据条件查询多个文档* @param minAge 最小年龄* @param maxAge 最大年龄* @return 用户列表*/public List<User> findByAgeRange(Integer minAge, Integer maxAge) {Query query = new Query(Criteria.where("age").gte(minAge).lte(maxAge));return mongoTemplate.find(query, User.class);}/*** 模糊查询* @param email 邮箱* @return 用户列表*/public List<User> findByEmailLike(String email) {Query query = new Query(Criteria.where("email").regex(Pattern.compile(email, Pattern.CASE_INSENSITIVE)));return mongoTemplate.find(query, User.class);}/*** 分页查询* @param page 页码(从0开始)* @param size 每页大小* @return 用户列表*/public List<User> findByPage(int page, int size) {Query query = new Query();query.skip(page * size);query.limit(size);return mongoTemplate.find(query, User.class);}/*** 排序查询* @param field 排序字段* @param direction 排序方向(asc/desc)* @return 用户列表*/public List<User> findBySort(String field, String direction) {Query query = new Query();if ("desc".equalsIgnoreCase(direction)) {query.with(Sort.by(Sort.Direction.DESC, field));} else {query.with(Sort.by(Sort.Direction.ASC, field));}return mongoTemplate.find(query, User.class);}/*** 更新文档* @param id 用户ID* @param age 新年龄* @return 更新后的用户对象*/public User updateAge(String id, Integer age) {Query query = new Query(Criteria.where("id").is(id));Update update = new Update().set("age", age);return mongoTemplate.findAndModify(query, update, User.class);}/*** 更新文档(如果不存在则创建)* @param user 用户对象* @return 更新后的用户对象*/public User upsert(User user) {Query query = new Query(Criteria.where("id").is(user.getId()));Update update = new Update().set("username", user.getUsername()).set("password", user.getPassword()).set("age", user.getAge()).set("email", user.getEmail());return mongoTemplate.findAndModify(query, update, User.class);}/*** 删除文档* @param id 用户ID*/public void deleteById(String id) {Query query = new Query(Criteria.where("id").is(id));mongoTemplate.remove(query, User.class);}/*** 删除所有文档*/public void deleteAll() {mongoTemplate.remove(new Query(), User.class);}/*** 统计文档数量* @return 文档数量*/public long count() {return mongoTemplate.count(new Query(), User.class);}/*** 检查文档是否存在* @param id 用户ID* @return 是否存在*/public boolean exists(String id) {Query query = new Query(Criteria.where("id").is(id));return mongoTemplate.exists(query, User.class);}
}
SpringBoot整合ES
步骤①:添加依赖
<!-- Spring Data Elasticsearch依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
or
步骤②:进行基础配置
在application.yml
配置文件中添加Elasticsearch相关配置
<!-- Spring Data Elasticsearch依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
步骤③:使用springboot整合ES的专用客户端接口ElasticsearchRestTemplate来进行操作
@SpringBootTest
class Springboot18EsApplicationTests {@Autowiredprivate ElasticsearchRestTemplate template;
}
示例:索引文档操作
// 1. 获取客户端对象
RestHighLevelClient client = ...; // 从Spring容器注入或手动创建// 2. 创建请求对象
IndexRequest request = new IndexRequest("book_index").id("1").source("{\"name\":\"Spring Boot实战\",\"description\":\"全面介绍Spring Boot框架\"}", XContentType.JSON);// 3. 发送请求并获取响应
IndexResponse response = client.index(request, RequestOptions.DEFAULT);// 4. 处理响应
String index = response.getIndex();
String id = response.getId();
// ...处理其他响应信息// 5. 关闭客户端连接(通常在应用关闭时执行,而不是每次操作后)
// client.close(); // 通常在应用关闭时执行
Spring Data Elasticsearch简化操作
在Spring Boot环境中,通过Spring Data Elasticsearch可以进一步简化操作:
// 1. 通过依赖注入获取Repository
@Autowired
private BookDocumentDao bookDocumentDao;// 2. 直接调用方法完成操作(底层自动处理了请求的构建和发送)
BookDocument book = bookDocumentDao.save(new BookDocument());// 3. 无需手动关闭连接(由Spring容器管理)
Elasticsearch操作的基本流程
获取客户端对象:无论进行何种操作,第一步总是获取Elasticsearch客户端对象(通常是
RestHighLevelClient
)创建请求对象:根据操作类型(如索引、搜索、更新等)创建相应的请求对象
发送请求并获取响应:通过客户端发送请求,并获取响应结果
处理响应:解析响应对象,获取操作结果
关闭客户端连接:操作完成后,最后一步总是关闭客户端对象释放资源
遵循着"获取客户端-发送请求-处理响应-关闭连接"的基本模式