0

我有带有 Hibernate 作为 DAL 的 Java (Axis2) webservice。使用 InnoDB 作为 MySql 引擎。

关于性能我有几个问题: 1. 通常抓取速度很快,但时间可能会有所不同,有时查询时间太长?通常需要时间查询的是以下查询: 1 获取用户信息的 Web 服务请求 - 我们在用户表上执行此操作,进行搜索 - “名称如 . 1 获取用户食谱的 Web 服务请求(查询食谱,其中 r.user. userId == userId, userId在webservice中给出) 2.如何配置c3p0连接池以获得最佳性能?

这取自 hibernate.cfg

<property name="connection.autoReconnect">true</property>
  <property name="connection.autoReconnectForPools">true</property>
  <property name="connection.is-connection-validation-required">true</property>
  <property name="hibernate.connection.zeroDateTimeBehavior">convertToNull</property>
  <property name="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
  <property name="hibernate.show_sql">false</property>
  <property name="hibernate.current_session_context_class">thread</property>
  <property name="hibernate.format_sql">true</property>
  <property name="hibernate.use_sql_comments">true</property>
  <property name="hibernate.query.factory_class">org.hibernate.hql.classic.ClassicQueryTranslatorFactory</property>

  <property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
  <property name="hibernate.c3p0.min_size">3</property>
  <property name="hibernate.c3p0.max_size">50</property>
  <property name="hibernate.c3p0.timeout">280</property>
  <property name="hibernate.c3p0.max_statements">50</property>
  <!-- this property forces the revalidation of a connection after the given amount of time (in secs) -->
  <!-- it must be set to LESS than the wait_timout setting for the mysql server (this setting defaults to 28800 secs (8 hours)) -->
  <property name="hibernate.c3p0.idle_test_period">300</property>

以下是调用 2 个方法时使用的 hbm.xml 文件……这是 user.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 21:48:14 27/03/2012 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.icdb.data.User" table="user" catalog="yoavDB">
        <id name="userid" type="java.lang.Integer">
            <column name="userid" />
            <generator class="identity" />
        </id>
        <property name="birthdate" type="string">
            <column name="birthdate" length="50" not-null="true" />
        </property>
        <property name="password" type="string">
            <column name="password" length="100" not-null="true" />
        </property>
        <property name="firstname" type="string">
            <column name="firstname" length="50" not-null="true" />
        </property>
        <property name="lastname" type="string">
            <column name="lastname" length="50" not-null="true" />
        </property>
        <property name="country" type="string">
            <column name="country" length="100" not-null="true" />
        </property>
        <property name="email" type="string">
            <column name="email" length="100" not-null="true" />
        </property>
        <property name="numOfRecipes" type="int">
            <column name="numOfRecipes" not-null="true" />
        </property>
        <property name="picUrl" type="string">
            <column name="picUrl" length="200" />
        </property>
        <property name="rate" type="float">
            <column name="rate" precision="12" scale="0" not-null="true" />
        </property>
        <property name="fewWords" type="string">
            <column name="fewWords" length="200" not-null="true" />
        </property>
        <property name="whatscooking" type="string">
            <column name="whatscooking" length="45" not-null="true" />
        </property>
        <set name="usermessagesesForSenderUserId" table="usermessages" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="senderUserId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Usermessages" />
        </set>
        <set name="usermessagesesForUserId" table="usermessages" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Usermessages" />
        </set>
        <set name="timelines" table="timeline" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Timeline" />
        </set>
        <set name="generaltipses" table="generaltips" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="authorid" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Generaltips" />
        </set>
        <set name="userlastvisitsForVisitedUserId" table="userlastvisit" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="visitedUserId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Userlastvisit" />
        </set>
        <set name="recipes" table="recipe" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="ownerid" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Recipe" />
        </set>
        <set name="userlikeses" table="userlikes" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Userlikes" />
        </set>
        <set name="friendshiptablesForUserBId" table="friendshiptable" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userB_Id" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Friendshiptable" />
        </set>
        <set name="usersForFavUserId" table="userfavchefsync" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userId" not-null="true" />
            </key>
            <many-to-many entity-name="com.icdb.data.User">
                <column name="favUserId" not-null="true" />
            </many-to-many>
        </set>
        <set name="friendshiptablesForUserAId" table="friendshiptable" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userA_Id" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Friendshiptable" />
        </set>
        <set name="usersForUserId" table="userfavchefsync" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="favUserId" not-null="true" />
            </key>
            <many-to-many entity-name="com.icdb.data.User">
                <column name="userId" not-null="true" />
            </many-to-many>
        </set>
        <set name="activitylogsForObjectUserId" table="activitylog" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="objectUserId" />
            </key>
            <one-to-many class="com.icdb.data.Activitylog" />
        </set>
        <set name="userlastvisitsForGuestUserId" table="userlastvisit" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="guestUserId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Userlastvisit" />
        </set>
        <set name="userrecipessyncs" table="userrecipessync" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Userrecipessync" />
        </set>
        <set name="activitylogsForUserId" table="activitylog" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="userId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Activitylog" />
        </set>
        <set name="recipereviews" table="recipereview" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="reviewerid" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Recipereview" />
        </set>
    </class>
