SpringBoot JPA 学习总结
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 集成依赖
[code]<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 配置
[code]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 配置需要注意
[code]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的下一个值。
[code]public enum GenerationType { TABLE, SEQUENCE, IDENTITY, AUTO; private GenerationType() { } }
@Column 标注列属性,大部分属性同数据库表字段,长度,是否非空等。
(2) 基本常用接口
创建Repository 接口 继承 JpaRepository<T,ID> ,基本常用操作都可以通过此接口完成。
[code]public interface AddressRepository extends JpaRepository<Address, Long> { }
[code]@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 使用对象的方式进行, 参数通过?数字的形式传递,参数内容为方法中的参数值
[code]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); }
[code]@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) 复杂查询
[code]# 定义接口返回信息 public interface UserInfo { String getUserName(); String getEmail(); String getHobby(); String getIntroduction(); }
[code]# 定义多表连接返回内容 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); }
[code] @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)条件组合查询
[code]# 定义接口 public interface UserDetailService { public Page<UserDetail> findByCondition(UserDetailParam detailParam, Pageable pageable); }
root 当前返回的对象类引用,可以获取对应参数,detailParam 获取参数对应值, cb 参数条件判断。predicates 组合where 条件。
[code]// 定义实现类 @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); }
[code]//定义参数类 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; } }
[code]@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 框架,按需选择就是最好的选择。
- 深入学习spring-boot系列(二)--使用spring-data-jpa
- SpringBoot 自动配置原理学习总结
- Spring Boot和Spring Cloud微服务架构学习(五)-Docker总结
- 基于(SpringMVC+DATAJpa+shiro )的用户管理系统学习的总结
- 从.Net到Java学习第十二篇——SpringBoot+JPA提供跨域接口
- 深入学习spring-boot系列(二)--使用spring-data-jpa
- 基于Spring Boot和Spring Cloud实现微服务架构学习(五)-Docker总结
- SpringDataJPA入门学习总结笔记
- Spring Boot 学习8--使用Jpa
- springboot + jpa 报错问题总结。转自别人的帖子。
- Spring Boot学习总结(6)——SpringBoot解决ajax跨域请求问题的配置
- springboot学习三(springboot结合spring data jpa和freemarker显示)
- SpringBoot学习-支持JPA
- SpringBoot学习之路:03.Spring Boot使用Jpa操作数据库
- SpringBoot学习-(4)集成SpringDataJpa
- 深入学习spring-boot系列(二)--使用spring-data-jpa
- 基于Spring Boot和Spring Cloud实现微服务架构学习(二)-Spring Boot总结
- 学习springboot笔记(四)数据访问之JPA
- 基于Spring Boot和Spring Cloud实现微服务架构学习(五)-Docker总结
- springboot学习总结(一)