spring data JPA使用详解

JPA 简介

全称Java Persistence API,是sun提出的一个对象持久化规范

Spring Data Jpa 一个用于简化数据库访问,并支持云服务的开源框架,根据JPA规范封装的一套JPA应用框架。

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

常用注解

@Entity :声明这个类是一个实体类

@Table:指定映射到数据库的表格

@Id :映射到数据库表的主键属性,一个实体只能有一个属性被映射为主键

@GeneratedValue:主键的生成策略

@Column配置单列属性

Spring data Jpa 接口

Repository

仅仅是一个标识,表明任何继承它的均为仓库接口类,方便Spring自动扫描识别

CrudRepository接口

继承Repository,实现了一组CRUD相关的方法

@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> { 
  <S extends T> S save(S entity);//保存 
  <S extends T> Iterable<S> save(Iterable<S> entities);//批量保存 
  T findOne(ID id);//根据id查询一个对象 
  boolean exists(ID id);//判断对象是否存在 
  Iterable<T> findAll();//查询所有的对象 
  Iterable<T> findAll(Iterable<ID> ids);//根据id列表查询所有的对象 
  long count();//计算对象的总个数 
  void delete(ID id);//根据id删除 
  void delete(T entity);//删除对象 
  void delete(Iterable<? extends T> entities);//批量删除 
  void deleteAll();//删除所有 
} 

实例:

@Entity
@Table(name="USER") 
public class User { 
  @Id
  @GeneratedValue
  private Integer id;    
  //账号 
  private String account; 
  //姓名 
  private String name;    
  //密码 
  private String password;    
  // 邮箱 
  private String email; 
} 


写接口,并继承CrudRepository接口:
public interface UserRepository extends CrudRepository<User, Integer> {    
} 


编写测试类:
public class UserRepositoryTest { 
  @Autowired
  private UserRepository dao; 
    
  @Test//保存 
  public void testSave(){ 
    User user = new User(); 
    user.setName("chhliu"); 
    user.setAccount("10000"); 
    user.setEmail("chhliu@.com"); 
    user.setPassword("123456"); 
    dao.save(user); 
  } 
    
  @Test//批量保存 
  public void testSave1(){ 
    List<User> users = new ArrayList<User>(); 
    User user = new User(); 
    user.setName("tanjie"); 
    user.setAccount("10000"); 
    user.setEmail("tanjie@.com"); 
    user.setPassword("123456"); 
    users.add(user); 
    user = new User(); 
    user.setName("esdong"); 
    user.setAccount("10000"); 
    user.setEmail("esdong@.com"); 
    user.setPassword("123456"); 
    users.add(user); 
    ...//省略部分
    dao.save(users); 
  } 
    
  @Test//更新 
  public void testUpdate(){ 
    User user = dao.findOne(1); 
    user.setPassword("123890");// 要想这样实现更新的功能,需要在service层加上@Transaction事物注解 
  } 
    
  @Test//删除 
  public void testDelete(){ 
    dao.delete(2); 
  } 
    
  @Test//查询所有 
  public void testFindAll(){ 
    List<User> users = (List<User>) dao.findAll(); 
    System.out.println(JSON.toJSONString(users)); 
  } 
    
  @Test//判断指定的id对象是否存在 
  public void testIsExist(){ 
    boolean isExist = dao.exists(8); 
    System.out.println(isExist); 
  } 
    
  @Test//通过id列表来查询 
  public void testFindUserByIds(){ 
    List<Integer> listIds = new ArrayList<Integer>(); 
    listIds.add(2); 
    listIds.add(4); 
    listIds.add(7); 
    List<User> users = (List<User>) dao.findAll(listIds); 
    System.out.println(JSON.toJSONString(users)); 
  } 
} 

我就只写了一个接口类,并没有实现这个接口类,就可以完成基本的CRUD操作。因为这个接口会自动为域对象创建增删改查方法,供业务层直接使用。

PagingAndSortingRepository

继承CrudRepository,实现了一组分页排序相关的方法

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { 
  Iterable<T> findAll(Sort sort);// 不带分页的排序 
  Page<T> findAll(Pageable pageable);// 带分页的排序 
} 

实例:

编写接口,并继承PagingAndSortingRepository接口:
public interface UserRepositoryWithOrder extends
    PagingAndSortingRepository<User, Integer> {  
} 

编写测试类:
@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional
public class UserRepositoryWithOrderTest { 
  @Autowired
  private UserRepositoryWithOrder dao; 
    
  @Test
  public void testOrder(){ 
    Sort sort = new Sort(Direction.DESC, "id"); 
    Pageable pageable = new PageRequest(0, 5, sort); 
    Page<User> page = dao.findAll(pageable); 
    System.out.println(JSON.toJSONString(page)); 
    System.out.println(page.getSize()); 
  } 
} 

JpaRepository

继承PagingAndSortingRepository,增加批量操作等