</hibernate-mapping>

这是 recipe.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 21:48:14 27/03/2012 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.icdb.data.Recipe" table="recipe" catalog="yoavDB">
        <id name="recipeid" type="java.lang.Integer">
            <column name="recipeid" />
            <generator class="identity" />
        </id>
        <many-to-one name="user" class="com.icdb.data.User" fetch="select">
            <column name="ownerid" not-null="true" />
        </many-to-one>
        <property name="releasedate" type="timestamp">
            <column name="releasedate" length="19" not-null="true" />
        </property>
        <property name="preparationtime" type="int">
            <column name="preparationtime" not-null="true" />
        </property>
        <property name="recipedifficulty" type="int">
            <column name="recipedifficulty" not-null="true" />
        </property>
        <property name="name" type="string">
            <column name="name" length="50" not-null="true" unique="true" />
        </property>
        <property name="description" type="string">
            <column name="description" length="200" />
        </property>
        <property name="lastupdated" type="timestamp">
            <column name="lastupdated" length="19" not-null="true" />
        </property>
        <property name="servecount" type="java.lang.Integer">
            <column name="servecount" />
        </property>
        <property name="complete" type="boolean">
            <column name="complete" not-null="true" />
        </property>
        <property name="category" type="int">
            <column name="category" not-null="true" />
        </property>
        <property name="numOfViews" type="int">
            <column name="numOfViews" not-null="true" />
        </property>
        <property name="indexOfRecipeOfUser" type="int">
            <column name="indexOfRecipeOfUser" not-null="true" />
        </property>
        <property name="picUrl" type="string">
            <column name="picUrl" length="200" />
        </property>
        <property name="numOfLikes" type="int">
            <column name="numOfLikes" not-null="true" />
        </property>
        <property name="calculatedRate" type="float">
            <column name="calculatedRate" precision="12" scale="0" not-null="true" />
        </property>
        <set name="userlastvisits" table="userlastvisit" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="lastViewedRecipeId" />
            </key>
            <one-to-many class="com.icdb.data.Userlastvisit" />
        </set>
        <set name="recipeingredients" table="recipeingredient" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="recipeid" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Recipeingredient" />
        </set>
        <set name="recipereviews" table="recipereview" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="recipeid" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Recipereview" />
        </set>
        <set name="userlikeses" table="userlikes" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="recipeId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Userlikes" />
        </set>
        <set name="activitylogs" table="activitylog" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="objectRecipeId" />
            </key>
            <one-to-many class="com.icdb.data.Activitylog" />
        </set>
        <set name="userrecipessyncs" table="userrecipessync" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="recipeId" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Userrecipessync" />
        </set>
        <set name="recipeinstructions" table="recipeinstruction" inverse="true" lazy="true" fetch="select">
            <key>
                <column name="recipeid" not-null="true" />
            </key>
            <one-to-many class="com.icdb.data.Recipeinstruction" />
        </set>
    </class>
</hibernate-mapping>

