Spring data JPA 理解(默认查询 自定义查询 分页查询)及no session 三种处理方法
简介:Spring Data JPA 其实就是JDK方式(还有一种cglib的方式需要Class)的动态代理 (需要一个接口 有一大堆接口最上边的是Repository接口来自org.springframework.data.repository,
还有CrudRepository接口及一个实现类SimpleJpaRepository),只要有接口就可以查询数据库了,实际上就是proxy的方法,具体查询的方法有两种
一种是简单式就是方法名为findBy+属性名+(AndOrIsEquals等)
另一种是自定义的方法就是属性名是瞎起的向abc xyz什么的根本找不到这个属性,这时就可以用sql或者jpql两种语言
@Query(nativeQuery=false是默认的不用写,可以用jpql语言,value="from standard where name=?")
@Query(nativeQuery=true必须写,代表用sql语言,value="select * from standard where c_name=?")
public List<Standard> findByAbc(String name) 参数就是?
如果是增删改操作还要加上@Modifying
分页:对于分页查询,更是简便
public interface StandardDao extends JpaRepository<Standard, Integer>{ //继承的接口中已经包含分页查询接口中的方法
所以只需要在service的实现类中
@Service
@Transactional
public class StandardServiceImpl implements StandardService { //调用dao接口中看不见的findAll()方法
public Page<Standard> pageQuery(Pageable pageable) {
return standardDao.findAll(pageable);
}
这个PageAble也是个接口,他的实现类封装了page和rows两个浏览器提交过来的参数(发自easyui的datagrid的url请求,要求这个datagrid有pagination属性)
Pageable pageable = new PageRequest(page-1, rows);
注意page的索引是从0开始的,0表示第一页,所以要减一
page是分页查询的页码 rows是每页几条
在Web层的Action中只需要通过Spring框架自动注入Service接口的实现类对象
@Autowired
private StandardService standardService;
调用其中方法
Page<Standard> page = standardService.pageQuery(pageable);
即可得到Page接口的实现类对象,
page对象中的内容正是easyui的datagrid组件中必需的内容,但是名字不同不叫rows而是content
{
"total":86,
"rows":[
{"id":101,"name":"jack","age":20},
{"id":102,"name":"rose","age":21},
{"id":103,"name":"lili","age":22}
]
}
通过page.getTotalElements()获得总记录数"total"
通过page.getContent()获得根据分页查询到内容
通过输出到控制台
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("当前页记录:"+page.getContent());
发现结果分别是Number类型和List集合并不是我们需要的json格式
通过Map集合转换为上边的json格式,把键值设置为我们需要的"rows"
Map<String, Object> map = new HashMap<>();
map.put("total", page.getTotalElements());
map.put("rows", page.getContent());
使用jsonlib的jsonObject转换成json字符串格式
String json = JSONObject.fromObject(map).toString();
发回浏览器
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
保存:页面提交表单<form id="standardForm" action="${pageContext.request.contextPath}/standardAction_save.action" method="post">
找到standardAction_save.action所指向的save方法
用自动注入的service调用save方法
standardService.save(model);
在service的实现类中
@Service
@Transactional
public class StandardServiceImpl implements StandardService {
调用自动注入的dao
@Autowired
private StandardDao standardDao;
的方法
public void save(Standard model) {
standardDao.save(model);
}
这个save(model)方法在dao的接口中看不到,在dao继承的接口CrudRepository中已经定义,增加修改都是save,没有add和update
model来自实现ModelDriven接口
implements ModelDriven<T>
下边是向上抽取出的BaseAction父类
public class BaseAction<T> extends ActionSupport implements ModelDriven<T> {
protected T model;//这里需要new对象的,在构造方法中生成的
public T getModel() {
return model;
}
//子类action创建,父类无参构造执行,获取子类继承BaseAction中泛型Class
/*
* 参数化类型Type:BaseAction<Standard> -- cn.itcast.bos.web.action.common.BaseAction<cn.itcast.bos.base.Standard>
* 实际类型参数:《》中class叫实际类型参数
* */
public BaseAction() {
try {
//第一步:获取当前运行class-子类
Class clzz = this.getClass();
System.err.println(clzz);
//第二步:获取子类继承父类的class--参数化类型
/*Type getGenericSuperclass() Type:接口 Class是Type实现类
返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。 */
Type type = clzz.getGenericSuperclass();
System.err.println(type);
//将Type接口转为子接口 ParameterizedType
ParameterizedType parameterizedType = (ParameterizedType) type;
//第三步:获取实际类型参数-model对象class
Type[] types = parameterizedType.getActualTypeArguments(); //[cn.itcast.bos.base.Standard]
System.err.println(types);
//将Type接口转为实现类Class
Class clzzzzzzzzzzzz = (Class) types[0];
//第四步:将class实例化
model = (T) clzzzzzzzzzzzz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
//通过属性驱动获取当前页,每页显示记录数
//page-1
protected Integer page;
protected Integer rows;
public void setPage(Integer page) {
this.page = page-1;
}
public void setRows(Integer rows) {
this.rows = rows;
}
/**
* @Description: 将service中查询到Page对象转为分页需要json数据
* @param page
* @param excluds
*
*/
public void java2Json(Page<T> page, String[] excluds){
try {
Map<String, Object> map = new HashMap<>();
map.put("total", page.getTotalElements());
map.put("rows", page.getContent());
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excluds);
String json = JSONObject.fromObject(map, jsonConfig).toString();
System.err.println(json);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description: 将List集合转为json数组
*/
public void java2Json(List list , String[] excluds){
try {
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(excluds);
String json = JSONArray.fromObject(list, jsonConfig).toString();
System.err.println(json);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);
} catch (Exception e) {
e.printStackTrace();
}
}
}
关于no session问题
下边在分页查询快递员时,如果不处理courier实体中外键关联的集合采用懒加载方式而导致no session异常,也就是
Page<Courier> page = courierService.pageQuery(model, pageable);执行后已经查询出快递员,但在转json的时候,
session已经关了,懒加载的集合没有session无法加载
解决方法一,
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(new String[]{"fixedAreas", "company"});
忽略掉fixedAreas集合就可以了,不用它
相关代码如下:
@Action("courierAction_pageQuery")
public String pageQuery() throws Exception {
Pageable pageable = new PageRequest(page, rows);
Page<Courier> page = courierService.pageQuery(model, pageable);
this.java2Json(page, new String[]{"fixedAreas"});
/*Map<String, Object> map = new HashMap<>();
map.put("total", page.getTotalElements());
map.put("rows", page.getContent());
//将快递员对象中集合属性fixedAreas排除掉(忽略该属性,最终在快递员对象不存在属性)
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(new String[]{"fixedAreas", "company"});
String json = JSONObject.fromObject(map, jsonConfig).toString();
System.err.println(json);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
ServletActionContext.getResponse().getWriter().write(json);*/
return NONE;
}
解决方法二,
也可以将session(Spring data JPA中是EntityManager)延长至web层
<filter>
<filter-name>openEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
解决方法三
@ManyToMany(fetch=FetchType.EAGER, mappedBy = "couriers")//jpa默认策略 集合形式延迟加载
private Set<FixedArea> fixedAreas = new HashSet<FixedArea>();
Spring data JPA 理解(默认查询 自定义查询 分页查询)及no session 三种处理方法的更多相关文章
- Spring Data JPA整合REST客户端Feign时: 分页查询的反序列化报错的问题
Type definition error: [simple type, class org.springframework.data.domain.Page]; nested exception i ...
- Spring Data JPA基本增删改查和JPQL查询(含完整代码和视频连接)
问题:SpringDataJPA怎么使用? 一.考察目标 主要考核SpringDataJPA的用法 二.题目分析 spring data jpa 的使用步骤(下面有具体实现细节) 1.创建maven工 ...
- Spring Data Jpa+SpringMVC+Jquery.pagination.js实现分页
本博客介绍基于Spring Data这款orm框架加上Jquery.pagination插件实现的分页功能. 介绍一下Spring Data框架 spring Data : Spring 的一个子项目 ...
- Spring Data Jpa 使用@Query标注自定义查询语句
https://blog.csdn.net/daniel7443/article/details/51159865 https://blog.csdn.net/pp_fzp/article/detai ...
- 【spring data jpa】 spring data jpa 中 时间格式设置between and 查询
实例代码: //举报时间 Date createDate = entity.getCreateDate(); if (createDate != null){ predicates.add(cb.be ...
- mysqli:查询数据库中,是否存在数据的三种校验方法
在我们编辑用户登录功能的时候,常常需要对用户输入的信息进行校验,校验的方法就是通过SQL语句进行一个比对,那么我们就需要用到以下三种中的一种进行校验啦 1.使用mysqli_num_rows()校验 ...
- spring data jpa封装specification实现简单风格的动态查询
github:https://github.com/peterowang/spring-data-jpa-demo 单一实体的动态查询: @Servicepublic class AdvancedUs ...
- springboot集成Spring Data JPA数据查询
1.JPA介绍 JPA(Java Persistence API)是Sun官方提出的Java持久化规范.它为Java开发人员提供了一种对象/关联映射工具来管理Java应用中的关系数据.它的出现主要是为 ...
- Spring Data JPA 条件查询的关键字
Spring Data JPA 为此提供了一些表达条件查询的关键字,大致如下: And --- 等价于 SQL 中的 and 关键字,比如 findByUsernameAndPassword(Stri ...
随机推荐
- opencv2.4.10+VS2012配置问题
opencv2.4.10+VS2012配置 作为opencv的初学者,第一个难题想必都一样,如何配置opencv+VS的环境呢?在网上的教程,铺天盖地,但我仍然是尝试了十几次才找到属于自己的那套配置方 ...
- DJango小总结二
1.Django请求的生命周期 武彦涛: 路由系统 -> 试图函数(获取模板+数据=>渲染) -> 字符串返回给用户 2.路由系统 王腾: ...
- XtraTabPage右键菜单(关闭当前页、关闭其它页、所有关闭的实现)
实现的需求: 用户习惯是一个不可忽略的东西,默认这版的dx的tab也木有右键操作,但用户习惯操作如浏览器都有右键关闭功能,故这里实现先dx的该功能 技术实现: (1)在winform的相应控件内,拖入 ...
- Git 基本知识与常用指令
一.Git代码状态转换图 其中: 未被Git跟踪的状态为unstage状态: 已被Git跟踪的状态为stage状态(stage:阶段),因此包括staging状态和staged状态. untrack ...
- 【阿里云产品公测】PTS压力测试最低配ECS性能及评测
PTS是一个性能测试工具,可以使用PTS对自身系统性能在阿里云环境里的状况进行整体评估来找出你的系统性能瓶颈从而优化系统,同时你还可以在了解自己的系统性能指标情况下便于未来新增扩容.在使用PTS前你必 ...
- 64位系统中连接Access数据库文件的一个问题
近日在windows 7 64位系统中编译以前写的程序,发现在连接Access数据库时总是出现异常,提示“Microsoft.Jet.OLEDB.4.0”未在本机注册,同样的代码在32位的xp系统中却 ...
- Sharepoint日志文件增长巨大的解决办法/缩小日志/删除日志
前段时间为公司开发部门建立了TFS平台,其中包括WSS3(MOSS07也可,但是如果不是必须,建议使用轻量级的WSS3).TFS建成之后,程序员们用起来都很满意,总监也很关注. 但是今天早上忽然发现连 ...
- C#设计模式之代理模式(一)
原文地址:http://blog.csdn.net/lovelion/article/details/8227953 代理模式是常用的结构型设计模式之一,当无法直接访问某个对象或访问某个对象存在困难时 ...
- SpringMVC方法接收参数可以为空、默认值设置
- Selenium2学习(十)-- iframe定位
前言 有很多小伙伴在拿163作为登录案例的时候,发现不管怎么定位都无法定位到,到底是什么鬼呢,本篇详细介绍iframe相关的切换 以http://mail.163.com/登录页面10为案例,详细介绍 ...