JPA调用EntityManageer实现

JPA调用EntityManageer:

我们在上篇中使用过JPA其中一种方案来访问数据库,就是继承JpaRepository接口,今天我们使用另一种方案来实现JPA的访问数据库。所需要引用的依赖和上篇是一致的,包括实体类的创建在这就不写第二遍了,我们直接看DAO层如何实现.

首先,我们先写一个接口定义查询方法:

public interface JpaEntity {

    List<Address> findAll();

    Address findAddress(Long addressId);
}

然后我们再写一个实现类来实现这个接口:

@Repository
public class JpaEntityImpl implements JpaEntity {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List<Address> findAll() {
        return this.entityManager.createQuery("select t from Address t",Address.class)
                .getResultList();
    }

    @Override
    public Address findAddress(Long addressId) {
        return this.entityManager.createQuery("select t from Address t where t.addressId = ?",Address.class)
                .setParameter(1,addressId)
                .getSingleResult();
    }
}

之后我们先给实体类重写toString方法,便于后面结果的查看:

@Override
    public String toString() {
        return "Address{" +
                "addressId=" + addressId +
                ", userId=" + userId +
                ", addressInfo='" + addressInfo + '\'' +
                '}';
    }

然后我们依旧通过单元测试来验证刚才写的代码的通过性:

@RunWith(SpringRunner.class)
@SpringBootTest
public class JpaEntityImplTest {

    @Autowired
    private JpaEntityImpl jpaEntity;

    @Test
    public void findAll() throws Exception {

        List<Address> list = jpaEntity.findAll();
        System.out.println(list.size());
        for (Address address : list){
            System.out.println(address.toString());
        }
    }

    @Test
    public void findAddress() throws Exception {
        Address address = jpaEntity.findAddress(Long.valueOf(9));
        System.out.println(address.toString());
    }

}

通过测试大家可以看到,我们通过EntityManager访问数据库也是没问题的。

springboot jpa 执行sql 脚本 springboot jpa entitymanager_数据库

springboot jpa 执行sql 脚本 springboot jpa entitymanager_spring-boot_02

大家通过控制台的输出可以看到,其实hibernate在查询数据库时,会自动生成所需要查询的SQL语句。

JPA分页实现

JPA使用Page实现分页:
不知道大家之前实现分页是如何实现的,一般的思路有两种,一个是数据库控制,也就是通过SQL语句,像Mysql的limit啊,SQLserver的Top啊(oracle的分页太复杂不举例了……),还有就是通过代码实现,一般我平时的话会使用PageHelper来实现。当然在SpringBoot中PageHelper也是支持的。

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>4.0.0</version>
</dependency>

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.1.0</version>
</dependency>

不过其实SpringBoot已经有了一个比较强大的分页插件,就是Page,那让我们看看Page在JPA中是如何使用的。
首先,我们在继承JpaRepository写一个findAllAddress方法,传入参数为Pageable,而返回不再是List,而是Page。

Page<Address> findAllAddress(Pageable pageable);

这里Pageable是指需要传入的分页信息,而Page则是分页后的数据内容。我们继续使用测试用例来测试我们的代码。

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Round1Application.class)
public class AddressRepositoryTest {

    @Autowired
    private AddressRepository addressRepository;

    @Test
    public void findAllAddress() throws Exception {

        int page = 0,size = 10;
        Sort sort = new Sort(Sort.Direction.DESC,"addressId");
        Pageable pageable = new PageRequest(page,size,sort);
        Page<Address> a = findAllAddress(pageable);
        System.out.println(a.getTotalPages());
        System.out.println(a.getTotalElements());
        List<Address> aa = a.getContent();
        for (Address u : aa){
            System.out.println(u.toString());
        }
    }

}

这里我们使用Sort来定义根据那一个字段进行排序,起始页一定要注意是从0开始的,而不是从1开始,我们规定每页包含10条内容,为了方便测试,我们在数据库中再加入一些内容:

springboot jpa 执行sql 脚本 springboot jpa entitymanager_数据库_03

好了,我们开始测试我们的代码,发现竟然报错了!!

springboot jpa 执行sql 脚本 springboot jpa entitymanager_spring-boot_04

我们写错什么了呢?看似我们什么也没写错,其实,使用Page来分页在JPA中是有严格的方法名匹配的,如果像这里我们想获得所有数据信息,就必须使用findAll()来作为方法名。我们把之前写的findAll()给注释了,并且将findAllAddress方法改为findAll后再进行测试,法相已经可以通过了,并且分页也为我们按照10条一页进行了划分。

springboot jpa 执行sql 脚本 springboot jpa entitymanager_jpa_05

以上就是使用JPA的分页进行数据分页,其实不得不说,JPA其实是一个比较大的坑,如果不是熟练使用的话,很容易犯错,而且各种错都比较难以排查,比如这种命名规范的错误。所以大家如果使用分页的话,还是暂时先继续PageHelper吧,希望Spring之后能将Page封装的更为完美和易用。