spring-data-jpa简介(转载)

转载:

https://blog.csdn.net/matafeiyanll/article/details/124603090

https://blog.csdn.net/qq_42495847/article/details/107991361

JPA全英文名叫Java Persistence API,就是java持久化API,是SUN公司推出的一套基于ORM的规范。

Sun引入新的JPA ORM规范出于两个原因:

其一,简化现有Java EE和Java SE应用开发工作;

其二,Sun希望整合ORM技术,实现天下归一。

Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。

一、JPA基础

整合SpringData JPA
1.导入jar包依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

 

2.添加配置文件

在application.yml中添加datasource配置,或者

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true

属性解析:

ddl.auto 参数的作用主要用于:自动创建、更新、验证数据库表结构,有四个值。
create:每次加载 Hibernate 时都会删除上一次生成的表,然后根据 model 类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop:每次加载 Hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。
update:最常用的属性,第一次加载 Hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 Hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
validate :每次加载 Hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

创建一张entity对象

@Data
@Entity
@Table(name = "task_info")
public class TaskInfo implements Serializable {
    private static final long serialVersionUID = 8247978712837006424L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String projectCode;
    @ApiModelProperty("job名称")
    private String jobName;

    @NotEmpty
    @ApiModelProperty("task名称")
    private String name;
    //前端传
    private Long taskCode;


    String description;

    @NotEmpty
    @ApiModelProperty("任务类型")
    private String taskType;

这里面使用了一些JPA的注解,但JPA注解远不止这些。

基本注解

基本注解包括@Entity、@Table、@Id、@IdClass、@GeneratedValue、@Basic、@Transient、@Column、@Temporal、 @Enumerated、@Lob。

@Entity定义对象将会成为被JPA管理的实体,将映射到指定的数据库表。
@Table指定数据库的表名。
@Id定义属性为数据库的主键,一个实体里面必须有一个。
@IdClass利用外部类的联合主键。
@GeneratedValue为主键生成策略
@Basic表示属性是到数据库表的字段的映射。如果实体的字段上没有任何注解,默认即为@Basic。
@Transient表示该属性并非一个到数据库表的字段的映射,表示非持久化属性,与@Basic作用相反。JPA映射数据库的时候忽略它。
@Column定义该属性对应数据库中的列名。
@Temporal用来设置Date类型的属性映射到对应精度的字段。
@Lob 将属性映射成数据库支持的大对象类型,支持以下两种数据库类型的字段。

关联关系注解
@JoinColumn定义外键关联的字段名称
@OneToOne关联关系
@OneToMany与@ManyToOne可以相对存在,也可只存在一方。
@ManyToMany表示多对多,和@OneToOne、@ManyToOne一样也有单向、双向之分。单向双向和注解没有关系,只看实体类之间是否相互引用。

如果是使用jdbcTemplate或者mybatis,下一步肯定是要写SQL了。使用JPA不需要这一步,直接创建repository接口即可。

public interface TaskInfoRepository extends JpaRepository<TaskInfo, Long> {


     List<TaskInfo> findByProjectCodeAndJobName(String projectCode, String jobName);

     @Transactional
     void deleteByProjectCodeAndJobName(String projectCode, String jobName) ;

}

 二、批量操作

如果直接引入repository,你会发现它已经内置了很多方法,这些方法都用SQL写也都能实现,但不知道要写到猴年马月。
但是你会发现,repository提供了findAll的内置方法,但是我们还有一些saveAll(),updateAll(),deleteAll()的需求,要怎么办?

JPA也考虑到了这个问题,提供了EntityManager供我们使用

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;


@Service
public class TaskInfoService {
    @PersistenceContext
    private EntityManager entityManager;

//jpa 批量更新
    @Transactional
    public void saveAll(List<TaskInfo> taskInfoList) {
        for (TaskInfo taskInfo : taskInfoList) {
            entityManager.persist(taskInfo);
        }

    }