友谊表:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 21:48:14 27/03/2012 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.icdb.data.Friendshiptable" table="friendshiptable" catalog="yoavDB">
        <composite-id name="id" class="com.icdb.data.FriendshiptableId">
            <key-property name="userAId" type="int">
                <column name="userA_Id" />
            </key-property>
            <key-property name="userBId" type="int">
                <column name="userB_Id" />
            </key-property>
        </composite-id>
        <many-to-one name="userByUserAId" class="com.icdb.data.User" update="false" insert="false" fetch="select">
            <column name="userA_Id" not-null="true" />
        </many-to-one>
        <many-to-one name="userByUserBId" class="com.icdb.data.User" update="false" insert="false" fetch="select">
            <column name="userB_Id" not-null="true" />
        </many-to-one>
        <property name="status" type="short">
            <column name="status" not-null="true" />
        </property>
        <property name="statusLastChangedDate" type="date">
            <column name="statusLastChangedDate" length="10" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

最后访问:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 21:48:14 27/03/2012 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.icdb.data.Userlastvisit" table="userlastvisit" catalog="yoavDB">
        <composite-id name="id" class="com.icdb.data.UserlastvisitId">
            <key-property name="guestUserId" type="int">
                <column name="guestUserId" />
            </key-property>
            <key-property name="visitedUserId" type="int">
                <column name="visitedUserId" />
            </key-property>
        </composite-id>
        <many-to-one name="userByVisitedUserId" class="com.icdb.data.User" update="false" insert="false" fetch="select">
            <column name="visitedUserId" not-null="true" />
        </many-to-one>
        <many-to-one name="userByGuestUserId" class="com.icdb.data.User" update="false" insert="false" fetch="select">
            <column name="guestUserId" not-null="true" />
        </many-to-one>
        <many-to-one name="recipe" class="com.icdb.data.Recipe" fetch="select">
            <column name="lastViewedRecipeId" />
        </many-to-one>
        <property name="lastVisitTimeStamp" type="timestamp">
            <column name="lastVisitTimeStamp" length="19" not-null="true" />
        </property>
    </class>
</hibernate-mapping>

获取用户信息的 Java 代码:

public String[] getUserInfo(    int visitingUserId,
                                int visitedUserId )
{
    Session session = ICDBHibernateUtil.getSessionFactory().getCurrentSession();
    try
    {
        session.beginTransaction();

        User                user    = (User) session.get(User.class, visitedUserId);
        ArrayList<String>   ret     = new ArrayList<String>();

        // Username
        ret.add( user.getFirstname() + " " + user.getLastname() );

        // Few words
        ret.add( user.getFewWords() );

        // Num of recipes
        ret.add( Integer.toString( user.getNumOfRecipes() ) );

        // Calculated Rank
        ret.add( Float.toString( user.getRate() ) );

        // Pic url
        ret.add( user.getPicUrl() );

        FriendshiptableId   id = new FriendshiptableId( visitingUserId, visitedUserId );
        Friendshiptable     ft = (Friendshiptable)session.get( Friendshiptable.class, id );
        if( ft == null )
        {
            id = new FriendshiptableId( visitedUserId, visitingUserId );
            ft = (Friendshiptable)session.get( Friendshiptable.class, id );
            if( ft == null )
            {
                ret.add( "none" );
            }
            else
            {
                FriendshipRequestStatusEnum status = FriendshipRequestStatusEnum.values()[ ft.getStatus() ];
                switch( status )
                {
                    case PENDING:
                        ret.add( "pending" );
                        break;

                    case ACCEPTED:
                        ret.add( "accepted" );
                        break;

                    case DECLINED:
                        ret.add( "declined" );
                        break;
                }
            }
        }
        else
        {
            FriendshipRequestStatusEnum status = FriendshipRequestStatusEnum.values()[ ft.getStatus() ];
            switch( status )
            {
                case PENDING:
                    ret.add( "pending" );
                    break;

                case ACCEPTED:
                    ret.add( "accepted" );
                    break;

                case DECLINED:
                    ret.add( "declined" );
                    break;
            }
        }

        if( visitingUserId != -1 )
        {
            // Has new stuff....
            UserlastvisitId ulvId   = new UserlastvisitId( visitingUserId, visitedUserId );
            Userlastvisit   ulv     = (Userlastvisit) session.get( Userlastvisit.class, ulvId );
            if( ulv == null )
            {
                // Lets add a new entry
                User visitingUser   = (User) session.load( User.class, visitingUserId );
                User visitedUser    = (User) session.load( User.class, visitedUserId );

                ulv = new Userlastvisit(    ulvId, 
                                            visitingUser, 
                                            visitedUser, 
                                            new Date() );
                session.save( ulv );

                ret.add( "true" );
            }
            else
            {
                List<?> loginResult= session.createQuery("from Recipe r where r.lastupdated >= :lastVisited" )
                        .setDate( "lastVisited", ulv.getLastVisitTimeStamp() )
                        .list();
                if( loginResult.size() > 0 )
                {
                    ret.add( "true" );
                }
                else
                {
                    ret.add( "false" );
                }

                // We need to update the last visit time...
                ulv.setLastVisitTimeStamp( new Date() );
                session.save( ulv );
            }
        }

        session.getTransaction().commit();

        String[] retStr = new String[ret.size()];
        ret.toArray( retStr );

        return retStr;
    }
    catch( RuntimeException e )
    {
        ICDBHibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback();
        throw e;
    }
}

