spring boot jpa中 Hibernate 注解 @Immutable 的使用场景
入门示例
使用 spring boot jpa 来操作数据库的增删改查是非常方便的,定义完 model 之后,直接定义JPA
即可,后续操作就很丝滑了:
@Table(name = "host_spec_price")
@Data
@Entity
public class BudgetHost {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", insertable = false, nullable = false)
private Long id;
@Column(name = "host_spec")
private String hostSpec;
@Column(name = "host_type")
private String hostType;
@Column(name = "start_date")
private String startDate;
@Column(name = "create_time")
private Timestamp createTime;
@Column(name = "update_time")
private Timestamp updateTime;
}
定义 JPA 接口:
import org.springframework.data.jpa.repository.JpaRepository;
public interface BudgetHostDao extends JpaRepository<BudgetHost, Long> {
}
然后在 Controller 里面就可以用了:
@RestController
@Slf4j
public class BudgetController {
@Resource
private BudgetHostDao budgetHostDao;
@GetMapping("/budget/cloudHostBudget")
public Result<List<BudgetHost>> getCloudHostBudget(String userName) {
List<BudgetHost> list = budgetHostDao.findAll();
log.info("userName = {} execute getCloudHostBudget, query size={}", userName, list.size());
return Result.success(list);
}
}
高级场景
入门例子已经能涵盖CURD 80%的需求了,但有时候我们定义的实体类并不会只是简单的 select,可能还要分组聚合,所以你需要使用 JPA 的 Native Query ,并配合一个新对象或接口来接受聚合场景下的对象返回封装。
这里我总结有两种情况:
- 使用接口接受新聚合结果
- 使用类接受聚合结果
使用接口接受聚合结果
假设我们按表里面 day 字段分组,求 count,那么我就 key 定义一个简单的接口接受结果,然后返会给前端
public interface GroupStatistics {
String getName();
int getValue();
}
JPA 类的定义:
@Query(nativeQuery = true,
value = " select day as name, count(*) as value from table group by day
where create_time between :startDate and :endDate and user like CONCAT('%',:user,'%')
")
List<GroupStatistics> findApprovalStatistics(@Param("user") String user, @Param("startDate") String startDate,@Param("endDate") String endDate);
ok,看起来还是非常简单的,但是这种用法有一个缺点,就是说如果用接口定义,你拿到返回的数据后,就没办法去再次修改返回结果了,因为这是接口不是类,没办法新增属性和修改属性,基于这种情况下,我们再来看使用类接受定制的查询结果
使用类接受聚合结果
model 定义
import lombok.Data;
import org.hibernate.annotations.Immutable;
import javax.persistence.*;
@NamedNativeQuery(name = "CloudHostBudgetDTO.budgetQuery",
query = "select SUBSTRING_INDEX(a.tag, ':', -1) as label, " +
" count(*) as hostCount, " +
" round(sum(b.real_price), 0) as hostPrice, " +
" 0 as cbsPrice, " +
" 0 as cbsCount " +
" from cloud_host_info a " +
" left join host_spec_price b " +
" on a.host_spec = b.host_spec " +
" group by label " +
" order by hostPrice desc;",
resultSetMapping = "cloudHostBudgetDto"
)
@SqlResultSetMapping(
name = "cloudHostBudgetDto",
entities = {
@EntityResult(
entityClass = CloudHostBudgetDTO.class,
fields = {
@FieldResult(name = "label", column = "label"),
@FieldResult(name = "hostCount", column = "hostCount"),
@FieldResult(name = "hostPrice", column = "hostPrice"),
@FieldResult(name = "cbsPrice", column = "cbsPrice"),
@FieldResult(name = "cbsCount", column = "cbsCount")
}
)
}
)
@Data
@Entity
@Immutable //注意这个注解,该 model 只为查询用,它本身的变更不会同步数据库表
public class CloudHostBudgetDTO {
@Id
private String label;
private Integer hostCount;
private Integer hostPrice;
private Integer cbsPrice;
private Integer cbsCount;
}
基于类的封装,我们用的是NamedNativeQuery和SqlResultSetMapping,虽然看着复杂点,但是其灵活性更好,可以预留多个额外字段,方便对有些时候从程序中动态计算结果的赋值,因为有些字段可能并不能从数据库里面全部计算好,所以还需要程序补充一部分,这个时候基于类的封装就很好了,你 Controller 方法里面拿到结果之后,可以继续遍历结果对某些字段进行额外的业务逻辑处理。
Immutable 注解解释
在 Hibernate 中,@Immutable 注解用于标识某个实体类是不可变的,即该实体的对象在持久化之后,其状态不应该被修改。这个注解告诉 Hibernate,不会对该实体进行任何更新或删除操作,比如上面我们的查询结果,就很明显只是为了接受聚合的结果用的,其 model 本身并不会对应数据库里面的任何一个实体表,所以这里必须用Immutable注解标记,明确告诉 Hibernate,当我们修改 model 字段属性时,不要去更新数据库里面的表,因为这个表并不存在,也不需要存在,如果你不加 Immutable 还会 model 属性进行了修改,那么这个时候就会报错,这一点需要注意。
@Immutable 的作用
优化性能
由于标记了 @Immutable 的实体对象不允许修改,Hibernate 在处理这些对象时可以进行一些性能上的优化。例如,Hibernate 不会再为这些对象生成更新语句(UPDATE),也不会尝试为它们执行任何删除操作。这样可以减少数据库交互的次数,从而提高性能,尤其在读取频繁且不修改的场景中。
数据一致性保证
@Immutable 可以确保实体对象的状态不被意外修改。如果有代码尝试对这些对象执行更新操作,Hibernate 会抛出异常。这样可以确保业务逻辑层的一致性,避免不小心对本应保持不变的数据进行修改。
与缓存结合
在 Hibernate 的一级缓存(Session 缓存)和二级缓存中,@Immutable 标记的对象可能会有不同的处理。Hibernate 可以在缓存中保留这些对象,并假定它们不会发生变化,从而减少了缓存失效的风险,提高了缓存命中率。
原文地址:https://blog.csdn.net/u010454030/article/details/143946365
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!