Java JPA 全面指南:语法详解与使用案例

一、JPA 简介

1.1 什么是 JPA?

Java Persistence API(JPA)是 Java EE 的一部分,提供了一套 对象关系映射(ORM) 的标准接口。它通过注解和 API 将 Java 对象与数据库表映射,简化了数据库操作。

1.2 JPA 的核心功能

  • 对象-关系映射(ORM):将 Java 类映射为数据库表,对象属性映射为表字段。
  • CRUD 操作:通过 EntityManager 提供增删改查操作。
  • 查询语言:JPQL(Java Persistence Query Language)和 Criteria API。
  • 事务管理:支持声明式事务(@Transactional)。
  • 缓存机制:一级缓存(Session 级)、二级缓存(应用级)。

二、JPA 入门

2.1 依赖配置(Spring Boot 示例)

<!-- Maven -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

2.2 配置文件(application.properties)

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

三、实体类映射

3.1 基本注解

注解说明
@Entity标记类为实体
@Table(name = "user")指定数据库表名
@Id标记主键字段
@GeneratedValue主键生成策略
@Column(name = "username")映射字段名
@Temporal(TemporalType.DATE)映射日期类型
@Enumerated(EnumType.STRING)映射枚举类型
示例:用户实体类
@Entity
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "username", unique = true, nullable = false)
private String username;

@Column(name = "email", unique = true)
private String email;

@Temporal(TemporalType.DATE)
private Date birthDate;

@Enumerated(EnumType.STRING)
private Role role;

// Getters and Setters
}

3.2 主键生成策略

策略说明
GenerationType.IDENTITY自增主键(MySQL、PostgreSQL)
GenerationType.SEQUENCE序列(Oracle)
GenerationType.TABLE使用数据库表维护主键
GenerationType.AUTO自动选择策略

四、JPA 操作

4.1 EntityManager 基本操作

EntityManager em = ...;
User user = new User();
user.setUsername("admin");
user.setEmail("admin@example.com");

// 保存
em.persist(user);

// 查询
User foundUser = em.find(User.class, 1L);

// 更新
foundUser.setEmail("new@example.com");
em.merge(foundUser);

// 删除
em.remove(foundUser);

4.2 Spring Data JPA 简化操作

Spring Data JPA 提供了 JpaRepository 接口,自动实现 CRUD 方法。

示例:Repository 接口
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
List<User> findByEmailContaining(String email);
}

五、JPQL 与查询

5.1 JPQL 基本语法

String jpql = "SELECT u FROM User u WHERE u.username LIKE :username";
TypedQuery<User> query = em.createQuery(jpql, User.class);
query.setParameter("username", "%admin%");
List<User> users = query.getResultList();

5.2 命名查询(@NamedQuery)

@Entity
@NamedQuery(name = "User.findByRole",
query = "SELECT u FROM User u WHERE u.role = :role")
public class User {
// ...
}

5.3 Criteria API(类型安全查询)

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<User> cq = cb.createQuery(User.class);
Root<User> user = cq.from(User.class);
cq.select(user).where(cb.equal(user.get("role"), Role.ADMIN));

List<User> admins = em.createQuery(cq).getResultList();

六、关联关系映射

6.1 一对一(@OneToOne)

@Entity
public class User {
@Id
private Long id;

@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "profile_id")
private Profile profile;
}

@Entity
public class Profile {
@Id
private Long id;

private String bio;
}

6.2 一对多(@OneToMany)

@Entity
public class User {
@Id
private Long id;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
}

@Entity
public class Order {
@Id
private Long id;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}

6.3 多对多(@ManyToMany)

@Entity
public class Student {
@Id
private Long id;

@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}

@Entity
public class Course {
@Id
private Long id;
}

七、事务管理

7.1 声明式事务(@Transactional)

@Service
public class UserService {
@Autowired
private UserRepository userRepository;

@Transactional
public void transferMoney(Long fromId, Long toId, Double amount) {
User fromUser = userRepository.findById(fromId).orElseThrow(...);
User toUser = userRepository.findById(toId).orElseThrow(...);

fromUser.setBalance(fromUser.getBalance() - amount);
toUser.setBalance(toUser.getBalance() + amount);

userRepository.save(fromUser);
userRepository.save(toUser);
}
}

7.2 事务传播行为

传播行为说明
REQUIRED如果存在事务则加入,否则新建(默认)
REQUIRES_NEW总是新建事务
NEVER不允许事务

八、性能优化

8.1 懒加载 vs 急加载

@OneToMany(fetch = FetchType.LAZY) // 懒加载(默认)
private List<Order> orders;

@OneToMany(fetch = FetchType.EAGER) // 急加载
private List<Order> orders;

8.2 避免 N+1 问题

  • 使用 JOIN FETCH
String jpql = "SELECT u FROM User u JOIN FETCH u.orders WHERE u.id = :id";
  • 使用 @BatchSize
@OneToMany(fetch = FetchType.LAZY)
@BatchSize(size = 10)
private List<Order> orders;

8.3 缓存配置

spring.jpa.open-in-view=false
spring.cache.type=caffeine

九、高级功能

9.1 实体监听器(@EntityListeners)

@Entity
@EntityListeners(AuditingEntityListener.class)
public class User {
@CreatedDate
private Date createdAt;

@LastModifiedDate
private Date updatedAt;
}

9.2 乐观锁(@Version)

@Entity
public class Product {
@Id
private Long id;

private String name;

@Version
private Integer version; // 乐观锁版本号
}

十、完整使用案例

10.1 用户管理系统

实体类
@Entity
public class User {
@Id
@GeneratedValue
private Long id;

private String username;
private String email;

@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Order> orders = new ArrayList<>();
}
Repository 接口
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
Service 层
@Service
public class UserService {
@Autowired
private UserRepository userRepository;

public User createUser(String username, String email) {
User user = new User();
user.setUsername(username);
user.setEmail(email);
return userRepository.save(user);
}

public List<User> searchByEmail(String email) {
return userRepository.findByEmailContaining(email);
}
}
Controller 层
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;

@PostMapping
public User createUser(@RequestBody UserDTO dto) {
return userService.createUser(dto.getUsername(), dto.getEmail());
}

@GetMapping("/search")
public List<User> searchByEmail(@RequestParam String email) {
return userService.searchByEmail(email);
}
}

十一、常见问题与解决方案

问题解决方案
LazyInitializationException使用 JOIN FETCH 或在事务中访问关联字段
StaleObjectStateException检查乐观锁版本号是否冲突
主键冲突检查 @GeneratedValue 策略
查询性能差使用分页(Pageable)或缓存

十二、总结

JPA 通过注解和 API 简化了数据库操作,但合理使用需要掌握以下要点:

  • 实体映射:正确使用注解定义表结构。
  • 查询优化:避免 N+1 问题,合理使用缓存。
  • 事务管理:保证数据一致性。
  • 性能调优:结合懒加载、缓存和索引。

在实际开发中,推荐使用 Spring Data JPA 来简化代码,但理解底层 JPA 原理对排查问题至关重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lisonseekpan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值