3

背景:私は教育環境で働いており、昨年の夏、開発者の 1 人が Spring MVC と Hibernate を使用して Java Web アプリケーションを設計および構築しました。ほこりだらけの古い Blackboard プラグインに取って代わったので、9 月に新しい用語で開始され、ユーザーから大きな喜びを得ました。アプリケーションの主な機能は、生徒の目標を設定し、メッセージを残し、生徒へのレポートを作成するために使用されます。

数か月早送りすると、元の開発者は別の場所に移動し、アプリケーションはいくつかの成長痛を抱えています。

ユース ケース シナリオ:教師がログインすると、現在選択されているコースのターゲット、メッセージ、およびレポートの概要と、現在選択されているコースの学生登録のリストとともに、彼らが教えるコースのリストを含むホーム画面が表示されます。コース。コースに含まれるターゲットの数が少ない場合などは、情報をすばやく返すことができます。しかし、情報量が増えるにつれて、読み込みにかかる時間は指数関数的に増加するようです。

調べてみると、その理由が分かった気がします。私はサンプル コースを受講し、レポートを見て何が起こっているかを確認しました。データベースは関連データをミリ秒単位で返し、ブラウザはそれをミリ秒単位でレンダリングしましたが、ブラウザがデータが返されるのを待っている間に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 オブジェクトにそれらを設定し、必要に応じて変換し (グレゴリオ暦を日付形式の文字列に変換するなど)、DTO を返すサービス層の Single メソッド:

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 に変換する正しい方法ですか? 彼が去って以来、私は彼のコードに従っており、新しく追加されたものはすべて同じ方法で行われました。オブジェクトを変換せずにフロントエンドに返すと、結果が 12 秒ではなく 300 ミリ秒を超えて表示されます。

私は彼がプロジェクトのためにここから Spring MVC を学んだことを知っているので、彼は経験豊富な Spring 開発者ではありませんでした。

4

2 に答える 2

3

beny23 が言及したように、Hibernate は遅延読み込みでした (最初に PK のリストを読み込み、データに対して何かを実行するときに残りを読み込みます)。

私が使用した解決策は、通常の JDBC 接続を使用してデータを読み取るための非休止状態の接続を作成することでした。クエリはデータを変換して、必要な形式 (Dates as Strings など) で返されるようにしました。 dto に変換する必要はありません。そのようにして、作業の一部をデータベースにアンロードし、アプリケーションを実行する手間を省きました。

于 2013-01-28T10:55:18.017 に答える
1

これはおそらく問題の原因ではありません (12 秒は巨大です) が、それでも言う価値があります。

(シンプル) DateFormatクラスはスレッドセーフではありません:

日付形式は同期されません。スレッドごとに個別のフォーマット インスタンスを作成することをお勧めします。複数のスレッドが同時にフォーマットにアクセスする場合は、外部で同期する必要があります。

したがって、それらをグローバル クラス属性に格納しないでください。そうしないと、奇妙な問題が発生する可能性があります。簡単なことは、使用する直前に( Simple)をインスタンス化することです。DateFormat

SimpleDateFormat に関するこの興味深いブログ記事も参照してください。

于 2013-01-21T19:50:14.433 に答える