    @Transactional
    public void deleteAll(List<TaskInfo> taskInfoList) {
        for (TaskInfo taskInfo : taskInfoList) {
            entityManager.remove(taskInfo);
        }
    }
}

 

三、自定义SQL

这样不管是单个对象的curd,还是批量对象的增删改查,JPA都可以搞定!

但实际情况可能远比理论复杂,如果实际场景中JPA提供的方法不够用怎么办?

没关系,JPA也是支持自定义SQL的。

案例1:

@Repository
public interface StockRepository extends JpaRepository<IndexCalculated, String> {

    @Query(nativeQuery = true, value = "SELECT `stock_code` AS `stockCode`,`stock_name` AS `stockName`,`stock_display_name` AS `stockDisplayName` FROM `stock_security`")
    List<Map<String, Object>> stockIndexInfoOfStock();

    @Query(nativeQuery = true, value = "SELECT `index_code` AS `stockCode`,`index_name` AS `stockName`,`index_display_name` AS `stockDisplayName` FROM `index_info` WHERE `index_code` IN (SELECT `index_code` FROM `index_calculated`)")
    List<Map<String, Object>> stockIndexInfoOfIndex();

    @Query(nativeQuery = true, value = "SELECT `stock_code` FROM `sector_stock` WHERE `sector_code` IN ?1")
    List<Object> stockOfSector(String[] sectorCodeArr);

    @Query(nativeQuery = true, value = "SELECT `name` AS `sectorName`,`stock_code` AS `stockCode` FROM `industry_sector`,`sector_stock` WHERE industry_sector.`code`=sector_stock.`sector_code`")
    List<Map<String, Object>> industryOfStock();

    @Query(nativeQuery = true, value = "SELECT `index_code` AS `code`,`index_name` AS `name`,`index_display_name` AS `displayName` FROM `index_info` WHERE `index_code` IN (SELECT `index_code` FROM `index_calculated`)")
    List<Map<String, Object>> allIndexInfoOfCalculated();

    @Transactional
    @Modifying
    @Query(nativeQuery = true, value = "INSERT INTO `index_calculated`(`index_code`,`update_time`) VALUES (?1,?2)")
    int updateIndexCalculated(String indexCode, String updateTime);
    

案例2:

//示例1
@Query("select t from Device t where t.deviceSn=:deviceSn and t.deleteFlag=1")
Device findExistDevice(@Param("deviceSn") String deviceSn);
//示例2
@Query("select t from Device t where t.deviceSn=:deviceSn and t.deviceType =:deviceType and t.deleteFlag=1")
Device findExistDevice(@Param("deviceSn") String deviceSn,@Param("deviceType")Integer deviceType);
//示例3
@Query("select t from Device t where t.deviceSn=?1 and t.deviceType = ?2 and t.deleteFlag=1")
Device findDevice(String deviceSn,Integer deviceType);

@Modifying
@Query("update Device t set t.userName =:userName where t.id =:userId")
User updateUserName(@Param("userId") Long userId,@Param("userName") String userName);

 四、唯一键的更新

大家可以发现,jpa只有save,没有update,那我如果想update怎么办?这个时候分为两种情况

1.你有主键ID

jpa就是按照注解更新的,直接save即可

2.没有主键ID,有业务上的unique id

那就通过uniqueID先把对象查询出来,这个时候已经有主键ID了,将主键ID复制到原来要更新的对象上,save即可。

贴一下代码

 @Test
    void save() {
        ProcessInfo byProjectCodeAndJobName = processInfoRepository.findByProjectCodeAndJobName("6012008297568", "job-111");
        ProcessInfo processInfo = new ProcessInfo();
        if (byProjectCodeAndJobName != null) {
            processInfo.setId(byProjectCodeAndJobName.getId());
        }
        processInfo.setJobName("job-111");
        processInfo.setProjectCode("6012008297568");
        processInfo.setLocations("[{\"taskCode\":6076344071520,\"x\":213,\"y\":328},{\"taskCode\":6076344071521,\"x\":600,\"y\":281}]");
        processInfo.setOwnership("default");
        processInfo.setGlobalParams("");
        processInfo.setDescription("job-111-update");
        ProcessInfo save = processInfoRepository.save(processInfo);
        System.out.println(save);
        
    }

 

posted @ 2022-07-04 15:37  Mars.wang  阅读(284)  评论(0编辑  收藏  举报