public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> { 
  List<T> findAll();//查询所有对象,不排序 
  List<T> findAll(Sort sort);//查询所有对象,并排序 
  <S extends T> List<S> save(Iterable<S> entities);//批量保存 
  void flush();//强制缓存与数据库同步 
  T saveAndFlush(T entity);//保存并强制同步 
  void deleteInBatch(Iterable<T> entities);//批量删除 
  void deleteAllInBatch();//删除所有 
} 

JpaSpecificationExecutor

比较特殊,不属于Repository体系,实现一组JPA Criteria查询相关的方法。Spring data JPA不会自动扫描识别,所以会报找不到对应的Bean,我们只需要继承任意一个继承了Repository的子接口或直接继承Repository接口,Spring data JPA就会自动扫描识别,进行统一的管理。

Spring data JPA查询

@Query 创建查询

@Query 注解的使用非常简单,只需在声明的方法上面标注该注解,同时提供一个 JP QL 查询语句即可。喜欢使用命名参数来代替位置编号,@Query 也对此提供了支持。JP QL 语句中通过": 变量"的格式来指定参数,同时在方法的参数前面使用 @Param 将方法参数与 JP QL 中的命名参数对应。

编写接口,如下:

/** 
 * 描述:自定义查询,当Spring Data JPA无法提供时,需要自定义接口,此时可以使用这种方式 
 */
public interface UserDefineBySelf extends JpaRepository<User, Integer> { 
  /** 
   * 命名参数 
   * 描述:推荐使用这种方法,可以不用管参数的位置 
   */
  @Query("select u from User u where u.name = :name") 
  User findUserByName(@Param("name") String name); 
    
  /** 
   * 索引参数 
   * 描述:使用?占位符 
   */
  @Query("select u from User u where u.email = ?1")// 1表示第一个参数 
  User findUserByEmail(String email); 
    
  /** 
   * 描述:可以通过@Modifying和@Query来实现更新 
   * 注意:Modifying queries的返回值只能为void或者是int/Integer 
   */
  @Modifying
  @Query("update User u set u.name = :name where u.id = :id") 
  int updateUserById(@Param("name") String name, @Param("id") int id); 
} 

测试类:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "classpath:applicationContext-config.xml" }) 
@TransactionConfiguration(defaultRollback = false) 
@Transactional
public class UserDefineBySelfTest { 
  @Autowired
  private UserDefineBySelf dao; 
    
  @Test
  public void testFindUserByName(){ 
    User user = dao.findUserByName("chhliu"); 
    Assert.assertEquals("chhliu", user.getName()); 
    System.out.println(user.getName()); 
  } 
    
  @Test
  public void testFindUserByEmail(){ 
    User user = dao.findUserByEmail("chhliu@.com"); 
    Assert.assertEquals("chhliu", user.getName()); 
    System.out.println(user.getName()); 
  } 
    
  @Test
  public void testUpdateUserById(){ 
    dao.updateUserById("tanjie", 4); 
  } 
} 

@NamedQueries创建查询

用户只需要按照 JPA 规范在 orm.xml 文件或者在代码中使用 @NamedQuery(或 @NamedNativeQuery)定义好查询语句,唯一要做的就是为该语句命名时,需要满足”DomainClass.methodName()”的 命名规则。

通过解析方法名创建查询

顾名思义,就是根据方法的名字,就能创建查询,也许初听起来,感觉很不可思议,等测试后才发现,原来一切皆有可能。

编写接口:

public interface SimpleConditionQueryRepository extends JpaRepository<User, Integer> { 
  /** 
   * 说明:按照Spring data 定义的规则,查询方法以find|read|get开头 
   * 涉及条件查询时,条件的属性用条件关键字连接,要注意的是:条件属性首字母需大写 
   */   
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name = :name and u.email = :email 
   * 参数名大写,条件名首字母大写,并且接口名中参数出现的顺序必须和参数列表中的参数顺序一致 
   */
  User findByNameAndEmail(String name, String email); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name = ?1 or u.password = ?2 
   */
  List<User> findByNameOrPassword(String name, String password); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.id between ?1 and ?2 
   */
  List<User> findByIdBetween(Integer start, Integer end); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.id < ?1 
   */
  List<User> findByIdLessThan(Integer end); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.id > ?1 
   */
  List<User> findByIdGreaterThan(Integer start); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name is null 
   */
  List<User> findByNameIsNull(); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name is not null 
   */
  List<User> findByNameIsNotNull(); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name like ?1 
   */
  List<User> findByNameLike(String name); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name not like ?1 
   */
  List<User> findByNameNotLike(String name); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.password = ?1 order by u.id desc 
   */
  List<User> findByPasswordOrderByIdDesc(String password); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.name <> ?1 
   */
  List<User> findByNameNot(String name); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.id in ?1 
   */
  List<User> findByIdIn(List<Integer> ids); 
    
  /** 
   * 注:此处这个接口相当于发送了一条SQL:select u from User u where u.id not in ?1 
   */
  List<User> findByIdNotIn(List<Integer> ids); 
} 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×