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访问数据库也是没问题的。
大家通过控制台的输出可以看到,其实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条内容,为了方便测试,我们在数据库中再加入一些内容:
好了,我们开始测试我们的代码,发现竟然报错了!!
我们写错什么了呢?看似我们什么也没写错,其实,使用Page来分页在JPA中是有严格的方法名匹配的,如果像这里我们想获得所有数据信息,就必须使用findAll()来作为方法名。我们把之前写的findAll()给注释了,并且将findAllAddress方法改为findAll后再进行测试,法相已经可以通过了,并且分页也为我们按照10条一页进行了划分。
以上就是使用JPA的分页进行数据分页,其实不得不说,JPA其实是一个比较大的坑,如果不是熟练使用的话,很容易犯错,而且各种错都比较难以排查,比如这种命名规范的错误。所以大家如果使用分页的话,还是暂时先继续PageHelper吧,希望Spring之后能将Page封装的更为完美和易用。