最近在项目中使用了一下jpa,发现还是挺好用的。这里就来讲一下jpa以及在spring boot中的使用。
在这里我们先来了解一下jpa。
JPA的全称是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基于ORM的规范,内部是由一系列的 接口和抽象类 构成。 JPA通过JDK 5.0注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
jpa的优势
标准化
JPA 是 JCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问API,这保证了基于JPA开发的企业应用能够经过少量的修改就能够在不同的JPA框架下运行。
容器级特性的支持
JPA框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。
简单方便
JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建 Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity 进行注释,JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成。
查询能力
JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是Hibernate HQL的等价物。JPA定义了独特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
高级特性
JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。
基础操作
相关依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.0.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cn.com.codingce</groupId> <artifactId>jpa</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>jpa</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
配置数据库连接信息和JPA配置(本地创建数据库springboot_jpa)
spring.datasource.url=jdbc:mysql://localhost:3306/springboot_jpa?useSSL=false&serverTimezone=CTT spring.datasource.username=root spring.datasource.password=123456 # 打印出 sql 语句 spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=create spring.jpa.open-in-view=false # 创建的表的 ENGINE 为 InnoDB spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL55Dialect
注意:
spring.jpa.hibernate.ddl-auto=create----每次运行该程序,没有表格会新建表格,表内有数据会清空 spring.jpa.hibernate.ddl-auto=create-drop----每次程序结束的时候会清空表 spring.jpa.hibernate.ddl-auto=update----每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新 spring.jpa.hibernate.ddl-auto=validate----运行程序会校验数据与数据库的字段类型是否相同,不同会报错
只限本地测试玩。
实体类
package cn.com.codingce.jpa.entity; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; /** * @Author: Jiangjun * @Date: 2019/10/22 13:01 */ @Entity @Data @NoArgsConstructor public class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(unique = true) private String name; private Integer age; public Person(String name, Integer age) { this.name = name; this.age = age; } }
到此步运行相应的表即可创建,控制台输出语句如下:
数据库相应表创建:
创建操作数据库的 Repository 接口
package cn.com.codingce.jpa.repository; import cn.com.codingce.jpa.entity.Person; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Repository; import java.util.Optional; /** * @Author: Jiangjun * @Date: 2019/10/22 13:04 */ @Repository public interface PersonRepository extends JpaRepository<Person, Long> { /** * 根据 name 来查找 Person * * @param name 用户姓名 * @return */ @Query("select p from Person p where p.name = :name") Optional<Person> findByNameCustomeQuery(@Param("name") String name); /** * 根据 id 更新Person name * * @param id 用户id * @return */ @Query("select p.name from Person p where p.id = :id") String findPersonNameById(@Param("id") Long id); }
这个接口和数据库操作有关,继承JpaRepository。JpaRepository继承自PagingAndSortingRepository接口,JpaRepository基于JPA的Repository接口,极大减少了JPA作为数据访问的代码,JpaRepository是实现Spring Data JPA技术访问数据库的关键接口。
@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); }
继承了JpaRepository就具有了JPA为我们提供好的增删改查、分页以及根据条件查询等方法。
jpa自带方法实战
service层
package cn.com.codingce.jpa.service; import cn.com.codingce.jpa.entity.Person; import cn.com.codingce.jpa.repository.PersonRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; /** * @Author: Jiangjun * @Date: 2019/10/22 13:07 */ @Service public class PersonService { @Autowired private PersonRepository repository; /** * 添加 * * @param person */ @Transactional(rollbackFor = Exception.class) public void save(Person person) { repository.save(person); } /** * 查找用户 * * @param id 用户id * @return */ public Person findById(Long id) { Person person = repository.findById(id) .orElseThrow(RuntimeException::new); return person; } /** * 删除用户 * * @param id 用户id */ public void deleteById(Long id) { repository.deleteById(id); } /** * 删除用户 * * @param person */ public void delete(Person person) { repository.delete(person); } }
测试添加
@SpringBootTest class JpaApplicationTests { @Autowired private PersonService service; @Test void save() { Person person = new Person("SnailClimb", 23); service.save(person); } }
条件查询
单表查询根据 JPA 提供的语法自定义的
带条件的查询
很多时候我们自定义 sql 语句会非常有用。
根据 name 来查找 Person:
@Query("select p from Person p where p.name = :name") Optional<Person> findByNameCustomeQuery(@Param("name") String name);
Person 部分属性查询,避免 select *操作:
@Query("select p.name from Person p where p.id = :id") String findPersonNameById(@Param("id") Long id);
当然也是写在PersonRepository内。