Spring Data JPA

JPA基础概述

JPA概念

JPA是Java的一个规范。 它用于在Java对象和关系数据库之间保存数据。 JPA充当面向对象的领域模型和关系数据库系统之间的桥梁。
由于JPA只是一个规范,它本身不执行任何操作。 它需要一个实现。 因此,像Hibernate,TopLink和iBatis这样的ORM工具实现了JPA数据持久性规范。
JPA仅仅是一种规范,也就是说JPA仅仅定义了一些接口,而接口是需要实现才能工作的。所以底层需要某种实现,而Hibernate就是实现了JPA接口的ORM框架

传统jdbc存在的问题

  1. 数据库连接频繁的创建和关闭,缺点是浪费数据库资源,影响操作效率。
    解决方法:使用数据库连接池
  2. sql语句是硬编码,如果需求变更需要修改sql,就需要修改java代码,需要重新编译,系统不易维护。
    解决方法:将sql语句 统一配置在文件中,修改sql不需要修改java代码
  3. 通过prepareStatement向占位符设置参数,存在硬编码(参数位置,参数)问题。系统不易维护。
    解决方法:将sql中的占位符及对应的参数类型配置在配置文件中,能过自动输入到映射
  4. 遍历查询结果集存在硬编码(列名)
    解决方法:通过进行 sql查询结果向java对象映射,能过自动输出到映射

ORM概述

orm(Object Relation Mapping)对象关系映射
ORM, 解决了:

  1. 存储: 将对象直接存入数据库
  2. 获取: 直接从数据库中拿去对象

JPA的优缺点

优点

  • 标准化: 提供相同的 API,这保证了基于JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。
  • 简单易用,集成方便: JPA 的主要目标之一就是提供更加简单的编程模型,在 JPA 框架下创建实体和创建 Java 类一样简单,只需要使用 javax.persistence.Entity 进行注释;JPA 的框架和接口也都非常简单,
  • 可媲美JDBC的查询能力: JPA的查询语言是面向对象的,JPA定义了独特的JPQL,而且能够支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。
  • 支持面向对象的高级特性: JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,最大限度的使用面向对象的模型。

缺点

  • 性能上比较差:应用底层要把对象翻译成原始sql,然后连接数据库查询。
  • 不适合复杂查询:复杂查询使用对象映射很不方便,也很复杂,更不容易维护。

SpringDataJPA简介

就是Spring的数据持久化对jpa做了集成,使得jpa使用起来更简单,开发效率更高,单表的增删改查操作都已经实现好了,我们只要调用方法就可以。

初识 SpringDataJPA

pom.xml依赖

<!-- 导入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>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.22</version>
</dependency>

yml文件

server:
  port: 8010
spring:
  datasource:
    url: jdbc:mysql://192.168.137.233:3306/jpa?useUnicode=true&characterEncoding=utf-8
    username: root
    password: root
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update

用户实体类

@Data
@Entity
@Table(name="tb_user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    // 用户名
    private String username;

    // 密码
    private String password;

    // 电话
    private String phone;

    // 盐
    private String salt;


    // 创建时间
    private Date created;

}

UserDao

@Component
public class UserDao {

    @Autowired
    private EntityManager entityManager;

    public List<User> findAll(){
        Query query = entityManager.createQuery("FROM User u");
        List resultList = query.getResultList();
        return resultList;
    }

    public User findById(Long id){
        return entityManager.find(User.class,id);
    }

    public List<User> findNameLike(String str){
        String jpql = "FROM User u WHERE u.username like :username";
        Query query = entityManager.createQuery(jpql);
        query.setParameter("username","%"+str+"%");
        List resultList = query.getResultList();
        return resultList;
    }

    public Object[] nativeQueryById(Long id){
        String sql = "select * from tb_user where id = ?";
        Query query = entityManager.createNativeQuery(sql);
        query.setParameter(1,id);
        return (Object[])query.getSingleResult();

    }


    @Transactional
    public User save(User user){
        return  entityManager.merge(user);
    }

    /**
     * 1.remove方法只能移除执久化对象,不能删除游离对象 即删除的对象必须是通过jpa查询出来的对象
     * 2.jpa查询出来的对象必须和remove方法是在一个事务下完成,否则报错
     * @param id
     */
    @Transactional
    public void delete(Long id){
        User user = findById(id);
        entityManager.remove(user);
    }
}

SpringDataJPA查询方法

Spring Data Common的Repository

Repository(包括子接口)位于Spring Data Common的lib里面,是Spring Data 里面做数据库操作的最底层的抽象接口,最顶级的父接口,源码中什么方法都没有,仅仅起到一个标示作用。
Repository源码如下:

package org.springframework.data.repository;

import org.springframework.stereotype.Indexed;

@Indexed
public interface Repository<T, ID> {
}

CrudRepository方法详解

CrudRepository源码:

@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
    <S extends T> S save(S var1);

    <S extends T> Iterable<S> saveAll(Iterable<S> var1);

    Optional<T> findById(ID var1);

    boolean existsById(ID var1);

    Iterable<T> findAll();

    Iterable<T> findAllById(Iterable<ID> var1);

    long count();

    void deleteById(ID var1);

    void delete(T var1);

    void deleteAll(Iterable<? extends T> var1);

    void deleteAll();
}

CrudRepository 主要的功能是单表的增删改查操作。
编写一个自定义都接口UserCrudRepository 去继承CrudRepository

