1. 数据访问层概述
Spring Boot为数据访问提供了强大的支持,通过自动配置和起步依赖,可以快速集成各种数据访问技术。Spring Boot数据访问层主要包括JPA、MyBatis、Redis、MongoDB等技术栈。
1.1 数据访问技术栈
- Spring Data JPA:基于Hibernate的ORM框架
- Spring Data Redis:Redis数据访问
- Spring Data MongoDB:MongoDB文档数据库
- MyBatis:轻量级ORM框架
- JdbcTemplate:JDBC模板类
- 数据库连接池:HikariCP、Druid等
1.2 核心依赖
<dependencies>
<!-- Spring Boot Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Spring Boot Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Spring Boot Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- H2数据库(测试用) -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
2. Spring Data JPA
2.1 实体类设计
package com.example.demo.entity;
import javax.persistence.*;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank(message = "用户名不能为空")
@Size(min = 2, max = 20, message = "用户名长度必须在2-20个字符之间")
@Column(unique = true, nullable = false)
private String username;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
@Column(unique = true, nullable = false)
private String email;
@NotBlank(message = "密码不能为空")
@Size(min = 6, message = "密码长度至少6位")
@Column(nullable = false)
private String password;
@Column(name = "full_name")
private String fullName;
@Column(name = "phone_number")
private String phoneNumber;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private UserStatus status = UserStatus.ACTIVE;
@Column(name = "created_at", nullable = false, updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private List<Role> roles;
// 枚举类
public enum UserStatus {
ACTIVE, INACTIVE, SUSPENDED
}
// 构造方法
public User() {}
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
this.createdAt = LocalDateTime.now();
}
// JPA回调方法
@PrePersist
protected void onCreate() {
createdAt = LocalDateTime.now();
updatedAt = LocalDateTime.now();
}
@PreUpdate
protected void onUpdate() {
updatedAt = LocalDateTime.now();
}
// getter和setter方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getFullName() { return fullName; }
public void setFullName(String fullName) { this.fullName = fullName; }
public String getPhoneNumber() { return phoneNumber; }
public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; }
public UserStatus getStatus() { return status; }
public void setStatus(UserStatus status) { this.status = status; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
public List<Order> getOrders() { return orders; }
public void setOrders(List<Order> orders) { this.orders = orders; }
public List<Role> getRoles() { return roles; }
public void setRoles(List<Role> roles) { this.roles = roles; }
}
2.2 Repository接口
package com.example.demo.repository;
import com.example.demo.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 根据用户名查找用户
Optional<User> findByUsername(String username);
// 根据邮箱查找用户
Optional<User> findByEmail(String email);
// 根据用户名或邮箱查找用户
Optional<User> findByUsernameOrEmail(String username, String email);
// 根据状态查找用户
List<User> findByStatus(User.UserStatus status);
// 根据创建时间范围查找用户
List<User> findByCreatedAtBetween(LocalDateTime start, LocalDateTime end);
// 根据用户名模糊查询
List<User> findByUsernameContainingIgnoreCase(String username);
// 根据邮箱域名查找用户
@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
List<User> findByEmailDomain(@Param("domain") String domain);
// 自定义查询:统计活跃用户数量
@Query("SELECT COUNT(u) FROM User u WHERE u.status = 'ACTIVE'")
Long countActiveUsers();
// 自定义查询:查找最近注册的用户
@Query("SELECT u FROM User u WHERE u.createdAt >= :since ORDER BY u.createdAt DESC")
List<User> findRecentUsers(@Param("since") LocalDateTime since);
// 分页查询:根据状态分页
Page<User> findByStatus(User.UserStatus status, Pageable pageable);
// 分页查询:根据用户名模糊查询
Page<User> findByUsernameContainingIgnoreCase(String username, Pageable pageable);
// 原生SQL查询
@Query(value = "SELECT * FROM users WHERE created_at >= ?1 ORDER BY created_at DESC", nativeQuery = true)
List<User> findUsersCreatedAfter(LocalDateTime date);
// 更新操作
@Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
int updateUserStatus(@Param("id") Long id, @Param("status") User.UserStatus status);
// 删除操作
void deleteByStatus(User.UserStatus status);
}
2.3 服务层实现
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
// 创建用户
public User createUser(User user) {
// 检查用户名是否已存在
if (userRepository.findByUsername(user.getUsername()).isPresent()) {
throw new RuntimeException("用户名已存在");
}
// 检查邮箱是否已存在
if (userRepository.findByEmail(user.getEmail()).isPresent()) {
throw new RuntimeException("邮箱已存在");
}
return userRepository.save(user);
}
// 根据ID获取用户
@Transactional(readOnly = true)
public Optional<User> getUserById(Long id) {
return userRepository.findById(id);
}
// 根据用户名获取用户
@Transactional(readOnly = true)
public Optional<User> getUserByUsername(String username) {
return userRepository.findByUsername(username);
}
// 更新用户
public User updateUser(Long id, User userDetails) {
User user = userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("用户不存在"));
// 更新用户信息
if (userDetails.getFullName() != null) {
user.setFullName(userDetails.getFullName());
}
if (userDetails.getPhoneNumber() != null) {
user.setPhoneNumber(userDetails.getPhoneNumber());
}
if (userDetails.getStatus() != null) {
user.setStatus(userDetails.getStatus());
}
return userRepository.save(user);
}
// 删除用户
public void deleteUser(Long id) {
if (!userRepository.existsById(id)) {
throw new RuntimeException("用户不存在");
}
userRepository.deleteById(id);
}
// 获取所有用户
@Transactional(readOnly = true)
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 分页获取用户
@Transactional(readOnly = true)
public Page<User> getUsers(Pageable pageable) {
return userRepository.findAll(pageable);
}
// 根据状态获取用户
@Transactional(readOnly = true)
public List<User> getUsersByStatus(User.UserStatus status) {
return userRepository.findByStatus(status);
}
// 搜索用户
@Transactional(readOnly = true)
public Page<User> searchUsers(String keyword, Pageable pageable) {
return userRepository.findByUsernameContainingIgnoreCase(keyword, pageable);
}
// 获取活跃用户数量
@Transactional(readOnly = true)
public Long getActiveUserCount() {
return userRepository.countActiveUsers();
}
// 获取最近注册的用户
@Transactional(readOnly = true)
public List<User> getRecentUsers(int days) {
LocalDateTime since = LocalDateTime.now().minusDays(days);
return userRepository.findRecentUsers(since);
}
// 批量更新用户状态
@Transactional
public int updateUserStatus(Long id, User.UserStatus status) {
return userRepository.updateUserStatus(id, status);
}
// 批量删除用户
@Transactional
public void deleteUsersByStatus(User.UserStatus status) {
userRepository.deleteByStatus(status);
}
}
3. 数据库配置
3.1 数据源配置
# application.yml
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# 连接池配置
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
leak-detection-threshold: 60000
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
use_sql_comments: true
jdbc:
batch_size: 20
order_inserts: true
order_updates: true
# 多数据源配置
datasource:
primary:
url: jdbc:mysql://localhost:3306/primary_db
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
secondary:
url: jdbc:mysql://localhost:3306/secondary_db
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
3.2 多数据源配置
package com.example.demo.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
@EnableJpaRepositories(
basePackages = "com.example.demo.repository.primary",
entityManagerFactoryRef = "primaryEntityManagerFactory",
transactionManagerRef = "primaryTransactionManager"
)
public class PrimaryDataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Primary
@Bean(name = "primaryEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean primaryEntityManagerFactory(
@Qualifier("primaryDataSource") DataSource dataSource) {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource);
em.setPackagesToScan("com.example.demo.entity.primary");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
Properties properties = new Properties();
properties.setProperty("hibernate.hbm2ddl.auto", "update");
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
properties.setProperty("hibernate.show_sql", "true");
em.setJpaProperties(properties);
return em;
}
@Primary
@Bean(name = "primaryTransactionManager")
public PlatformTransactionManager primaryTransactionManager(
@Qualifier("primaryEntityManagerFactory") LocalContainerEntityManagerFactoryBean entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory.getObject());
}
}
4. Spring Data Redis
4.1 Redis配置
package com.example.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
// 使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringSerializer());
template.setValueSerializer(serializer);
template.setHashKeySerializer(new StringSerializer());
template.setHashValueSerializer(serializer);
template.afterPropertiesSet();
return template;
}
}
4.2 Redis服务类
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 设置缓存
public void set(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
// 设置缓存并指定过期时间
public void set(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
// 获取缓存
public Object get(String key) {
return redisTemplate.opsForValue().get(key);
}
// 删除缓存
public void delete(String key) {
redisTemplate.delete(key);
}
// 判断key是否存在
public boolean hasKey(String key) {
return Boolean.TRUE.equals(redisTemplate.hasKey(key));
}
// 设置过期时间
public boolean expire(String key, long timeout, TimeUnit unit) {
return Boolean.TRUE.equals(redisTemplate.expire(key, timeout, unit));
}
// 获取过期时间
public long getExpire(String key) {
Long expire = redisTemplate.getExpire(key);
return expire != null ? expire : -1;
}
// 递增
public long increment(String key, long delta) {
Long result = redisTemplate.opsForValue().increment(key, delta);
return result != null ? result : 0;
}
// 递减
public long decrement(String key, long delta) {
Long result = redisTemplate.opsForValue().decrement(key, delta);
return result != null ? result : 0;
}
}
4.3 缓存注解使用
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class CachedUserService {
@Autowired
private UserRepository userRepository;
// 缓存用户信息
@Cacheable(value = "users", key = "#id")
public Optional<User> getUserById(Long id) {
System.out.println("从数据库查询用户: " + id);
return userRepository.findById(id);
}
// 更新缓存
@CachePut(value = "users", key = "#user.id")
public User updateUser(User user) {
return userRepository.save(user);
}
// 清除缓存
@CacheEvict(value = "users", key = "#id")
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
// 清除所有用户缓存
@CacheEvict(value = "users", allEntries = true)
public void clearAllUserCache() {
System.out.println("清除所有用户缓存");
}
// 缓存用户列表
@Cacheable(value = "userList")
public List<User> getAllUsers() {
System.out.println("从数据库查询所有用户");
return userRepository.findAll();
}
}
5. Spring Data MongoDB
5.1 MongoDB实体类
package com.example.demo.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.time.LocalDateTime;
import java.util.List;
@Document(collection = "products")
public class Product {
@Id
private String id;
@Field("name")
private String name;
@Field("description")
private String description;
@Field("price")
private Double price;
@Field("category")
private String category;
@Field("tags")
private List<String> tags;
@Field("created_at")
private LocalDateTime createdAt;
@Field("updated_at")
private LocalDateTime updatedAt;
// 构造方法
public Product() {}
public Product(String name, String description, Double price, String category) {
this.name = name;
this.description = description;
this.price = price;
this.category = category;
this.createdAt = LocalDateTime.now();
}
// getter和setter方法
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public List<String> getTags() { return tags; }
public void setTags(List<String> tags) { this.tags = tags; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public LocalDateTime getUpdatedAt() { return updatedAt; }
public void setUpdatedAt(LocalDateTime updatedAt) { this.updatedAt = updatedAt; }
}
5.2 MongoDB Repository
package com.example.demo.repository;
import com.example.demo.entity.Product;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ProductRepository extends MongoRepository<Product, String> {
// 根据名称查找
List<Product> findByName(String name);
// 根据名称模糊查询
List<Product> findByNameContainingIgnoreCase(String name);
// 根据价格范围查找
List<Product> findByPriceBetween(Double minPrice, Double maxPrice);
// 根据分类查找
List<Product> findByCategory(String category);
// 根据标签查找
List<Product> findByTagsIn(List<String> tags);
// 自定义查询
@Query("{'name': {$regex: ?0, $options: 'i'}}")
List<Product> findByNameRegex(String namePattern);
// 复杂查询
@Query("{'price': {$gte: ?0, $lte: ?1}, 'category': ?2}")
List<Product> findByPriceRangeAndCategory(Double minPrice, Double maxPrice, String category);
// 分页查询
Page<Product> findByCategory(String category, Pageable pageable);
// 统计查询
@Query(value = "{}", count = true)
long countAllProducts();
@Query(value = "{'category': ?0}", count = true)
long countByCategory(String category);
}
6. 事务管理
6.1 声明式事务
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class TransactionalUserService {
@Autowired
private UserRepository userRepository;
// 只读事务
@Transactional(readOnly = true)
public List<User> getAllUsers() {
return userRepository.findAll();
}
// 写事务
@Transactional
public User createUser(User user) {
return userRepository.save(user);
}
// 回滚事务
@Transactional(rollbackFor = Exception.class)
public void createUserWithRollback(User user) {
userRepository.save(user);
throw new RuntimeException("模拟异常,触发回滚");
}
// 不回滚事务
@Transactional(noRollbackFor = RuntimeException.class)
public void createUserWithoutRollback(User user) {
userRepository.save(user);
throw new RuntimeException("模拟异常,但不回滚");
}
// 嵌套事务
@Transactional
public void createMultipleUsers(List<User> users) {
for (User user : users) {
createUser(user);
}
}
// 新事务
@Transactional(propagation = org.springframework.transaction.annotation.Propagation.REQUIRES_NEW)
public void createUserInNewTransaction(User user) {
userRepository.save(user);
}
}
6.2 编程式事务
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.util.List;
@Service
public class ProgrammaticTransactionService {
@Autowired
private UserRepository userRepository;
@Autowired
private PlatformTransactionManager transactionManager;
public void createUsersWithProgrammaticTransaction(List<User> users) {
// 定义事务属性
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
def.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
def.setTimeout(30);
// 开始事务
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 执行业务逻辑
for (User user : users) {
userRepository.save(user);
}
// 提交事务
transactionManager.commit(status);
System.out.println("事务提交成功");
} catch (Exception e) {
// 回滚事务
transactionManager.rollback(status);
System.out.println("事务回滚: " + e.getMessage());
throw e;
}
}
}
7. 数据访问最佳实践
7.1 性能优化
package com.example.demo.service;
import com.example.demo.entity.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class OptimizedUserService {
@Autowired
private UserRepository userRepository;
// 分页查询优化
@Transactional(readOnly = true)
public Page<User> getUsersOptimized(int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
return userRepository.findAll(pageable);
}
// 批量操作优化
@Transactional
public List<User> batchCreateUsers(List<User> users) {
return userRepository.saveAll(users);
}
// 查询优化:只查询需要的字段
@Transactional(readOnly = true)
public List<User> getUsersWithProjection() {
return userRepository.findAll();
}
}
7.2 异常处理
package com.example.demo.exception;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class DataAccessExceptionHandler {
// 处理数据访问异常
@ExceptionHandler(DataAccessException.class)
public ResponseEntity<Map<String, Object>> handleDataAccessException(DataAccessException ex) {
Map<String, Object> response = new HashMap<>();
response.put("code", 500);
response.put("message", "数据访问异常");
response.put("error", ex.getMessage());
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response);
}
// 处理数据完整性异常
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<Map<String, Object>> handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
Map<String, Object> response = new HashMap<>();
response.put("code", 400);
response.put("message", "数据完整性约束违反");
response.put("error", ex.getMessage());
return ResponseEntity.badRequest().body(response);
}
// 处理空结果异常
@ExceptionHandler(EmptyResultDataAccessException.class)
public ResponseEntity<Map<String, Object>> handleEmptyResultDataAccessException(EmptyResultDataAccessException ex) {
Map<String, Object> response = new HashMap<>();
response.put("code", 404);
response.put("message", "未找到相关数据");
response.put("error", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
}
}
8. 数据库迁移
8.1 Flyway配置
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
# application.yml
spring:
flyway:
enabled: true
locations: classpath:db/migration
baseline-on-migrate: true
validate-on-migrate: true
8.2 迁移脚本
V1__Create_users_table.sql
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
full_name VARCHAR(100),
phone_number VARCHAR(20),
status ENUM('ACTIVE', 'INACTIVE', 'SUSPENDED') NOT NULL DEFAULT 'ACTIVE',
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
V2__Create_roles_table.sql
CREATE TABLE roles (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
description VARCHAR(255),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE user_roles (
user_id BIGINT NOT NULL,
role_id BIGINT NOT NULL,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
9. 总结
Spring Boot数据访问层提供了完整的数据持久化解决方案:
- Spring Data JPA:基于Hibernate的ORM框架,支持复杂查询和关系映射
- Spring Data Redis:Redis数据访问,支持缓存和会话存储
- Spring Data MongoDB:文档数据库访问,适合非关系型数据存储
- 事务管理:声明式和编程式事务支持
- 性能优化:分页查询、批量操作、查询优化
- 异常处理:完善的异常处理机制
- 数据库迁移:Flyway数据库版本管理
通过合理使用这些技术,可以构建出高性能、可扩展的数据访问层。
下一篇:Spring Boot安全框架详解
1096

被折叠的 条评论
为什么被折叠?



