Hibernate 框架超详细说明
1. Hibernate 框架概述
- ORM 框架:对象关系映射(Object-Relational Mapping)
- JPA 实现:Java Persistence API 的具体实现
- 数据库抽象:屏蔽底层数据库差异
- 自动 SQL 生成:减少手动 SQL 编写工作
2. 核心概念
2.1 持久化生命周期
- 瞬时态(Transient):未与 Session 关联的对象
- 持久态(Persistent):与 Session 关联的对象
- 脱管态(Detached):与 Session 断开连接的对象
2.2 Session 机制
- Session 接口:Hibernate 的核心接口
- 事务管理:提供 ACID 事务支持
- 缓存机制:一级缓存(Session 级别)
3. 项目配置
3.1 Maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
3.2 application.yml 配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/hibernate_demo
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.MySQL8Dialect
format_sql: true
hbm2ddl.auto: update
4. 实体类定义
4.1 基础实体类
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username", nullable = false, length = 50)
private String username;
@Column(name = "email", unique = true)
private String email;
@Column(name = "created_at")
private LocalDateTime createdAt;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders = new ArrayList<>();
// 构造函数
public User() {}
public User(String username, String email) {
this.username = username;
this.email = email;
this.createdAt = 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 LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public List<Order> getOrders() { return orders; }
public void setOrders(List<Order> orders) { this.orders = orders; }
}
4.2 关联实体类
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "order_number", unique = true)
private String orderNumber;
@Column(name = "total_amount")
private BigDecimal totalAmount;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
@Column(name = "order_date")
private LocalDateTime orderDate;
// 构造函数
public Order() {}
public Order(String orderNumber, BigDecimal totalAmount, User user) {
this.orderNumber = orderNumber;
this.totalAmount = totalAmount;
this.user = user;
this.orderDate = LocalDateTime.now();
}
// Getter 和 Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getOrderNumber() { return orderNumber; }
public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }
public BigDecimal getTotalAmount() { return totalAmount; }
public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
public LocalDateTime getOrderDate() { return orderDate; }
public void setOrderDate(LocalDateTime orderDate) { this.orderDate = orderDate; }
}
5. Repository 接口
5.1 基础 Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
List<User> findByEmailContaining(String email);
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findUserWithOrders(@Param("id") Long id);
@Query("SELECT u FROM User u WHERE u.username LIKE %:keyword% OR u.email LIKE %:keyword%")
List<User> searchUsers(@Param("keyword") String keyword);
}
5.2 Order Repository
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByUser(User user);
List<Order> findByUserAndTotalAmountGreaterThan(User user, BigDecimal amount);
@Query("SELECT o FROM Order o WHERE o.orderDate BETWEEN :startDate AND :endDate")
List<Order> findOrdersByDateRange(@Param("startDate") LocalDateTime startDate,
@Param("endDate") LocalDateTime endDate);
}
6. Service 层实现
6.1 UserService
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
public User createUser(String username, String email) {
User user = new User(username, email);
return userRepository.save(user);
}
public Optional<User> findUserById(Long id) {
return userRepository.findById(id);
}
public User findUserWithOrders(Long id) {
return userRepository.findUserWithOrders(id)
.orElseThrow(() -> new EntityNotFoundException("User not found: " + id));
}
public List<User> findAllUsers() {
return userRepository.findAll();
}
public User updateUser(Long id, String username, String email) {
User user = userRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("User not found: " + id));
user.setUsername(username);
user.setEmail(email);
return userRepository.save(user);
}
public void deleteUser(Long id) {
if (!userRepository.existsById(id)) {
throw new EntityNotFoundException("User not found: " + id);
}
userRepository.deleteById(id);
}
public List<User> searchUsers(String keyword) {
return userRepository.searchUsers(keyword);
}
public Order createOrderForUser(Long userId, String orderNumber, BigDecimal amount) {
User user = userRepository.findById(userId)
.orElseThrow(() -> new EntityNotFoundException("User not found: " + userId));
Order order = new Order(orderNumber, amount, user);
return orderRepository.save(order);
}
}
7. 控制器层
7.1 UserController
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {
User user = userService.createUser(request.getUsername(), request.getEmail());
return ResponseEntity.ok(user);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
try {
User user = userService.findUserWithOrders(id);
return ResponseEntity.ok(user);
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.findAllUsers();
return ResponseEntity.ok(users);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id,
@RequestBody UpdateUserRequest request) {
try {
User updatedUser = userService.updateUser(id, request.getUsername(), request.getEmail());
return ResponseEntity.ok(updatedUser);
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
try {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
@GetMapping("/search")
public ResponseEntity<List<User>> searchUsers(@RequestParam String keyword) {
List<User> users = userService.searchUsers(keyword);
return ResponseEntity.ok(users);
}
@PostMapping("/{userId}/orders")
public ResponseEntity<Order> createOrder(@PathVariable Long userId,
@RequestBody CreateOrderRequest request) {
try {
Order order = userService.createOrderForUser(userId,
request.getOrderNumber(),
request.getAmount());
return ResponseEntity.ok(order);
} catch (EntityNotFoundException e) {
return ResponseEntity.notFound().build();
}
}
}
8. 高级特性
8.1 事务管理
@Service
public class TransactionalService {
@Autowired
private UserRepository userRepository;
@Autowired
private OrderRepository orderRepository;
@Transactional
public void performComplexOperation(Long userId) {
// 在同一个事务中执行多个操作
User user = userRepository.findById(userId).orElse(null);
// 创建订单
Order order = new Order("ORD-001", new BigDecimal("100.00"), user);
orderRepository.save(order);
// 更新用户信息
user.setUsername("updated_username");
userRepository.save(user);
// 如果发生异常,整个事务回滚
}
@Transactional(rollbackFor = Exception.class)
public void customRollback() throws Exception {
// 自定义回滚条件
}
}
8.2 缓存配置
@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "users")
public class User {
// 实体定义
}
8.3 分页和排序
@Service
public class UserService {
public Page<User> getUsersWithPagination(int page, int size, String sortBy, String direction) {
Sort sort = direction.equalsIgnoreCase("desc") ?
Sort.by(sortBy).descending() :
Sort.by(sortBy).ascending();
Pageable pageable = PageRequest.of(page, size, sort);
return userRepository.findAll(pageable);
}
}
9. 查询优化
9.1 Fetch Join 优化
@Query("SELECT u FROM User u LEFT JOIN FETCH u.orders WHERE u.id = :id")
Optional<User> findUserWithOrders(@Param("id") Long id);
9.2 批量处理
@Service
public class BatchService {
@PersistenceContext
private EntityManager entityManager;
@Transactional
public void batchInsertUsers(List<User> users) {
for (int i = 0; i < users.size(); i++) {
entityManager.persist(users.get(i));
if (i % 20 == 0) { // 每20个对象刷新一次
entityManager.flush();
entityManager.clear();
}
}
}
}
10. 异常处理
10.1 自定义异常
public class EntityNotFoundException extends RuntimeException {
public EntityNotFoundException(String message) {
super(message);
}
}
public class DataIntegrityException extends RuntimeException {
public DataIntegrityException(String message) {
super(message);
}
}
10.2 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
public ResponseEntity<ErrorResponse> handleEntityNotFound(EntityNotFoundException e) {
ErrorResponse error = new ErrorResponse("ENTITY_NOT_FOUND", e.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
@ExceptionHandler(DataIntegrityException.class)
public ResponseEntity<ErrorResponse> handleDataIntegrity(DataIntegrityException e) {
ErrorResponse error = new ErrorResponse("DATA_INTEGRITY_ERROR", e.getMessage());
return ResponseEntity.status(HttpStatus.CONFLICT).body(error);
}
}
11. 性能优化要点
- 合理使用懒加载和急加载
- 避免 N+1 查询问题
- 使用批量操作
- 合理配置缓存
- 使用索引优化查询
- 及时关闭 Session 和连接
12. 常见问题
- LazyInitializationException:在事务外访问懒加载属性
- 事务边界问题:确保在事务范围内进行数据库操作
- 缓存一致性:在集群环境中注意缓存同步
- 并发控制:使用乐观锁或悲观锁处理并发访问
Hibernate 懒加载机制详解
懒加载的工作原理
1. 代理对象机制
- 当使用
FetchType.LAZY 时,Hibernate 会创建一个代理对象
user.getOrders() 返回的是 Hibernate 的集合代理
- 代理对象继承自
PersistentBag、PersistentList 等
2. SQL 执行时机
User user = userRepository.findById(1L).get(); // 执行: SELECT * FROM users WHERE id = 1
// 此时 orders 集合为空的代理对象,未执行查询
List<Order> orders = user.getOrders(); // 此时才执行: SELECT * FROM orders WHERE user_id = ?
// 仅当真正访问 orders 时才触发 SQL 查询
3. 持久层调用方式
初始化时
userRepository.findById(1L).get() → 调用 JpaRepository 的方法
- 执行对
users 表的查询
访问懒加载属性时
user.getOrders() → 代理对象拦截调用
- Hibernate 内部触发额外的 SQL 查询
- 通过
Session 或 EntityManager 执行查询
4. 实际执行流程
1. userRepository.findById(1L).get()
→ Spring Data JPA → Hibernate → SQL: SELECT * FROM users WHERE id = 1
2. user.getOrders()
→ Hibernate 代理拦截器 → 触发懒加载
→ 生成 SQL: SELECT * FROM orders WHERE user_id = 1
→ 执行查询并填充集合
5. 关键点
- 懒加载是在访问属性时 触发,而非方法调用时
- 需要在事务范围内 访问,否则抛出
LazyInitializationException
- Hibernate 通过字节码增强实现透明的懒加载机制
Hibernate 事务开启方式详解
1. @Transactional 注解方式
主要开启方式
- 使用
@Transactional 注解是 Spring 中开启事务的主要方式
- 可以在方法级别 或类级别使用
- Spring 会自动管理事务的开启、提交和回滚
代码示例
@Service
public class TransactionalService {
@Transactional // 开启事务
public void performComplexOperation(Long userId) {
// 事务范围内的操作
}
}
2. 事务开启的其他方式
编程式事务管理
@Service
public class ProgrammaticTransactionService {
@Autowired
private PlatformTransactionManager transactionManager;
public void performWithProgrammaticTransaction() {
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
// 业务逻辑
// ...
transactionManager.commit(status); // 提交事务
} catch (Exception e) {
transactionManager.rollback(status); // 回滚事务
}
}
}
3. @Transactional 工作机制
Spring AOP 代理
- Spring 通过AOP 代理实现事务管理
- 在方法执行前开启事务
- 方法执行成功后提交事务
- 发生异常时回滚事务
事务传播行为
@Transactional(propagation = Propagation.REQUIRED) // 默认传播行为
public void methodA() {
methodB(); // 如果存在事务则加入,否则新建
}
@Transactional(propagation = Propagation.REQUIRES_NEW) // 新建事务
public void methodB() {
// 独立的事务
}
4. 事务配置参数
常用配置
rollbackFor: 指定哪些异常触发回滚
noRollbackFor: 指定哪些异常不触发回滚
isolation: 事务隔离级别
propagation: 事务传播行为
timeout: 事务超时时间
示例配置
@Transactional(
rollbackFor = Exception.class, // 所有异常都回滚
timeout = 30, // 30秒超时
isolation = Isolation.READ_COMMITTED // 隔离级别
)
public void customTransaction() {
// 自定义事务配置
}