SpringBoot-JPA(一)

什么是JPA

JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。 [1]
Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。

简单来说为是Java 开发人员提供了一种对象/关联映射工具来管理 Java 应用中的关系数据。Hibernate3.2+、TopLink 10.1.3以及OpenJPA都提供了JPA的实现。
JPA的总体思想和现有Hibernate、TopLink、JDO等ORM框架大体一致。总的来说,JPA包括以下3方面的技术:

  • ORM映射元数据:将实体对象持久化到数据库表中。
  • API:执行CRUD操作。
  • 查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。

spring data jpa是spring整合了jpa,现在Spring涉及的方面太广,主要是体现在和第三方工具的整合上。而在与第三方整合这方面,Spring做了持久化这一块的工作,于是就有了Spring-data-**这一系列包。包括,Spring-data-jpa,Spring-data-template,Spring-data-mongodb,Spring-data-redis,还有个民间产品,mybatis-spring。
spring boot jpa是基于 ORM 框架、Jpa 规范的基础上封装的一套 Jpa 应用框架,可使开发者用极简的代码即可实现对数据的访问和操作。ORM提供了包括增删改查等在内的常用功能。但是ORM是没有提供业务层次的数据处理的,而spring-data-jpa提供了业务逻辑的功能,全方位解决用户的需求,使用Spring-data-jpa进行开发的过程中,常用的功能,我们几乎不需要写一条sql语句,企业级应用基本上可以不用写任何一条sql,当然spring-data-jpa也提供自己写sql的方式。

Spring data jpa的使用

创建springboot项目,在pom文件中添加spring-data-jpa和mysql依赖

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>
配置数据库:

在application.properties文件中配置数据库的相关信息

spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=create#自动创建表,也可为update,create-drop,validate,no
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect#数据库方言是.MySQL5InnoDBDialect
spring.jpa.show-sql=true#控制台打印sql语句
spring.jpa.properties.hibernate.format_sql=true#美化sql语句
创建实体类:
@Entity
public class User  {

    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, unique = true)
    private String userName;
    @Column(nullable = false)
    private String passWord;
    @Column(nullable = false, unique = true)
    private String email;
    @Column(nullable = true, unique = true)
    private String nickName;
    @Column(nullable = false)
    private String regTime;
  • @Entity表示该类是一个实体,在项目启动时会在数据库中自动创建一张表,表名可以指定 @Entity(name=""),默认为类名。
  • @Id表示主键, @GeneratedValue表示自动生成主键,可以用参数strategy自定义生成策略。
  • @Column指定生成字段的属性,可以自定义表中对应的name,nullable表示非空,unique表示唯一。也可以不添加@Column注解,默认列名就是属性名。
  • @Transient注解表示在生成数据库中的表时,该属性被忽略,即不生成对应的字段。
创建Dao层接口:

继承JpaRepository

public interface UserRepository extends JpaRepository<User, Long> {

    User findByUserName(String userName);

    User findByUserNameOrEmail(String username, String email);

    @Transactional(timeout = 10)
    @Modifying
    @Query("update User set userName = ?1 where id = ?2")
    int modifyById(String  userName, Long id);

    @Transactional
    @Modifying
    @Query("delete from User where id = ?1")
    void deleteById(Long id);

    @Query("select u from User u where u.email = ?1")
    User findByEmail(String email);

    @Query("select u from User u")
    Page<User> findALL(Pageable pageable);

    Page<User> findByNickName(String nickName, Pageable pageable);

    Slice<User> findByNickNameAndEmail(String nickName, String email,Pageable pageable);


}

自定义的Dao层接口继承自JpaRepository,它提供了一些基本的增删改查,这是JpaRepository默认预先生成的CURD的方法。默认的方法如下:

@Test
public void testBaseQuery() throws Exception {
	User user=new User();
	userRepository.findAll();
	userRepository.findOne(1l);
	userRepository.save(user);
	userRepository.delete(user);
	userRepository.count();
	userRepository.exists(1l);
	// ...
}

添加用户:

public void addUser(User user){
	UserRepository.save(user)

自定义简单的查询方法
如findByUserName,findByUserNameOrEmail(String username, String email)等条件的属性名称与个数要与参数的位置与个数一一对应,JpaRepository能够解析方法名自动生成sql语句,主要的语法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称即可,

关键词举例对应的sql语句
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collection ages)… where x.age in ?1
NotInfindByAgeNotIn(Collection age)… where x.age not in ?1
TRUEfindByActiveTrue()… where x.active = true
FALSEfindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)
JpaRepository查询方法解析流程:

