1. 什么是JPA ?
全称Java Persistence API ,通俗来讲就是一套API框架,通过操作相应API,完成实体对象持久化存储到数据库的操作。
2 JPA 能做什么?
ORM映射元数据:通过注解或xml 配置方式,建立对象和表关系。(JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中)
JPA 的API:一套执行CRUD 的操作API。封装了不同的方法进行操作。(用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发者从繁琐的JDBC和SQL代码中解脱出来。)
查询语言:查询sql 时,通过对象进行查询,而非原生SQL.(通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合。)
JPA 本身是一套规范,其他厂商基于JPA 规范做了相应实现,比如Hibernate, Spring Data JPA 等。类似于Log4J 规范,向Logback,Slf4j 等具体实现了日志操作。
3. 接口约定关键字
|
关键字 |
描述 |
方法命名 |
样例 |
|
And |
sql and 条件 |
findByUsernameAndPwd |
where username = ? and pwd = ? |
|
Or |
sql or 条件 |
findByUserNameOrEmail |
where username =? or email=? |
|
Is,Equals |
sql = 条件 |
findById,findByIdEquals |
where id = ? |
|
Between |
sql between 条件 |
findByIdBetween |
where id between ? and ? |
|
LessThan |
sql < 条件 |
findByIdLessThan |
where id < ? |
|
LessThanEquals |
sql <= 条件 |
findByIdLessThanEquals |
where id<=? |
|
GreaterThan |
sql > 条件 |
findByIdGreaterThan |
where id > ? |
|
GreaterThanEquals |
sql >= 条件 |
findByIdGreaterThanEquals |
where id >=? |
|
After |
sql > 条件 |
findByIdAfter |
where id >? |
|
Before |
sql < 条件 |
findByIdBefore |
where id < ? |
|
IsNull |
sql is null |
findByIdIsNull |
where id is null |
|
NotNull |
sql not null |
findByIdNotNull |
where id is not null |
|
Like |
sql like |
findByNameLike |
where name like ? |
|
NotLike |
sql not like |
findByNameNotLike |
where name not like ? |
|
In |
sql in |
findByIdIn(Collection c) |
where id in (?) |
|
NotIn |
sql not in |
findByIdNotIn(Collection c) |
where id not in (?) |
|
StartingWith |
sql like ?% |
findByNameStartingWith |
where name like '?%' |
|
EndingWith |
sql like %? |
findByNameEndingWith |
where name like '%?' |
|
Containing |
sql like %?% |
findByNameContaining |
where name like '%?%' |
4 JPA 集成依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
5. application 配置
spring.datasource.url=jdbc:mysql://IP:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=test
spring.datasource.password=test
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
hbm2ddl.auto 配置需要注意
create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
create-drop:每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
6. JPA 的使用
(1)常用注解:
@Entity 实体标注,数据库表和对象映射
@Id 标注一个字段是ID
@GeneratedValue 标注ID生成策略, 默认使用AUTO ,会在数据库中生成一张表,hibernate_sequence 存储ID的下一个值。
public enum GenerationType {
TABLE,
SEQUENCE,
IDENTITY,
AUTO;
private GenerationType() {
}
}
@Column 标注列属性,大部分属性同数据库表字段,长度,是否非空等。
(2) 基本常用接口
创建Repository 接口 继承 JpaRepository<T,ID> ,基本常用操作都可以通过此接口完成。
public interface AddressRepository extends JpaRepository<Address, Long> {
}
@Resource
private AddressRepository addressRepository;
public void test(){
Address address=new Address();
address.setUserId(1L);
address.setCity("北京");
address.setProvince("北京");
address.setStreet("天安门");
addressRepository.save(address);
}
(3)方法覆盖,SQL 绑定
方法命名规则采用约定规则,SQL 使用对象的方式进行, 参数通过?数字的形式传递,参数内容为方法中的参数值
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);
}
@Resource
private UserRepository userRepository;
public void test(){
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);
List<User> u0 = userRepository.findAll();
Optional<User> u = userRepository.findById(3L);
String name = u.map(e -> e.getNickName()).get();
userRepository.save(user);
user.setId(2L);
userRepository.delete(user);
userRepository.count();
userRepository.estsById(3L);
}
(3) 复杂查询
# 定义接口返回信息
public interface UserInfo {
String getUserName();
String getEmail();
String getHobby();
String getIntroduction();
}
# 定义多表连接返回内容
public interface UserDetailRepository extends JpaSpecificationExecutor<UserDetail>,JpaRepository<UserDetail, Long> {
UserDetail findByHobby(String hobby);
@Query("select u.userName as userName, u.email as email, d.introduction as introduction , d.hobby as hobby from User u , UserDetail d " +
"where u.id=d.userId and d.hobby = ?1 ")
List<UserInfo> findUserInfo(String hobby);
}
@Resource
private UserDetailRepository userDetailRepository;
List<UserInfo> userInfos=userDetailRepository.findUserInfo("钓鱼");
for (UserInfo userInfo:userInfos){
System.out.println("userInfo: "+userInfo.getUserName()+"-"+userInfo.getEmail()+"-"+userInfo.getHobby()+"-"+userInfo.getIntroduction());
}
(4)条件组合查询
# 定义接口
public interface UserDetailService {
public Page<UserDetail> findByCondition(UserDetailParam detailParam, Pageable pageable);
}
root 当前返回的对象类引用,可以获取对应参数,detailParam 获取参数对应值, cb 参数条件判断。predicates 组合where 条件。
// 定义实现类
@Service
public class UserDetailServiceImpl implements UserDetailService{
@Resource
private UserDetailRepository userDetailRepository;
@Override
public Page<UserDetail> findByCondition(UserDetailParam detailParam, Pageable pageable){
return userDetailRepository.findAll((root, query, cb) -> {
List<Predicate> predicates = new ArrayList<Predicate>();
//equal 示例
if (!StringUtils.isNullOrEmpty(detailParam.getIntroduction())){
predicates.add(cb.equal(root.get("introduction"),detailParam.getIntroduction()));
}
//like 示例
if (!StringUtils.isNullOrEmpty(detailParam.getRealName())){
predicates.add(cb.like(root.get("realName"),"%"+detailParam.getRealName()+"%"));
}
//between 示例
if (detailParam.getMinAge()!=null && detailParam.getMaxAge()!=null) {
Predicate agePredicate = cb.between(root.get("age"), detailParam.getMinAge(), detailParam.getMaxAge());
predicates.add(agePredicate);
}
//greaterThan 大于等于示例
if (detailParam.getMinAge()!=null){
predicates.add(cb.greaterThan(root.get("age"),detailParam.getMinAge()));
}
return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
}, pageable);
}
//定义参数类
public class UserDetailParam {
private String userId;
private Integer minAge;
private Integer maxAge;
private String realName;
private String introduction;
private String city;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Integer getMinAge() {
return minAge;
}
public void setMinAge(Integer minAge) {
this.minAge = minAge;
}
public Integer getMaxAge() {
return maxAge;
}
public void setMaxAge(Integer maxAge) {
this.maxAge = maxAge;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public String getIntroduction() {
return introduction;
}
public void setIntroduction(String introduction) {
this.introduction = introduction;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
}
@Resource
private UserDetailService userDetailService;
@Test
public void testFindByCondition() {
int page=0,size=10;
Sort sort = new Sort(Sort.Direction.DESC, "id");
Pageable pageable = PageRequest.of(page, size, sort);
UserDetailParam param=new UserDetailParam();
param.setIntroduction("程序员");
param.setMinAge(10);
param.setMaxAge(30);
Page<UserDetail> page1=userDetailService.findByCondition(param,pageable);
for (UserDetail userDetail:page1){
System.out.println("userDetail: "+userDetail.toString());
}
}
总结,JPA 在Hibernate基础上更简化的封装常用的SQL CURD操作,大大简化的业务持久化操作,有优点也有缺点,复杂组合SQL 上,使用起来比较麻烦, 可以把基本操作和复杂操作分开,可以提高开发效率,具体还是跟团队使用吻合更好,有人喜欢纯SQL,有人系统Mybatis 框架,按需选择就是最好的选择。
深入理解SpringBoot JPA:从基础到实践
本文详细介绍了Java Persistence API (JPA) 的核心概念,包括ORM映射元数据、JPA API、查询语言以及如何在Spring Boot应用中集成和配置JPA。通过对JPA常用注解、Repository接口的探讨,揭示了JPA简化持久化操作的优势,同时也指出了其在复杂查询上的局限性,为开发者选择合适的持久层技术提供了参考。
1156

被折叠的 条评论
为什么被折叠?



