Allra数据库设计及QueryDSL规则Skill allra-database-schema

Allra后端团队数据库设计规范,涵盖JPA实体设计、QueryDSL查询编写、事务管理标准。提供Spring Boot项目中的数据库层最佳实践,包括Repository结构、DTO投影、关联关系映射和@Transactional使用指南。关键词:数据库设计、JPA、QueryDSL、Spring Boot、事务管理、后端开发、Java持久层、ORM最佳实践。

后端开发 0 次安装 1 次浏览 更新于 3/1/2026

name: allra-database-schema description: Allra数据库设计及QueryDSL使用规则。在创建JPA实体、编写QueryDSL查询或添加@Transactional注解时使用。

Allra数据库设计及QueryDSL规则

定义Allra后端团队的数据库设计、JPA、QueryDSL、事务管理标准。

项目基本信息

本指南基于以下环境编写:

  • Java: 17及以上
  • Spring Boot: 3.2及以上
  • ORM: JPA/Hibernate
  • Query Library: QueryDSL(可选)
  • Testing: Testcontainers(可选)

注意:各项目使用的数据库(MariaDB、PostgreSQL、MySQL等)和库可能不同。

QueryDSL使用规则

1. Repository结构(Allra推荐模式)

同时使用JPA Repository和Support接口:

// JPA Repository接口
public interface UserRepository extends JpaRepository<User, Long>, UserRepositorySupport {
}

// QueryDSL Support接口
public interface UserRepositorySupport {
    List<UserSummaryDto> findUserSummaries(UserSearchCondition condition);
}

// QueryDSL Support实现类
@Repository
public class UserRepositoryImpl implements UserRepositorySupport {

    private final JPAQueryFactory queryFactory;

    @Override
    public List<UserSummaryDto> findUserSummaries(UserSearchCondition condition) {
        return queryFactory
            .select(new QUserSummaryDto(
                user.id,
                user.email,
                user.name
            ))
            .from(user)
            .where(
                emailContains(condition.email()),
                nameContains(condition.name())
            )
            .fetch();
    }

    private BooleanExpression emailContains(String email) {
        return email != null ? user.email.contains(email) : null;
    }
}

注意:Support模式是可选的。根据项目情况,可以使用@Query注解或其他方式。

2. QueryDSL DTO投影

使用Record和@QueryProjection

public record UserSummaryDto(
    Long id,
    String email,
    String name
) {
    @QueryProjection
    public UserSummaryDto {}
}

构建设置

Gradle:

annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jakarta"

Maven:

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
        </execution>
    </executions>
</plugin>

3. 根据From子句确定Repository位置

建议在From子句对应的Repository中定义:

// ❌ 避免:在Order中查询User
public interface OrderRepositorySupport {
    List<UserDto> findUsersByOrderDate(LocalDate date); // From user
}

// ✅ 推荐:在User中关联Order
public interface UserRepositorySupport {
    List<UserOrderDto> findUsersWithOrders(LocalDate date); // From user
}

4. 数据库兼容性

编写QueryDSL时考虑所用数据库的特性:

// 通用查询
queryFactory
    .selectFrom(user)
    .where(user.createdAt.between(startDate, endDate))
    .fetch();

// LIMIT/OFFSET
queryFactory
    .selectFrom(user)
    .limit(10)
    .offset(0)
    .fetch();

注意:窗口函数或特定数据库函数可能因数据库版本而异。

5. 禁止直接依赖xxxRepositorySupport

必须通过JPA Repository接口使用:

// ❌ 错误示例
@Service
public class UserService {
    private final UserRepositoryImpl userRepositoryImpl; // 直接注入实现类
}

// ✅ 正确示例
@Service
public class UserService {
    private final UserRepository userRepository; // 注入接口
}

@Transactional使用指南

必要规则

在每个服务方法中显式声明:

  1. 仅查询操作@Transactional(readOnly = true)
  2. 包含修改操作@Transactional

示例

@Service
public class UserService {

    private final UserRepository userRepository;

    // 只读事务
    @Transactional(readOnly = true)
    public List<User> findAllUsers() {
        return userRepository.findAll();
    }

    // 写事务
    @Transactional
    public User createUser(SignUpRequest request) {
        User user = User.create(request.email(), request.password());
        return userRepository.save(user);
    }

    // 查询+修改
    @Transactional
    public User activateUser(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new UserNotFoundException(id));
        user.activate(); // 修改
        return user;
    }
}

注意:事务传播(Propagation)使用默认值(REQUIRED),仅在特殊情况下显式指定。

JPA实体设计指南

基本结构

@Entity
@Table(name = "users")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false, unique = true, length = 100)
    private String email;

    @Column(nullable = false, length = 100)
    private String name;

    @Enumerated(EnumType.STRING)
    @Column(nullable = false, length = 20)
    private UserStatus status;

    @CreatedDate
    @Column(nullable = false, updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(nullable = false)
    private LocalDateTime updatedAt;

    // 静态工厂方法
    public static User create(String email, String password, String name) {
        User user = new User();
        user.email = email;
        user.password = password;
        user.name = name;
        user.status = UserStatus.ACTIVE;
        return user;
    }

    // 业务方法
    public void activate() {
        this.status = UserStatus.ACTIVE;
    }
}

关联关系映射

@Entity
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // ManyToOne - 推荐延迟加载
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id", nullable = false)
    private User user;

    // OneToMany - 延迟加载,Cascade设置
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<OrderItem> items = new ArrayList<>();

    // 关联关系便捷方法
    public void addItem(OrderItem item) {
        items.add(item);
        item.setOrder(this);
    }
}

注意:建议关联关系默认使用延迟加载(LAZY)。

何时使用此技能

此技能在以下情况下自动应用:

  • JPA实体创建及修改
  • QueryDSL查询编写
  • Repository接口及实现类编写
  • Service方法添加@Transactional
  • DTO投影编写

检查清单

编写数据库相关代码时确认事项:

  • [ ] QueryDSL Support是否继承自JPA Repository?(使用Support模式时)
  • [ ] QueryDSL实现类是否位于From子句对应的Repository中?
  • [ ] DTO投影是否应用了@QueryProjection?(使用QueryDSL时)
  • [ ] Service的所有public方法是否都显式声明了@Transactional?
  • [ ] 只读方法是否应用了readOnly = true?
  • [ ] 是否考虑了MariaDB兼容性?
  • [ ] 实体的关联关系是否设置为延迟加载(LAZY)?
  • [ ] 是否未直接注入xxxRepositorySupport实现类?