JPA
这些操作完全不用我们去实现,这些不是我们以往在普通的Spring项目中自己所定义的BaseDao吗?SpringBoot真的是非常体贴,大大减低了我们的工作量。但是更为强大的还在后面。我们通过继承JpaRepository接口,除了可以获得上面的基础CRUD操作方法之外,还可以通过Spring规定的接口命名方法自动创建复杂的CRUD操作,以下是我在Spring Data JPA 文档中找到的命名规则表:
| Keyword | Sample | JPQL snippet |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在当然@Query不止是查询语言也可以用于更新和删除语句,不过需要额外添加@Modifying annotation,由于实验环境我就直接打上@Transactional声明式事务,在正式的开发环境请在你的业务层上写@Transactional,当然你也可以都写上,这样会按照你配置的或者是默认的事务传播机制进行事务传播:
@Modifying
@Transactional(readOnly = false)
@Query("update Weibo w set w.weiboText = :text where w.user = :user")
int setUserWeiboContent(@Param("text")String weiboText,@Param("user")User user);
除了@Query annotation 还可以在Entity类中使用@NamedQuery,定义查询语句。但是笔者觉得还是不及@Query来得直接方便。
@Entity
@Table(name = "users")
@NamedQuery(name = "User.searchUserName",query = "select u from User u where u.username like :username")
public class User {
UserRepository接口定义searchUserName方法即可:
public interface UserRepository extends JpaRepository<User,Long> {
List<User> searchUserName(@Param("username") String username);
四、JpaSpecificationExecutor接口
还记得刚刚暂时忽略的JpaSpecificationExecutor<Weibo>接口继承吗?在WeiboRepository接口中继承JpaSpecificationExecutor<Weibo>接口就可以在外部使用Spring提供的Criteria查询,但是这个查询也存在一些问题~ 以下就是一段范例:
@RequestMapping("/searchWeibo")
public Page<Weibo> searchWeibo(final String username, final String weiboText, final Date startDate, final Date endDate,int pageNo,int pageSize) {
Page<Weibo> page = this.weiboRepository.findAll(new Specification<Weibo>() {
@Override
public Predicate toPredicate(Root<Weibo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
List<Predicate> predicates = new LinkedList<>();
if (!StringUtils.isEmpty(username)) {
//Join有两种方式
// Join<Weibo,User> userJoin = root.join("user",JoinType.INNER);
// predicates.add(criteriaBuilder.equal(userJoin.get("username"), username));
predicates.add(criteriaBuilder.equal(root.get("user").get("username"),username));
}
if (!StringUtils.isEmpty(weiboText)) {
predicates.add(criteriaBuilder.like(root.get("weiboText"), "%" + weiboText + "%"));
}
if(startDate!=null){
predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createDate").as(Date.class),startDate));
}
if(endDate != null){
predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("createDate").as(Date.class),endDate));
}
return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
}
},new PageRequest(pageNo,pageSize));
return page;
}
可以直接使用findAll方法并创建匿名内部类继承Specification即可,实现toPredicate方法返回最终的条件,但是笔者想在这里使用JoinFetch,通过很多方法也未能在toPredicate实现,希望其他大牛走过路过,留下在这里使用joinFetch的方法。
五、普通的DAO
当然我们可以使用最为基础的方法去写DAO。直接@Repository 然后@PersistenceContext。最原始最基本~
@Repository
public class WeiboDao {
@PersistenceContext
private EntityManager entityManager;
@Transactional(readOnly = true)
public List<Weibo> searchWeiboByEm(String username, String weiboText, Date startDate, Date endDate, int pageNo, int pageSize) {
StringBuffer jpql = new StringBuffer("select w from Weibo w join fetch w.user u left join fetch w.comments c where 1=1 ");
Map<String,Object> paramMap = new HashMap<>();
if(!StringUtils.isEmpty(username)){
jpql.append(" and u.username = :username");
paramMap.put("username",username);
}
if(!StringUtils.isEmpty(weiboText)){
jpql.append(" and w.weiboText like :weiboText");
paramMap.put("weiboText","%"+weiboText+"%");
}
if(startDate!=null){
jpql.append(" and w.createDate >= :startDate");
paramMap.put("startDate",startDate);
}
if(endDate != null){
jpql.append(" and w.createDate <= :endDate");
paramMap.put("endDate",endDate);
}
Query query = entityManager.createQuery(jpql.toString());
Set<String> keys = paramMap.keySet();
for (String keyItem : keys) {
query.setParameter(keyItem,paramMap.get(keyItem));
}
return query.setFirstResult(pageNo*pageSize).setMaxResults(pageSize).getResultList();
}
}
六、声明式事务
SpringBoot默认已经帮我们自动配置好了JPATransaction,我们直接使用即可。
直接在Service层测试@Transactional,当然正常的事务隔离级别还有事务传递方式还是和以前Spring一样配置。注意这个@Transactional是Spring提供的,不要错误的使用JPA的@Transactional
@Service
public class WeiboService {
@Autowired
private WeiboRepository weiboRepository;
@Transactional(readOnly = false,isolation = Isolation.READ_COMMITTED)
public List<Weibo> importWeiboList(List<Weibo> weibos, User user){
int index = 0;
Date nowDateTime = new Date(System.currentTimeMillis());
for (Weibo weiboItem: weibos) {
weiboItem.setUser(user);
weiboItem.setCreateDate(nowDateTime);
if(5<=index++){
throw new RuntimeException("Weibo out of limit!!!");
}
this.weiboRepository.save(weiboItem);
}
return weibos;
}
}
posted on 2018-04-17 22:15 yangjingzhi 阅读(363) 评论(0) 收藏 举报
浙公网安备 33010602011771号