一.概述
Spring Data JPA:是Spring Data 系列的一部分,可以轻松实现基于 JPA 的操作数据库。该模块处理对基于 JPA 的数据访问层的增强支持。它使构建使用数据访问技术的 Spring 驱动的应用程序变得更加容易。
JPA:Java Persistence API Java持久层API技术,Java中提供的一套操作数据库的API接口,就是使用注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
优点:
1.支持多种操作数据库的方式
2.根据实体类 ,自动生成DDL语句
3.支持面向对象查询语言(JPQL)
4.内部封装常用的CRUD方法
5.对应简单操作,支持方法名解析查询
二.快速入门
1.导包
<dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies>
2.配置
spring:datasource:url: jdbc:mysql://39.105.189.141:3307/db_j215data?characterEncoding=UTF-8driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: zzjavatype: com.alibaba.druid.pool.DruidDataSourceinitialSize: 5minIdle: 5maxActive: 20maxWait: 60000logSlowSql: truejpa:database: MySQLshow-sql: truehibernate:ddl-auto: update
3.代码
(1)实体类
@Data@Entity //JPA 标记这是个数据库表的映射类@Table(name = "t_project_group") //标记映射类对应的数据库表名,如果一致,可以省略public class ProjectGroup {@Id //修饰属性,标记主键字段对应的属性@GeneratedValue(strategy = GenerationType.IDENTITY)//标记主键的生成策略,指定自增private Integer id;private String name;private String leaderName;private String projectName;}
(2)持久层
//继承默认接口,JpaRepository,双泛型://1.持久层对应的映射类名//2.注解的数据类型 。默认提供了常用的单表操作方法public interface ProjectGroupDao extends JpaRepository<ProjectGroup,Integer> {}
(3)单元测试
@RunWith(SpringJUnit4ClassRunner.class)@SpringBootTest(classes = DataJpaApplication.class)public class JPATest {@Autowiredprivate ProjectGroupDao dao;//新增或者修改 主键存在修改 ,不存在就是新增@Testpublic void t1(){ProjectGroup g1=new ProjectGroup();g1.setLeaderName("李源2");g1.setName("第一组");g1.setProjectName("Keep");//新增System.err.println(dao.save(g1));}//查询数据@Testpublic void t2(){System.err.println(dao.findAll());}//删除@Testpublic void t3(){dao.deleteById(2);System.err.println(dao.findAll(Sort.by(Sort.Order.desc("id"))));}}
三.核心
1.Spring Data JPA重点
1.实体类
需要记忆的注解
@Entity :修饰类,标记这是个数据库表的映射类
@Table(name = “表名”) :修饰类,标记映射类对应的数据库 表名,如果一致,可以省略
@Id :修饰属性,标记主键字段对应的属性
@GeneratedValue(strategy = GenerationType.IDENTITY):修饰属性,标记主键的生成策略,指定自增,一般配合@Id使用
@Column(length = 长度) :修饰属性,标记属性对应的数据库表的字段信息
2.持久层
_默认的接口:_JpaRepository<映射类的名称,主键的数据类型>
JpaRepository默认提供单表的常用操作,CRUD page sort等
3.开关类
映射层的扫描:@EntityScan(basePackages = “映射类所在的包名”)
4.Spring Data JPA的配置
spring:jpa:database: MySQLshow-sql: truehibernate:ddl-auto: update
2.核心操作:
(1)接口式操作
JpaRepository 提供了默认的常用的单表操作的各种方法,默认自动生成对应的sql语句
(2)JPQL查询
JPQL:面向对象查询语言,跟SQL语句完全不一样,采用面向对象的思维,来操作数据库
表—-类,字段—-类中属性,一条数据—-对象
比如:
sql:select * from 表名 Jpql: from 类名 或者 select new 类名(属性名,……) from 类名
字段换成类的属性,表名换成类名。
(3)方法名解析查询
提供了一种,规则,去定义方法名,可以根据此规则,逆向解析方法名,从而自动生成sql语句
比如:findById(int id)—-方法名解析—- select from 表名 where id=xxx
findByNameLikeAndId—-方法名解析—select from 表名 where name like ‘’ and id=xx
(4)SQL查询
也支持原生SQL语句进行执行sql语句,但是需要在@Query(nativeQuery=true)
多参数的处理:?索引 的格式获取参数,索引从1开始
四、Spring Data JPA综合代码
基于代码实现Spring Data JPA的四种查询
持久层
//继承默认接口,JpaRepository,双泛型:1.持久层对应的映射类名 2.注解的数据类型//默认提供了常用的单表操作方法public interface ProjectGroupDao extends JpaRepository<ProjectGroup,Integer> {//JPQL操作 表--类 字段--属性@Query("from ProjectGroup")List<ProjectGroup> all1();@Query("from ProjectGroup where leaderName like ?1")List<ProjectGroup> all3(String n);//方法名解析查询List<ProjectGroup> findByNameLike(String n);//SQL语句操作@Query(nativeQuery = true,value = "select * from t_project_group where id=?1")ProjectGroup all2(int id);}
测试
//接口的操作@Testpublic void t4(){dao.findAll(Pageable.ofSize(1).withPage(0)).get().forEach(System.out::println);}//JPQL测试@Testpublic void t5(){dao.all1().forEach(System.out::println);dao.all3("%李%").forEach(System.err::println);}//方法名解析查询(方法名规则查询)@Testpublic void t6(){dao.findByNameLike("%三%").forEach(System.out::println);}//sql语句实现查询@Testpublic void t7(){System.err.println(dao.all2(3));}
五、Spring Data JPA附录
1 方法命名规则和对应的JPQL
| Keyword | Sample | JPQL snippet |
|---|---|---|
| Distinct | findDistinctByLastnameAndFirstname | select distinct … where x.lastname = ?1 and x.firstname = ?2 |
| And | findByLastnameAndFirstname | … where x.lastname = ?1 and x.firstname = ?2 |
| Or | findByLastnameOrFirstname | … where x.lastname = ?1 or x.firstname = ?2 |
| Is, Equals | findByFirstname,findByFirstnameIs,findByFirstnameEquals | … where x.firstname = ?1 |
| Between | 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, Null | findByAge(Is)Null | … where x.age is null |
| IsNotNull, NotNull | findByAge(Is)NotNull | … where x.age not null |
| Like | findByFirstnameLike | … where x.firstname like ?1 |
| NotLike | findByFirstnameNotLike | … where x.firstname not like ?1 |
| StartingWith | findByFirstnameStartingWith | … where x.firstname like ?1 (parameter bound with appended %) |
| EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (parameter bound with prepended %) |
| Containing | findByFirstnameContaining | … where x.firstname like ?1 (parameter bound wrapped in %) |
| OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
| Not | findByLastnameNot | … where x.lastname <> ?1 |
| In | findByAgeIn(Collection |
… where x.age in ?1 |
| NotIn | findByAgeNotIn(Collection |
… where x.age not in ?1 |
| True | findByActiveTrue() | … where x.active = true |
| False | findByActiveFalse() | … where x.active = false |
| IgnoreCase | findByFirstnameIgnoreCase | … where UPPER(x.firstname) = UPPER(?1) |
六.注意事项
@PersistenceContext
这是jpa专有的注解,和@Autowired作用差不多,而@Autowired是spring自带的注释, 因为EntityManager不是线程安全的,当多个请求进来的时候,spring会创建多个线程,@PersistenceContext就是用来为每个线程创建一个EntityManager的,而@Autowired只创建了一个,为所有线程共用,有可能报错
在使用EntityManager的时,请采用@PersistenceContext进行注解,而不要使用@Autowired
@Transient 注解: 表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性。
EntityManager
这是JPA中用于增删改查的接口,它的作用相当于一座桥梁,连接内存中的java对象和数据库的数据存储。其接口如下:
托管方式:
EntityManager托管方式由两种:容器托管(EntityManger && PersistenceContext)和应用托管(EntityManagerFactory && PersistenceUnit),比较简单的方式是采用容器托管(EJB容器)。实现方式如下:
@PersistenceContext
private EntityManager entityManager;
@Transactional(rollbackFor = {RuntimeException.class, Exception.class})
@Column(name = “CODE”)
private String code;
@Column和private String code必须有一个和数据库select 后的字段一致
返回值问题:
EntityManager.createNativeQuery(SQL)返回值类型的问题
(1)如果这样写:createNativeQuery(SQL),返回类型就是List list,
(2)如果这样写:createNativeQuery(SQL, User.class),返回类型就是List
但是有一个问题,就比如第二种写法,返回了指定的User类型,但是这个User类必须含有@Entity 注解, 一旦加了这个注解就会生成对应的表, 如果我们不想生成表怎么办呢,假如返回的是多表数据,可能这这个数据就用一次,在生成一个表那不是浪费了吗
使用封装的工具类,即可解决这个问题;
/*** 将数组数据转换为实体类* 此处数组元素的顺序必须与实体类构造函数中的属性顺序一致** @param list 你要转换的对象* @param clazz<T> 转换为什么类型,就是转换成什么类型的实体类* @param model 这里传入的是实例化的实体类对象,必须有全参构造* @return 实体类集合*/List<T> castEntity(List<Object[]> list, Class<T> clazz, Object model);
