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