Spring Data JPA基本使用
JPA简介
JPA 即Java Persistence API。是一款持久层框架,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。JPA的对象关系映射(ORM)模型是基于Hibernate。是一款面向对象的ORM框架,JPA不需要关心数据库字段,通过注解将数据库表与实体完成映射,在java中的操作只需要对实体进行操作即可。
ORM简介
ORM(Object-Relational Mapping) 表示对象关系映射。在面向对象的软件开发中,通过ORM,就可以把对象映射到关系型数据库中。只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射。也就是说ORM是建立了一个实体与数据库表的关系,使得开发者对实体的直接操作而不是对数据库的操作,但操作实体也就等同于操作了数据库。 ORM框架还有:MyBatis、Hibernate。
Spring Data JPA
Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。 它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率! Spring Data JPA 让我们解脱了DAO层的操作,基本上所有CRUD都可以依赖于它来实现 在实际的工作工程中,推荐使用Spring Data JPA + ORM(如:hibernate)完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦。
SpringBoot整合JPA
1、导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
</dependencies>
Spring Data JPA默认使用的ORM框架是Hibernate。
2、配置文件
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
username: root
password: 123456
type: com.mysql.cj.jdbc.MysqlDataSource
jpa:
show-sql: true
generate-ddl: true
3、创建Entity
@MappedSuperclass
public class BaseEntity {
@Column(name = "is_del")
private Integer isDel;
@CreatedDate
@Column(name = "created_at", updatable = false)
private Date createdAt;
@LastModifiedDate
@Column(name = "modified_at")
private Date modifiedAt;
}
@Table(name = "sys_user")
@Data
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class SysUser extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name ="user_id")
private Long userId;
@Column(name = "userName", nullable = false,length = 255)
private String userName;
@Column(name = "password")
private String password;
@Column(name = "email")
private String email;
}
3.1、JPA Entity常用注解
注解 | 解释 |
---|---|
@Table | 声明数据库中的表都名字实现实体与数据表映射 |
@Entity | 声明一个类是实体类 |
@Id | 声明主键 |
@GeneratedValue | 设置自动生成策略 |
@Column | 指定持久属性或字段的映射列 |
@MappedSuperclass | 用于抽离出通用属性,并使用MappedSuperclass注解修饰。子类也可继承这些属性 |
注意:
1.标注为@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。
2.标注为@MappedSuperclass的类不能再标注@Entity或@Table注解,也无需实现序列化接口。
4、创建Repository
@Repository
public interface SysUserJpaRepo extends JpaRepository<User,Long>, JpaSpecificationExecutor<User> {
}
4.1、JPA Repository注解
注解 | 解释 |
---|---|
@Repository | 声明接口为Repository |
@NoRepositoryBean | 声明以排除存储库接口,从而避免创建实例。 |
4.2、JPA Repository接口
接口 | 作用 |
---|---|
Repository | Repository接口 |
CrudRepository | 提供CRUD |
PagingAndSortingRepository | 提供分页和排序的方式查询 |
JpaRepository | 继承PagingAndSortingRepository、QueryByExampleExecutor |
JpaRepositoryImplementation | 继承JpaSpecificationExecutor、JpaRepository |
JpaSpecificationExecutor | 提供通过Specification实例的方式查询 |
QueryByExampleExecutor | 提供通过Example实例的方式查询 |
5、创建启动类,
@SpringBootApplication
@EnableJpaRepositories(basePackages = "me.demo.repo")
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class);
}
}
启动后,如果数据库未创建表结构,则自动创建。
6、查询
Spring Data JPA中可以在接⼝中⾃定义⽅法上⾯使⽤ @Query 注解,在该注解中可以使⽤JPQL或SQL来 指定此⽅法被调⽤的时候需要执⾏的sql语⾔是什么。
JPQL(JavaPersistence Query Language)是⼀种⾯向对象的查询语⾔,它在ORM框架中最终会 翻译成为sql进⾏执⾏。在hibernate框架中,这种语句叫做HQL(Hibernate Query Language)。
JPQL是⾯向对象的查询语⾔,在查询语句中,出现的不是表的名字、字段的名字,⽽是类的名字和类中 属性的名字,因为在ORM框架中,类和表,属性和字段都做好了映射关系,所以JPQL最后是可以根据映 射关系转换sql语句的。
JPQL的特点:
- 语句中不能出现表名,列名,只能出现java的类名,属性名,并且区分⼤⼩写
- 语句中出现的关键字和sql语句中的是⼀样的意思,不区分⼤⼩写
- 语句中不能写select * ⽽是要写select 类的别名,或者写select 具体的属性名
@Query("select u from User u where u.name = ?1")
User findByUserName(String name);
该语句中的 ?1 代表第⼀个参数,?2 代表第⼆个参数,不是从0开始
也可以配合 @Param 注解使⽤命名参数(Named Parameters)的⽅式:
@Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname, @Param("firstname") String firstname);
@Query 注解除了⽀持JPQL之外,还可以⽀持原⽣sql语句的编写:
6.1、解析方法名查询
默认的JPA支持解析方法名,创建SQL语句。
如果启动类设置@EnableJpaRepositories(basePackages = "me.demo.repo",queryLookupStrategy = QueryLookupStrategy.Key.USE_DECLARED_QUERY),那么将不支持此方式。
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
SysUser findByUserName(String userName);
SysUser findByUserNameAndEmail(String userName, String email);
SysUser findByUserNameLike(String userName);
}
6.2、分页查询
JPA实现分页在方法中加入Pageable参数
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
Page<SysUser> findByUserNameLike(String userName, Pageable pageable);
}
6.3、Native SQL查询
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
@Query(value = "select * from sys_user where user_name= :username", nativeQuery = true)
Page<SysUser> findUserByName(@Param("username") String userName, Pageable pageable);
}
6.4、HQL
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
@Query(value = "select u from SysUser u where u.userName like :username")
Page<SysUser> findUser(@Param("username") String userName, Pageable pageable);
}
6.5、返回自定义对象
@Data
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class SysUserBo {
private Long userId;
private String userName;
private String password;
private String email;
}
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
//需要全部参数的构造器
@Query(value = "select new me.zk.bo.SysUserBo(u.userId,u.userName,u.password,u.email) " +
"from SysUser u where u.userName= :username")
Page<SysUserBo> findByName(@Param("username") String userName, Pageable pageable);
}
6.6、Example查询
UserJpaRepo继承JpaRepository,拥有QueryByExampleExecutor的能力
@SpringBootTest(classes = JpaApplication.class)
public class JpaTest {
@Autowired
private SysUserJpaRepo sysUserJpaRepo;
@Test
public void testExample() {
SysUser sysUser = new SysUser();
sysUser.setUserName("zk,zjw");
Example<SysUser> example = Example.of(sysUser);
Page<SysUser> all = sysUserJpaRepo.findAll(example, Pageable.unpaged());
System.out.println("find:" + all.getContent());
}
@Test
public void testExampleMatcher() {
SysUser sysUser = new SysUser();
sysUser.setUserName("zk,zjw");
ExampleMatcher matcher = ExampleMatcher.matching().withIgnoreNullValues();
Example<SysUser> example = Example.of(sysUser,matcher);
Page<SysUser> all = sysUserJpaRepo.findAll(example, Pageable.unpaged());
System.out.println("find:" + all.getContent());
}
}
6.7、动态查询(自定义where条件)
@SpringBootTest(classes = JpaApplication.class)
public class JpaTest {
@Autowired
private SysUserJpaRepo sysUserJpaRepo;
//动态条件查询
@Test
public void testDynamicSearch() {
Specification<SysUser> specification = new Specification<SysUser>() {
@Override
public Predicate toPredicate(Root<SysUser> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
List<Predicate> list = new ArrayList<>();
list.add(criteriaBuilder.like(root.get("userName"),"z%"));
return query.where(list.toArray(new Predicate[list.size()])).getRestriction();
}
};
Page<SysUser> all = sysUserJpaRepo.findAll(specification, Pageable.unpaged());
System.out.println(all.getContent());
}
}
6.8、返回Object,自定义转换
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
@Query(value = "select user_id,user_name,email from sys_user where user_name= :username", nativeQuery = true)
List<Map<String,Object>> queryUserByName(@Param("username") String userName);
}
7、自定义删除操作
7.1 Native SQL
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
@Query(nativeQuery = true, value = "delete from sys_user where user_name = :username ")
@Modifying
@Transactional
int deleteByName(@Param("username") String userName);
}
7.2 HQL
@Repository
public interface SysUserJpaRepo extends JpaRepository<SysUser,Long>, JpaSpecificationExecutor<SysUser> {
@Query(value = "delete from SysUser s where s.userId = ?1 ")
@Modifying
@Transactional
int deleteByUserId(Long userId);
}