Quick start

1.pom引用

在spring boot中可以直接引入stater,该starter默认引入Hibernate依赖。

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

如果使用mysql,还需要引入mysql驱动,使用mongoDB则引入mongoDB驱动。

2.配置

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/databasename
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver //驱动
  jpa:
    hibernate:
     show-sql: true  //日志中显示sql语句,生产环境需关闭

3.定义实体

实体是一个POJO类,属性必须有public的getter, setter方法。

@Entity
@Table(name = "person_info")
public class PersonInfo {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "name", nullable = true, length = 20)
    private String name;

    @Column(name = "agee", nullable = true, length = 4)
    private int age;
}

如果没有定义@Table,@Column;jpa会默认将驼峰命名改为下划线命名映射到数据库。

实体定义常见注解

注解

解释

@Entity

声明类为实体或表。

@Table

声明表名。

@Id

指定的类的属性,用于识别(一个表中的主键)。

@GeneratedValue

指定如何标识属性可以被初始化,例如自动、手动、或从序列表中获得的值。

@Transient

指定的属性,它是不持久的,即:该值永远不会存储在数据库中。

@Column

指定持久属性栏属性。

@Enumerated

设置枚举类型

4.定义仓库

定义参考只需要继承JpaRepository接口即可。spring boot会自动创建接口的实现类。

public interface PersonInfoRepository extends JpaRepository<PersonInfo, Long> {
}

JpaRepository接口泛型两个参数分别表示实体对象类型和实体对象主键(ID)的类型。

实战建议

spring data jpa极大的简化了开发人员对实体持久化的工作,屏蔽了java程序员对数据库的操作。但在日常工作中经常存在各种错误的使用方案,具体说明如下。

1. 实体属性枚举值的定义

与表字段严格耦合的枚举应该定义在Entity类中,必须包含所有值域且没有多于的值。
例如PersonInfo的性别建议如下定义:

public class PersonInfo {
    @Enumerated(EnumType.STRING) 
    private Gender gender;
//... auttribue and getter setter
    
	public enum Gender{
	   unknow, male,female, //maybe some others , you konw -_-
	}
}

JPA默认映射的是@Enumerated(EnumType.ORDINAL) ,这时存储到DB中的是枚举的序号。所以即使我们不添加@Enumerated,JPA也可以正确的把枚举存储到数据库。

2.Repository的定义

Repository接口应该处理通用的实体持久化和查询逻辑,不能出现任何业务逻辑代码。
这样是有业务逻辑的反例:

@Query("SELECT p FROM PersonInfo p WHERE p.gender= 'femal' AND p.age < :age ")
    PersonInfo  findMyGirl(@Param("age ") int age);

JPA场景下建议使用查询出完整Entity后,重置需要更新的属性,然后整体保存Entity。不建议写特定的sql更新某些具体的字段。
比如这样的代码就是更新反例:

@Query("update PersonInfo set status=:status where id=:id")
    int updateStatusById(@Param("status") String status, @Param("id") int id);

2.Repository的使用

原则上不需要将Repository封装一层service给其他service调用。
比如这样纯属累赘:

public class PersonInfoService{
        @Autowired PersonInfoRepository repository ;
    
         public void save(PersonInfo person){
               repository .save(person);
         }
    }

但是如果存在实体相关的通用查询逻辑被不同的service调用,就需要抽出通用的业务逻辑,避免代码重复。比如:

public class PersonInfoService{
       @Autowired 
       PersonInfoRepository repository ;
    
        public List<PersonInfo>  findFemal(){
                repository.findAllByGender(PersonInfo.Gender.female);
         }
    }

参考文献
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

Spring JPA 使用@CreatedDate、@CreatedBy、@LastModifiedDate、@LastModifiedBy 自动生成时间和修改者
https://www.jianshu.com/p/14cb69646195