Spring Boot数据访问层详解 - 实践

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数据访问层提供了完整的数据持久化解决方案:

  1. Spring Data JPA:基于Hibernate的ORM框架,支持复杂查询和关系映射
  2. Spring Data Redis:Redis数据访问,支持缓存和会话存储
  3. Spring Data MongoDB:文档数据库访问,适合非关系型数据存储
  4. 事务管理:声明式和编程式事务支持
  5. 性能优化:分页查询、批量操作、查询优化
  6. 异常处理:完善的异常处理机制
  7. 数据库迁移:Flyway数据库版本管理

通过合理使用这些技术,可以构建出高性能、可扩展的数据访问层。


下一篇:Spring Boot安全框架详解

posted on 2025-11-06 10:32  wgwyanfs  阅读(9)  评论(0)    收藏  举报

导航