Spring Data JPA-基础使用

简介

Spring Data JPA 是基于JPA标准操作数据库的简化方案,底层默认使用的是 Hibernate 5来实现的。

在Spring Data JPA 中提供常用的CURD的接口实现,很多地方可以直接使用,提高开发效率。

核心接口简介

Spring Data JPA 接口关系如下图

![image-20200623165122198](

JPA使用文档 java jpa curd_JPA

)

Repository接口

Repository接口是Spring Data respository的中心接口,它需要管理域 class 以及域 class 的 ID 类型作为类型 arguments。此接口主要用作标记接口,用于捕获要使用的类型,并帮助您发现扩展此接口的接口。

@Indexed
public interface Repository<T, ID> {
}

CrudRepository接口

CrudRepository接口正如其名,主要提供CURD功能,从源码提供的方法可知,基本的CURD都提供了

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
    <S extends T> S save(S var1);

    <S extends T> Iterable<S> saveAll(Iterable<S> var1);

    Optional<T> findById(ID var1);

    boolean existsById(ID var1);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> var1);

    long count();

    void deleteById(ID var1);

    void delete(T var1);

    void deleteAll(Iterable<? extends T> var1);

    void deleteAll();
}

PagingAndSortingRepository接口

该接口主要用于查询进行分页和排序使用

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
    Iterable<T> findAll(Sort var1);

    Page<T> findAll(Pageable var1);
}

JpaRepository接口

