JPA
JPA是一个ORM(对象关系映射)规范,是一组接口;
像Hibernate、open jpa、eclipse link就是jpa的一种实现
在springboot快速构建项目中的jpa依赖默认就使用的是Hibernate
1.引入依赖
<!--jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
2.SpringBoot配置JPA
server.port=8989
#数据库配置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/jpa?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=111111
#spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
#让字段使用驼峰命名
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#控制台显示sql
spring.jpa.show-sql=true
#格式化sql
spring.jpa.properties.hibernate.format_sql=true
3.jpa实体对象类
@Data
@Entity
@Table(name = "p_user")
@EntityListeners(AuditingEntityListener.class)
public class User {
@Id
@GenericGenerator(name = "myuuid", strategy = "uuid")
@GeneratedValue(generator = "myuuid")
@Column(name = "id")
private String id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;
@CreatedDate
@Column(name = "gmtCreate")
private Date createTime;
@LastModifiedDate
@Column(name = "gmtModified")
private Date updateTime;
}
解释:
如果你要使用主键自增:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@GeneratedValue中strategy的四个选项:
-AUTO主键由程序控制, 是默认选项 ,不设置就是这个
-IDENTITY 主键由数据库生成, 采用数据库自增长, Oracle不支持这种方式
-SEQUENCE 通过数据库的序列产生主键, MYSQL 不支持
-Table 提供特定的数据库产生主键, 该方式更有利于数据库的移植
4.创建Mapper层接口
很简单,直接继承JpaRespository接口即可,其泛型填你要操作的实体类
public interface UserRespository extends JpaRepository<User,String> {
}
这样,你就有了jpa的基本crud了
5.写一个测试接口
1.查询所有:
@RestController
@CrossOrigin
public class TestController {
@Autowired
private UserRespository userRespository;
@GetMapping("/test")
public void test(){
List<User> all = userRespository.findAll();
for (User user : all) {
System.out.println(user);
}
return;
}
}
运行效果:
2.分页查询
//简单的条件分页Example,根据user对象的属性进行匹配
//比如我设置了user的name为cc
//查询时,就生成where name=‘cc’的条件
User user = new User();
user.setName("cc");
Example<User> of = Example.of(user);
//分页查询
Page<User> page = userRespository.findAll(of, PageRequest.of(0, 2, Sort.by("id")));
for (User user1 : page.getContent()) {
System.out.println(user1);
}
效果:
需要注意的是jpa中是从第0页开始分页的’
如果你想使用一些特别的查询条件,比如模糊查询,就可以自定义查询条件:
User user = new User();
user.setName("c");
//自定义查询条件
ExampleMatcher matcher = ExampleMatcher
.matching().
withMatcher("name",ExampleMatcher.GenericPropertyMatchers.contains());
//查询条件对象
Example<User> of = Example.of(user, matcher);
//分页查询
Page<User> page = userRespository.findAll(of, PageRequest.of(0, 4, Sort.by("id")));
for (User user1 : page.getContent()) {
System.out.println(user1);
}
此时就会根据name的值去数据库模糊匹配
结果:
如果你想降序排列:
Sort.by("id").descending()
3.API很多
就不一个一个试了,结合自定义条件查询就能适用于很多情况了
4.JPA命名查询
什么叫命名查询?
JPA可以根据你Respository的接口的方法名来实现查询:
比如,你在Repository接口中定义了一个方法:
List<User> findByEmail(String email);
你不用做其它事,他就会帮我们根据邮箱查找数据,生成where email=?
这时官网爬的,大家可自行参考
关键词 | 样本 | JPQL 片段 |
---|---|---|
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 (参数绑定了 append % ) |
EndingWith | findByFirstnameEndingWith | … where x.firstname like ?1 (参数绑定 prepended % ) |
Containing | findByFirstnameContaining | … where x.firstname like ?1 (参数绑定包裹在% ) |
OrderBy | findByAgeOrderByLastnameDesc | … where x.age = ?1 order by x.lastname desc |
Not | findByLastnameNot | … where x.lastname <> ?1 |
In | findByAgeIn(Collection<Age> ages) | … where x.age in ?1 |
NotIn | findByAgeNotIn(Collection<Age> ages) | … 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) |
5.自己写sql:@Query
@Transactional
@Modifying
@Query(nativeQuery = true, value = "update t_bucket set isDelete=1 where id=?1 ")
int deleteBucket(String id);
6.一对一,一对多。。。。
很简单只需要在实体类中加上注解即可OneToOne、OneToMany
@OneToOne(cascade = CascadeType.ALL,fetch = FetchType.LAZY)
@JoinColumn(name = "表外键")
private Dog dog;
CascadeType:
ALL,
PERSIST,
MERGE,
REMOVE,
REFRESH,
DETACH;
-
CascadeType.PERSIST:级联新增(又称级联保存):对order对象保存时也对items里的对象也会保存。对应EntityManager的presist方法。
例子:只有A类新增时,会级联B对象新增。若B对象在数据库存(跟新)在则抛异常(让B变为持久态)
-
CascadeType.MERGE:级联合并(级联更新):若items属性修改了那么order对象保存时同时修改items里的对象。对应EntityManager的merge方法 。
例子:指A类新增或者变化,会级联B对象(新增或者变化) -
CascadeType.REMOVE:级联删除:对order对象删除也对items里的对象也会删除。对应EntityManager的remove方法。
例子:REMOVE只有A类删除时,会级联删除B类;
-
CascadeType.REFRESH:级联刷新:获取order对象里也同时也重新获取最新的items时的对象。对应EntityManager的refresh(object)方法有效。即会重新查询数据库里的最新数据。
-
CascadeType.ALL:以上四种都是。
FetchType:
1、FetchType.LAZY:懒加载,加载一个实体时,定义懒加载的属性不会马上从数据库中加载。
2、FetchType.EAGER:急加载,加载一个实体时,定义急加载的属性会立即从数据库中加载。
比方User类有两个属性,name跟address,就像百度知道,登录后用户名是需要显示出来的,此属性用到的几率极大,要马上到数据库查,用急加载;
而用户地址大多数情况下不需要显示出来,只有在查看用户资料是才需要显示,需要用了才查数据库,用懒加载就好了。所以,并不是一登录就把用户
的所有资料都加载到对象中,于是有了这两种加载模式。
以上仅是本人学习使用过程中觉得比较实用的,可能存在错误或不准确,第一次接触JPA,多多包含
若后续工作中使用到了JPA,我会把有用的东西更新到此文章