JPA方法名解析流程:

Spring Data JPA框架在进行方法名解析时,会先把方法名多余的前缀截取掉
比如find、findBy、read、readBy、get、getBy,然后对剩下部分进行解析。
假如创建如下的查询:findByUserDepUuid(),框架在解析该方法时,首先剔除findBy,然后对剩下的属性进行解析,假设查询实体为Doc。

1.先判断userDepUuid (根据POJO(Plain Ordinary Java Object简单java对象,实际就是普通java bean)规范,首字母变为小写。)是否是查询实体的一个属性,
如果根据该属性进行查询;如果没有该属性,继续第二步。

2.从右往左截取第一个大写字母开头的字符串(此处为Uuid),然后检查剩下的字符串是否为查询实体的一个属性,
如果是,则表示根据该属性进行查询;如果没有该属性,则重复第二步,继续从右往左截取;最后假设 user为查询实体的一个属性。

3.接着处理剩下部分(DepUuid),先判断 user 所对应的类型是否有depUuid属性
如果有,则表示该方法最终是根据 “ Doc.user.depUuid” 的取值进行查询;
否则继续按照步骤 2 的规则从右往左截取,最终表示根据 “Doc.user.dep.uuid” 的值进行查询。

4.可能会存在一种特殊情况,比如 Doc包含一个 user 的属性,也有一个 userDep 属性,此时会存在混淆。
可以明确在属性之间加上 “_” 以显式表达意图,比如 “findByUser_DepUuid()” 或者 “findByUserDep_uuid()”。

自定义SQL查询
当然,上面这些方法也不能完全满足我们在生产中的需求,所以Spring data jpa还支持自定义查询语句,使用 @Query注解,添加JPQL语句,JPQL是一种面向对象的表达式语言,通过类名和属性访问,而不是数据库中的表名和属性,避免了不同数据库语法的不同。如涉及到删除和修改在需要加上@Modifying.也可以根据需要添加 @Transactional对事物的支持,查询超时的设置等。

分页查询:在查询方法中需要传入参数Pageable

public Page<User> getUserByPage(Pageable pageable){
	int page=1,size=10;
	Sort sort = new Sort(Direction.DESC, "id");
	return UserRepository.findAll(pageable);
	 userRepository.findByUserName("testName", pageable);
	}

使用findAll方法返回Page数据,该对象中包含分页常用数据,总记录数,每页记录数,当前页记录数等。

限制查询
有时候我们只需要查询前N个元素,或者支取前一个实体。

User findFirstByOrderByLastnameAsc();
User findTopByOrderByAgeDesc();
Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
List<User> findFirst10ByLastname(String lastname, Sort sort);
List<User> findTop10ByLastname(String lastname, Pageable pageable);

测试:

@Test
	public void testSave() {
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
		String formattedDate = dateFormat.format(date);
		
		userRepository.save(new User("aa", "aa123456","aa@126.com", "aa",  formattedDate));
		userRepository.save(new User("bb", "bb123456","bb@126.com", "bb",  formattedDate));
		userRepository.save(new User("cc", "cc123456","cc@126.com", "cc",  formattedDate));
	}


	@Test
	public void testBaseQuery() {
		Date date = new Date();
		DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG);
		String formattedDate = dateFormat.format(date);
		User user=new User("ff", "ff123456","ff@126.com", "ff",  formattedDate);
		userRepository.findAll();
		userRepository.findById(3L);
		userRepository.save(user);
		user.setId(2L);
		userRepository.delete(user);
		userRepository.count();
		userRepository.existsById(3L);
	}

	@Test
	public void testCustomSql() {
		userRepository.modifyById("neo",3L);
		userRepository.deleteById(3L);
		userRepository.findByEmail("ff@126.com");
	}


	@Test
	public void testPageQuery()  {
		int page=1,size=2;
		Sort sort = new Sort(Sort.Direction.DESC, "id");
		Pageable pageable = PageRequest.of(page, size, sort);
		userRepository.findALL(pageable);
		userRepository.findByNickName("aa", pageable);
	}


参考文档
Spring Boot(五):Spring Boot Jpa 的使用
[springboot+vue全栈开发实战 ]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值