public interface UserCrudRepository extends CrudRepository<User,Long> {
    public List<User> findUserByUsername(String str);
}

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserCrudRepositoryTest {
    @Autowired
    UserCrudRepository userCrudRepository;

    @Test
    public void findAll(){
        Iterable<User> users = userCrudRepository.findAll();
        System.out.println(users);
    }

    @Test
    public void findById(){
        Optional<User> optional = userCrudRepository.findById(28L);
        User user = optional.get();
        System.out.println(user);
    }

    @Test
    public void save(){
        User user= new User();
        user.setUsername("laogao");
        user.setPhone("13611064315");
        user.setPassword("123456");
        user.setSalt("123");
        user.setCreated(new Date());
        User user1 = userCrudRepository.save(user);
        System.out.println(user1);
    }

    @Test
    public void update(){
        User user= new User();
        user.setId(33L);
        user.setUsername("wangwu");
        user.setPhone("13611064316");
        user.setPassword("123456");
        user.setSalt("123");
        user.setCreated(new Date());
        User user1 = userCrudRepository.save(user);
        System.out.println(user1);
    }

    @Test
    public void delete(){
        User user= new User();
        user.setId(33L);
        userCrudRepository.delete(user);
    }

    @Test
    public void findUserByUsername() {
        List<User> users = userCrudRepository.findUserByUsername("jianganming");
        System.out.println(users);
    }
}

PagingAndSortingRepository方法详解

PagingAndSortingRepository在CrudRepository 中扩展了分页和排序功能
PagingAndSortingRepository源码如下

@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
    Iterable<T> findAll(Sort var1);

    Page<T> findAll(Pageable var1);
}

编写一个自定义都接口UserPagingAndSortingRepository 去继承PagingAndSortingRepository

public interface UserPagingAndSortingRepository 
extends PagingAndSortingRepository<User,Long> {
}

测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserPagingAndSortingRepositoryTest {
    @Autowired
    UserPagingAndSortingRepository userCrudRepository;

    //分页
    @Test
    public void findAll(){
        Pageable pageable  = PageRequest.of(0, 2);
        Page<User> page = userCrudRepository.findAll(pageable);
        System.out.println("总页数:"+page.getTotalPages());
        System.out.println("总条数:"+page.getTotalElements());
        System.out.println("数据:"+page.getContent());
    }


    //排序
    @Test
    public void findAllSort(){
        Iterable<User> users = userCrudRepository.findAll(
                new Sort(Sort.Direction.DESC, "username"));
        System.out.println(users);

    }

    //分页排序一起使用
    @Test
    public void findAllPageAndSort(){
        Sort sort = new Sort(Sort.Direction.DESC, "username");
        Pageable pageable  = PageRequest.of(0, 2,sort);
        Page<User> page = userCrudRepository.findAll(pageable);
        System.out.println("总页数:"+page.getTotalPages());
        System.out.println("总条数:"+page.getTotalElements());
        System.out.println("数据:"+page.getContent());

    }

}

定义查询方法

  1. 定义查询方法的配置
    由于Spring JPA Repository的实现原理是采用动态代理机制,我们可以自己定义查询方法,但是方法名称指定特定的查询,或者通过使用@Query手动定义查询,这取决于实际操作。只需要自定义的Repository继承类Spring Data Common里的Repository接口即可。
    如果想有其他更多默认通用方法的实现,可以选择CrudRepository,PagingAndSortingRepository,JpaRepository等接口。
    如果希望对所暴露对方法有选择性,可以自定义Repository。代码如下
@NoRepositoryBean
public interface BaseRepository<T, ID> extends Repository<T, ID> {
    T getOne(ID id);
    T save(T entity);
}
interface MyRepository extends BaseRepository<User,Long>{
    User findByUsernameAndPassword(String username,String password);
}

  1. 自定义查询方法创建与关键字
    spring data jpa 查询方法有多种,其中最快捷和方便的是方法名查询,命名规则如下
关键字例子JPQL语句
ANDfindByLastnameAndFirstnamewhere x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstnamewhere x.lastname = ?1 or x.firstname = ?2
BetweenfindByStartDateBetweenwhere x.startDate between ?1 and ?2
LessThanfindByAgeLessThanwhere x.age < ?1
GreaterThanfindByAgeGreaterThanwhere x.age > ?1
AfterfindByStartDateAfterwhere x.startDate > ?1
BeforefindByStartDateBeforewhere x.startDate < ?1
IsNullfindByAgeIsNullwhere x.age is null
NotNullfindByAgeNotNullwhere x.age not null
LikefindByFirstnameLikewhere x.firstname like ?1
NotLikefindByFirstnameNotLikewhere x.firstname not like ?1
StartingWithfindByFirstnameStartingWithwhere x.firstname like ?1(parameter bound with appended %)
EndingWithfindByFirstnameEndingWithwhere x.firstname like ?1(parameter bound with prepended %)
ContainingfindByFirstnameContainingwhere x.firstname like ?1(parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDescwhere x.age = ?1 order by x.lastname desc
NotfindByLastnameNotwhere x.lastname <> ?1
InfindByAgeIn(Collection ages)where x.age in ?1
NotInfindByAgeNotIn(Collection age)where x.age not in ?1
TRUEfindByActiveTrue()where x.active = true
FALSEfindByActiveFalse()where x.active = false

查询条件和分页一起使用

Page<User> findUserByPhone(String phone, Pageable pageable);

测试代码

@Test
public void findUserByPhone(){
    Pageable pageable  = PageRequest.of(0, 2);
    Page<User> page = userRepository.findUserByPhone("13600527634",pageable);
    System.out.println("总页数:"+page.getTotalPages());
    System.out.println("总条数:"+page.getTotalElements());
    System.out.println("数据:"+page.getContent());
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值