背景:我在教育环境中工作,去年夏天我们的一位开发人员使用Spring MVC和Hibernate设计并构建了一个Java Web应用程序。它在九月份新学期开始时推出,用户非常高兴,因为它取代了一个过时的Blackboard插件。该应用程序的主要功能是为学生设置目标、留言和创建报告。
几个月后,原始开发人员已经离开,该应用程序正在经历一些成长痛苦。
使用案例场景:教师登录后,他们会看到主屏幕,其中包含他们所教授课程的列表,以及当前选定课程的目标、留言和报告概述,以及该课程的学生注册列表。如果一个课程只包含少量目标等信息,则返回信息很快。但随着信息量的增加,加载时间似乎呈指数增长。
经过调查,我想我已经找到了原因。我选择了一个样本课程,并查看了报告,看看发生了什么。我发现数据库在毫秒内返回了相关数据,浏览器也在毫秒内渲染了它,但在浏览器等待数据返回的12秒钟内没有任何操作。在数据库查询完成和前端接收响应之间唯一执行的操作是转换为DTO。
代码:这是DAO层中报告对象的样子
@Entity
@Table(name = "REPORTS")
public class Report implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -7659637777880535914L;
@Id
@GeneratedValue
@Column(name = "REPORT_ID", insertable = true, updatable = false, nullable = false, unique=true)
private Integer reportID;
@Column(name = "DATE_CREATED", insertable = true, updatable = false, nullable = false)
private GregorianCalendar dateCreated;
@Column(name = "DATE_MODIFIED", insertable = true, updatable = true, nullable = true)
private GregorianCalendar dateModified;
@Column(name = "TITLE", insertable = true, updatable = true, nullable = false, length=1000)
private String title;
@Column(name = "CURRENT_PERFORMANCE_GRADE", insertable = true, updatable = true, nullable = false)
private String currentPerformanceGrade;
@Column(name = "TARGET_GRADE", insertable = true, updatable = true, nullable = false)
private String targetGrade;
//VARCHAR(MAX) as this is the main body of the tutor report comments. Here the tutor can write as much content as they like.
@Column(name = "TUTOR_COMMENTS", insertable = true, updatable = true, nullable = false, columnDefinition="VARCHAR(MAX)")
private String tutorComments;
//getters and setters below
}
这里还有其他字段,例如与报告相关联的用户、课程、编写报告的导师等,但为了简单起见,在此处将它们留出。
public class ReportDTO implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 2795129355073929139L;
private Integer reportID;
private String dateCreated;
private String dateModified;
private String title;
private String currentPerformanceGrade;
private String targetGrade;
private String tutorComments;
//getters and setters below
}
主要的区别在于日期对象已经变成了日期格式的字符串,而不是GregorianCalendar对象,这样前端显示的日期就是一个漂亮易读的格式。以下是转换为DTO所涉及的示例。服务层中的单个方法接受DAO对象,从中获取相关字段,将它们设置在新构造的DTO对象中,必要时进行转换(例如将Gregorian Calendar转换为日期格式化字符串),并返回DTO:
public ReportDTO convertToDto(Report daoReport) throws Exception
{
ReportDTO dtoReport = new ReportDTO();
try
{
if(daoReport.getReportID() != null)
{
dtoReport.setReportID(daoReport.getReportID());
}
if(daoReport.getDateCreated() != null)
{
dtoReport.setDateCreated(ReportServiceImpl.ISO_DATE_TIME_FORMAT.format(daoReport.getDateCreated().getTime()));
}
if(daoReport.getDateModified() != null)
{
dtoReport.setDateModified(ReportServiceImpl.ISO_DATE_TIME_FORMAT.format(daoReport.getDateModified().getTime()));
}
if(daoReport.getTitle() != null)
{
dtoReport.setTitle(daoReport.getTitle());
}
if(daoReport.getCurrentPerformanceGrade() != null)
{
dtoReport.setCurrentPerformanceGrade(daoReport.getCurrentPerformanceGrade());
}
if(daoReport.getTargetGrade() != null)
{
dtoReport.setTargetGrade(daoReport.getTargetGrade());
}
if(daoReport.getTutorComments() != null)
{
dtoReport.setTutorComments(daoReport.getTutorComments());
}
return dtoReport;
}
catch(Exception e)
{
Exception myException = new Exception("Exception was thrown while converting a persistent Report object to it's data transport equivalent", e);
throw myException;
}
问题:那么经过所有这些,我的问题是,将DAO转换为DTO的正确方式是什么?自从他离开后,我一直在按照他的代码进行任何新的添加。如果将对象返回到前端而不进行转换,我可以在>300毫秒内看到结果,而不是12秒。
我知道他从这里学习了项目中的Spring MVC,所以他不是一个有经验的Spring开发人员,我也不是,鉴于我们看到如此长的请求时间,我们肯定做错了些什么。
long start = System.currentTimeMillis(); // code to measure; System.out.println("took: " + (System.currentTimeMillis() - start));
- pillingworthconvertToDto
方法中发生(最初可能只查询了PK列表)。将 Hibernate 日志设置为 DEBUG 并逐步执行代码。此外,根据 https://dev59.com/FGoy5IYBdhLWcg3wfeMR,从性能上考虑,拥有 VARCHAR(MAX) 可能不是一个好主意... - beny23