getuserRecipes 方法:

public String[] getUserRecipesNew(  int     visitingUserId,
                                        int     userId,     
                                        int     pageNumber )
    {
        final int       PAGE_SIZE   = 20;

        Session session = ICDBHibernateUtil.getSessionFactory().getCurrentSession();
        try
        {
            session.beginTransaction();

            String hql = "from Recipe r where r.user.userid= :userid";

            Query query = session.createQuery( hql )
                                .setInteger(    "userid",       userId );

            query = query.setFirstResult( PAGE_SIZE * (pageNumber - 1) );
            query.setMaxResults( PAGE_SIZE );

            List<?> recipes = query.list();

            ArrayList<String> ret = new ArrayList<String>();
            if( recipes.size() == PAGE_SIZE )
            {
                // Indicates that might be more results
                ret.add( "true" );
            }
            else
            {
                // No more results
                ret.add( "false" );
            }

            DateFormat df = new SimpleDateFormat("MM/dd/yyyy");

            // Format the Recipes into string
            for( int i = 0; i < recipes.size(); i++ )
            {
                UserlikesId     userLikeId  = new UserlikesId( userId, ((Recipe)recipes.get(i)).getRecipeid() );
                Userlikes       userLike    = (Userlikes) session.get( Userlikes.class, userLikeId );

                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getRecipeid() ) );
                ret.add( ((Recipe)recipes.get(i)).getName() );
                ret.add( ((Recipe)recipes.get(i)).getDescription() );
                ret.add( ((Recipe)recipes.get(i)).getUser().getFirstname() + ((Recipe)recipes.get(i)).getUser().getLastname() );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getRecipedifficulty() ) );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getServecount() ) );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getPreparationtime() ) );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getUser().getUserid() ) );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getNumOfViews() ) );
                ret.add( df.format( ((Recipe)recipes.get(i)).getReleasedate() ) );
                ret.add( (((Recipe)recipes.get(i)).getPicUrl() == null) ? "" : ((Recipe)recipes.get(i)).getPicUrl() );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getCategory() ) );
                ret.add( (userLike==null)?"0":(userLike.isIsLike()?"1":"0") );
                ret.add( Integer.toString( ((Recipe)recipes.get(i)).getNumOfLikes() ) );
            }

            session.getTransaction().commit();

            String[] retStr = new String[ret.size()];
            ret.toArray( retStr );

            return retStr;
        }
        catch( RuntimeException e )
        {
            ICDBHibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback();
            throw e;
        }
    }

一切都写好了吗?应该如何调整它以获得更好的性能?

4

1 回答 1

1

首先衡量什么需要时间。然后尝试在需要的地方进行优化。

如果您的池太小,并且您的并发请求多于池的连接数,那么显然会有延迟。嵌套可能的罪魁祸首是查询:

  • 打开 SQL 日志并查看是否所有 SQL 查询都是必要的(没有不必要的急切获取)
  • 在 MySQL 中检查这些查询的执行计划,并查看是否没有缺少索引。

快速阅读您的代码,您正在执行手动 N + 1 查询:

  1. 菜谱查询
  2. 对于每个食谱,找到一个 Userlikes

您应该使用单个查询在单个查询中加载所有需要的数据。或者至少,您应该使用一个where id in (:setOfUserLikesIds)子句执行一个查询来一次加载所有 Userlikes。

于 2012-05-23T07:03:48.690 回答