我们这里项目使用mysql数据库及spring data jpa进行数据库操作。
第一步,先引入所需依赖:
<!-- spring boot中spring data JPA的依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- mysql依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
然后说一下如何使用
spirng boot 有一个接口,Repository接口
/** <a href="http://www.cpupk.com/decompiler">Eclipse Class Decompiler</a> plugin, Copyright (c) 2017 Chen Chao. */
package org.springframework.data.repository;
import java.io.Serializable;
/**
* Central repository marker interface. Captures the domain type to manage as well as the domain type's id type. General
* purpose is to hold type information as well as being able to discover interfaces that extend this one during
* classpath scanning for easy Spring bean creation.
* <p>
* Domain repositories extending this interface can selectively expose CRUD methods by simply declaring methods of the
* same signature as those declared in {@link CrudRepository}.
*
* @see CrudRepository
* @param <T> the domain type the repository manages
* @param <ID> the type of the id of the entity the repository manages
* @author Oliver Gierke
*/
public interface Repository<T, ID extends Serializable> {
}
该接口为一个空接口,用来标注继承或实现了此接口的类或接口为spring ioc注入的repository bean。
泛型第一个是缩写模块实体bean的类名,第二个为主键类型。
例如:
public interface DogRepository extends PagingAndSortingRepository<Dog, Integer>{
这里注意的是:Dog类一定要被@Entity标注,让Dog被spring管理,不然Dog启动时会报错找不到这个bean。
这里还有三个接口需要介绍:CrudRepository 、PagingAndSortingRepository和JpaRepository
JpaRepository接口是PagingAndSortingRepository子接口。
PagingAndSortingRepository是CrudRepository的子接口。
CrudRepository是repository接口的子接口,
CrudRepository中包含有常用的一些方法,列出源码看一下:
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity
* @return the saved entity
*/
<S extends T> S save(S entity);
/**
* Saves all given entities.
*
* @param entities
* @return the saved entities
* @throws IllegalArgumentException in case the given entity is {@literal null}.
*/
<S extends T> Iterable<S> save(Iterable<S> entities);
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @return the entity with the given id or {@literal null} if none found
* @throws IllegalArgumentException if {@code id} is {@literal null}
*/
T findOne(ID id);
/**
* Returns whether an entity with the given id exists.
*
* @param id must not be {@literal null}.
* @return true if an entity with the given id exists, {@literal false} otherwise
* @throws IllegalArgumentException if {@code id} is {@literal null}
*/
boolean exists(ID id);
/**
* Returns all instances of the type.
*
* @return all entities
*/
Iterable<T> findAll();
/**
* Returns all instances of the type with the given IDs.
*
* @param ids
* @return
*/
Iterable<T> findAll(Iterable<ID> ids);
/**
* Returns the number of entities available.
*
* @return the number of entities
*/
long count();
/**
* Deletes the entity with the given id.
*
* @param id must not be {@literal null}.
* @throws IllegalArgumentException in case the given {@code id} is {@literal null}
*/
void delete(ID id);
/**
* Deletes a given entity.
*
* @param entity
* @throws IllegalArgumentException in case the given entity is {@literal null}.
*/
void delete(T entity);
/**
* Deletes the given entities.
*
* @param entities
* @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
*/
void delete(Iterable<? extends T> entities);
/**
* Deletes all entities managed by the repository.
*/
void deleteAll();
}
@NoRepositoryBean 这个注解标注该接口或类不会被spring 实例化。一般用作父级接口或者类。
可以看到里面有常用的查询 添加 删除等方法。不一一介绍了。看一下返回值。
PagingAndSortingRepository接口还封装了分页和排序两个方法。
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> {
/**
* Returns all entities sorted by the given options.
*
* @param sort
* @return all entities sorted by the given options
*/
Iterable<T> findAll(Sort sort);
/**
* Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
*
* @param pageable
* @return a page of entities
*/
Page<T> findAll(Pageable pageable);
}
然后说使用最多的JpaRepository,他不仅包含前面的基本方法还有分页排序,还封装了一层把返回值从iterable变成list。也封装了一些其他方法。一般是用这个接口即可。使用方式是让自己的业务repository接口继承这个接口或者使用注解。先看这个接口源码:
@NoRepositoryBean
public interface JpaRepository<T, ID extends Serializable>
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
List<T> findAll();
/*
* (non-Javadoc)
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
List<T> findAll(Sort sort);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
*/
List<T> findAll(Iterable<ID> ids);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
*/
<S extends T> List<S> save(Iterable<S> entities);
/**
* Flushes all pending changes to the database.
*/
void flush();
/**
* Saves an entity and flushes changes instantly.
*
* @param entity
* @return the saved entity
*/
<S extends T> S saveAndFlush(S entity);
/**
* Deletes the given entities in a batch which means it will create a single {@link Query}. Assume that we will clear
* the {@link javax.persistence.EntityManager} after the call.
*
* @param entities
*/
void deleteInBatch(Iterable<T> entities);
/**
* Deletes all entities in a batch call.
*/
void deleteAllInBatch();
/**
* Returns a reference to the entity with the given identifier.
*
* @param id must not be {@literal null}.
* @return a reference to the entity with the given identifier.
* @see EntityManager#getReference(Class, Object)
*/
T getOne(ID id);
/* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
*/
@Override
<S extends T> List<S> findAll(Example<S> example);
/* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
*/
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
注解方法使用:注意!!!!这个注解和继承repository是一个效果的。所以一般使用继承方式。
@RepositoryDefinition(domainClass=Dog.class,idClass=Integer.class)
继承方式使用:这样就可以使用自带方法了。
public interface DogRepository extends JpaRepository<Dog, Integer>{
这里有疑问了,如果常用的方法无法满足使用该怎么办。
那么就需要自定义来进行查询了。
spring boot jpa 有几种进行自定义查询的方式:
1,使用默认约定:
查询方法开头用find、get、read等来查询。后面使用驼峰写法。
以Dog类来举栗:
public Dog findByName(String name); //select * from dog where name = ?
public Dog findDistinctByNameAndSexOrderById(String name,String sex);//select distinct * from dog where name = ? and sex = ? order by id;
public Dog findByNameLike(String name); //select * from dog where name like ?
诸如此类还有很多。
当这些都无法满足使用的话,还有一种方式。使用@Query注解。
@Query有两种使用方式:
一个是使用JPQL,就和以前使用hibernate时差不多,必须关注大小写等问题。
一种是使用原生Sql,就不赘述了。 使用方式:在@Query中使用nativeQuery=true。
JPQL举栗:
@Query("select d from Dog d where d.name = ?1 and d.sex = ?2")
public List<Dog> findByNameAndSex(String name,String sex);
原生SQL举栗:
@Query(value="select * from dog where id = :id",nativeQuery=true)
public Dog findDogById(@Param("id")int value);
这上面使用了两种传值方式:
第一种,使用索引传值。“?x”索引x从1开始。这个要关系到参数的顺序。
第二种,直接赋值。:x 这个可以不关心顺序。但参数列表中的参数要使用@Param标注出来。
没记错的话,使用spring data jpa时进行update或者delete操作时,需要使用@Modifying注解进行标注。
通知spring 这是一个修改或者删除操作,需要事务。在调用此方法的service层,或者该方法中,必须使用事务注解。
举栗:
@Modifying
@Query(value="update dog set remarks = :remarks where id = :id",nativeQuery=true)
public void updateRemarksById(@Param("id")int id,@Param("remarks")String remarks);
service:
@Transactional
public void updateRemarksById(int id,String remarks) {
dogRepository.updateRemarksById(id,remarks);
}
如果没有事务,在程序运行期间会报错。
下面再说一下分页查询。
举栗:
1,使用PagingAndSortingRepository的Page<T> findAll(Pageable pageable);方法
Pageable pageable = new PageRequest(page, SIZE, new Sort(Direction.DESC,"id"));
userService.findAll(pageable);
page:是当前页数。
size:每页显示数量
new sort()第一个是排序方式,后面是排序字段。
2,注解方式:
public Iterable<Dog> findAll(@PageableDefault(page=0,size=5,sort= {"id"},direction=Sort.Direction.ASC)Pageable pageable){
return dogService.findAll(pageable);
}
这里有个坑,使用注解如何将页数传入过来。注解中如何传入页数呢,回来弄明白回来填坑。
3,使用lambda表达式的复杂方式。
public Iterable<Dog> getList(Pageable pageable,String name){
Page<Dog> page = dogRepository.findAll((Root<Dog> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
Expression<String> pathName = root.get("name");
query.where(cb.like(pathName, name));
return null;
},pageable);
return page;
// Page<Dog> page = dogRepository.findAll(new Specification<Dog>() {
// @Override
// public Predicate toPredicate(Root<Dog> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
// Expression<String> pathName = root.get("name");
// query.where(cb.like(pathName, name));
// return null;
// }
// },pageable);
// return page;
}
注释掉的部分和上面的实现是一样的。Specification接口是一个函数式接口。所以可以使用lambda来写。
应该就这么多吧。写的可能有点乱。