从接口关系可以知道JpaRespository接口 继承了其他接口的所有方法,在平时的使用用通常使用这个接口比较多点

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAllById(Iterable<ID> var1);

    <S extends T> List<S> saveAll(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

QueryByExampleExecutor接口

Respository查询的方式

在respository接口中提供了两种查询方式:

  1. 基于方法名称命名规则查询
  2. 基于@Query注解

基于方法名称命名规则查询

规则: findBy(关键字)+属性名称(属性名称的首字母大写)+查询条件(首字母大写)

关键词

SQL符号

样例

对应JPQL 语句片段

And

and

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

=

findByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

between xxx and xxx

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

<

findByAgeLessThan

… where x.age < ?1

LessThanEqual

<=

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

>

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

>=

findByAgeGreaterThanEqual

… where x.age >= ?1

After

>

findByStartDateAfter

… where x.startDate > ?1

Before

<

findByStartDateBefore

… where x.startDate < ?1

IsNull

is null

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

is not null

findByAge(Is)NotNull

… where x.age not null

Like

like

findByFirstnameLike

… where x.firstname like ?1

NotLike

not like

findByFirstnameNotLike

… where x.firstname not like ?1

StartingWith

like 'xxx%'

findByFirstnameStartingWith

… where x.firstname like ?1(parameter bound with appended %)

EndingWith

like 'xxx%'

findByFirstnameEndingWith

… where x.firstname like ?1(parameter bound with prepended %)

Containing

like '%xxx%'

findByFirstnameContaining

… where x.firstname like ?1(parameter bound wrapped in %)

OrderBy

order by

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

<>

findByLastnameNot

… where x.lastname <> ?1

In

in()

findByAgeIn(Collection ages)

… where x.age in ?1

NotIn

not in()

findByAgeNotIn(Collection ages)

… where x.age not in ?1

TRUE

=true

findByActiveTrue()

… where x.active = true

FALSE

=false

findByActiveFalse()

… where x.active = false

IgnoreCase

upper(xxx)=upper(yyyy)

findByFirstnameIgnoreCase

基于@Query注解

通过使用@Query注解来进行查询,@Query注解其实是通过HQL演变过来

代码如下:

创建接口

@Repository
public interface BookRepository extends org.springframework.data.repository.Repository<Book,Long> {

	/**
	 * 通过书名查找书
	 *
	 * @param name
	 * @return
	 */
	Book findBookByName(String name);

	/**
	 * 更新名称和作者信息
	 * @param name
	 * @param author
	 * @param id
	 */
	@Transactional(rollbackFor = Exception.class)
	@Modifying
	@Query("update Book set name = ?1,author = ?2 where id = ?3")
	void updateNameAndAuthorById(String name,String author,long id);

}

测试:

/**
* @Description:    测试类
* @Author:         ZhangQiang
* @CreateDate:     2020/6/24 9:27
*/
@SpringBootTest
public class BooKTest {

	@Autowired
	private BookService bookService;

	/**
	 * 新增
	 */
	@Test
	public void saveBook(){
		Book book = new Book();
		book.setAuthor("岩井俊二");
		book.setName("情书");
		book.setPrice(50);
		bookService.save(book);

	}

	/**
	 * 通过名称来查找
	 * @throws Exception
	 */
	@Test
	public void findBookByName() throws Exception {
		Book book = bookService.getBookByName("平行的世界");
		System.out.println(book.toString());
	}

	/**
	 * 通过id来更新名称和作者信息
	 */
	@Test
	public void updateNameAndAuthorById(){
		bookService.updateNameAndAuthorById("平凡的世界","路遥",1);
	}

	/**
	 * 更新数据
	 */
	@Test
	public void updatePriceByBook(){
		Book book = new Book();
		book.setId(3);
		book.setPrice(38.0);
		book.setAuthor("岩井俊二");
		book.setName("情书");
		bookService.save(book);
	}

	/**
	 * 分页
	 */
	@Test
	public void findAllPageable(){
		Pageable pageRequest = PageRequest.of(0,2);
		Stream<Book> bookStream = bookService.findAll(pageRequest);
		bookStream.forEach(book -> System.out.println(book.toString()));
	}

}

注意:在JPA中更新数据可以通过@Query来更新,也可以共用save方法,save方法根据传入的实体 id来进行区分,会调用findById方法来查询,如果存在那么就是认为是更新,如果不存在 那么就是新增。

多对多

实体:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Entity
public class User implements Serializable {
	@Id
	@GeneratedValue
	private Long id;

	private String name;

	private String password;

	private Integer age;

	@ManyToMany
	private Set<Role> roles;
}

@Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class Role implements Serializable {
	@Id
	@GeneratedValue
	private Long id;
	@Column
	private String name;
	@ManyToMany(mappedBy = "roles")
	private Set<User> users;
}

接口:

/**
* @Description:    角色接口
* @Author:         ZhangQiang
* @CreateDate:     2020/6/24 14:39
*/
public interface RoleRepository extends JpaRepository<Role,Long> {
}

/**
* @Description:    用户接口
* @Author:         ZhangQiang
* @CreateDate:     2020/6/24 10:39
*/
@Repository
public interface UserRepository extends JpaRepository <User,Long>{
}

实现:

/**
* @Description:    角色实现类
* @Author:         ZhangQiang
* @CreateDate:     2020/6/24 11:17
*/
@Service
public class RoleServiceImpl implements RoleService {
	@Autowired
	private RoleRepository roleRepository;

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void save(Role role) {
		roleRepository.save(role);
	}

	@Override
	public Optional<Role> findById(Long id) {
		return roleRepository.findById(id);
	}
}

/**
* @Description:    用户实现类
* @Author:         ZhangQiang
* @CreateDate:     2020/6/24 10:39
*/
@Service
public class UserServiceImpl implements UserService {
	@Autowired
	private UserRepository userRepository;

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void save(User user) {
		userRepository.save(user);
	}
}

测试:

@SpringBootTest
public class UserTest {

	@Autowired
	private UserService userServiceImpl;
	@Autowired
	private RoleService roleService;
	@Test
	public void saveUser(){
		User user = new User();
		user.setName("xiaozhang");
		user.setPassword("11111");
		user.setAge(18);
		Optional<Role> role = roleService.findById(13L);
		Role role1 = role.get();
		HashSet<Role> set = new HashSet<>();
		set.add(role1);
		//会自动绑定两者之间的关系
		user.setRoles(set);
		userServiceImpl.save(user);

	}

	@Test
	public void saveRole(){
		Role role = new Role();
		role.setName("管理员");
		roleService.save(role);
	}

}