📄 loader.java
字号:
final EntityKey optionalObjectKey, final Object optionalObject, final List hydratedObjects, final SessionImplementor session) throws HibernateException, SQLException { final String instanceClass = getInstanceClass( rs, i, persister, key.getIdentifier(), session ); final Object object; if ( optionalObjectKey != null && key.equals( optionalObjectKey ) ) { //its the given optional object object = optionalObject; } else { // instantiate a new instance object = session.instantiate( instanceClass, key.getIdentifier() ); } //need to hydrate it. // grab its state from the ResultSet and keep it in the Session // (but don't yet initialize the object itself) // note that we acquire LockMode.READ even if it was not requested LockMode acquiredLockMode = lockMode == LockMode.NONE ? LockMode.READ : lockMode; loadFromResultSet( rs, i, object, instanceClass, key, rowIdAlias, acquiredLockMode, persister, session ); //materialize associations (and initialize the object) later hydratedObjects.add( object ); return object; } private boolean isEagerPropertyFetchEnabled(int i) { boolean[] array = getEntityEagerPropertyFetches(); return array!=null && array[i]; } /** * Hydrate the state an object from the SQL <tt>ResultSet</tt>, into * an array or "hydrated" values (do not resolve associations yet), * and pass the hydrates state to the session. */ private void loadFromResultSet( final ResultSet rs, final int i, final Object object, final String instanceEntityName, final EntityKey key, final String rowIdAlias, final LockMode lockMode, final Loadable rootPersister, final SessionImplementor session) throws SQLException, HibernateException { final Serializable id = key.getIdentifier(); // Get the persister for the _subclass_ final Loadable persister = (Loadable) getFactory().getEntityPersister( instanceEntityName ); if ( log.isTraceEnabled() ) { log.trace( "Initializing object from ResultSet: " + MessageHelper.infoString( persister, id, getFactory() ) ); } boolean eagerPropertyFetch = isEagerPropertyFetchEnabled(i); // add temp entry so that the next step is circular-reference // safe - only needed because some types don't take proper // advantage of two-phase-load (esp. components) TwoPhaseLoad.addUninitializedEntity( key, object, persister, lockMode, !eagerPropertyFetch, session ); //This is not very nice (and quite slow): final String[][] cols = persister == rootPersister ? getEntityAliases()[i].getSuffixedPropertyAliases() : getEntityAliases()[i].getSuffixedPropertyAliases(persister); final Object[] values = persister.hydrate( rs, id, object, rootPersister, cols, eagerPropertyFetch, session ); final Object rowId = persister.hasRowId() ? rs.getObject(rowIdAlias) : null; final AssociationType[] ownerAssociationTypes = getOwnerAssociationTypes(); if ( ownerAssociationTypes != null && ownerAssociationTypes[i] != null ) { String ukName = ownerAssociationTypes[i].getRHSUniqueKeyPropertyName(); if (ukName!=null) { final int index = ( (UniqueKeyLoadable) persister ).getPropertyIndex(ukName); final Type type = persister.getPropertyTypes()[index]; // polymorphism not really handled completely correctly, // perhaps...well, actually its ok, assuming that the // entity name used in the lookup is the same as the // the one used here, which it will be EntityUniqueKey euk = new EntityUniqueKey( rootPersister.getEntityName(), //polymorphism comment above ukName, type.semiResolve( values[index], session, object ), type, session.getEntityMode(), session.getFactory() ); session.getPersistenceContext().addEntity( euk, object ); } } TwoPhaseLoad.postHydrate( persister, id, values, rowId, object, lockMode, !eagerPropertyFetch, session ); } /** * Determine the concrete class of an instance in the <tt>ResultSet</tt> */ private String getInstanceClass( final ResultSet rs, final int i, final Loadable persister, final Serializable id, final SessionImplementor session) throws HibernateException, SQLException { if ( persister.hasSubclasses() ) { // Code to handle subclasses of topClass Object discriminatorValue = persister.getDiscriminatorType().nullSafeGet( rs, getEntityAliases()[i].getSuffixedDiscriminatorAlias(), session, null ); final String result = persister.getSubclassForDiscriminatorValue( discriminatorValue ); if ( result == null ) { //woops we got an instance of another class hierarchy branch throw new WrongClassException( "Discriminator: " + discriminatorValue, id, persister.getEntityName() ); } return result; } else { return persister.getEntityName(); } } /** * Advance the cursor to the first required row of the <tt>ResultSet</tt> */ private void advance(final ResultSet rs, final RowSelection selection) throws SQLException { final int firstRow = getFirstRow( selection ); if ( firstRow != 0 ) { if ( getFactory().getSettings().isScrollableResultSetsEnabled() ) { // we can go straight to the first required row rs.absolute( firstRow ); } else { // we need to step through the rows one row at a time (slow) for ( int m = 0; m < firstRow; m++ ) rs.next(); } } } private static boolean hasMaxRows(RowSelection selection) { return selection != null && selection.getMaxRows() != null; } private static int getFirstRow(RowSelection selection) { if ( selection == null || selection.getFirstRow() == null ) { return 0; } else { return selection.getFirstRow().intValue(); } } /** * Should we pre-process the SQL string, adding a dialect-specific * LIMIT clause. */ private static boolean useLimit(final RowSelection selection, final Dialect dialect) { return dialect.supportsLimit() && hasMaxRows( selection ); } /** * Obtain a <tt>PreparedStatement</tt> with all parameters pre-bound. * Bind JDBC-style <tt>?</tt> parameters, named parameters, and * limit parameters. */ protected final PreparedStatement prepareQueryStatement( final QueryParameters queryParameters, final boolean scroll, final SessionImplementor session) throws SQLException, HibernateException { queryParameters.processFilters( getSQLString(), session ); String sql = queryParameters.getFilteredSQL(); final Dialect dialect = getFactory().getDialect(); final RowSelection selection = queryParameters.getRowSelection(); boolean useLimit = useLimit( selection, dialect ); boolean hasFirstRow = getFirstRow( selection ) > 0; boolean useOffset = hasFirstRow && useLimit && dialect.supportsLimitOffset(); boolean callable = queryParameters.isCallable(); boolean useScrollableResultSetToSkip = hasFirstRow && !useOffset && getFactory().getSettings().isScrollableResultSetsEnabled(); ScrollMode scrollMode = scroll ? queryParameters.getScrollMode() : ScrollMode.SCROLL_INSENSITIVE; if ( useLimit ) { sql = dialect.getLimitString( sql.trim(), //use of trim() here is ugly? useOffset ? getFirstRow(selection) : 0, getMaxOrLimit(selection, dialect) ); } sql = preprocessSQL( sql, queryParameters, dialect ); PreparedStatement st = null; if (callable) { st = session.getBatcher() .prepareCallableQueryStatement( sql, scroll || useScrollableResultSetToSkip, scrollMode ); } else { st = session.getBatcher() .prepareQueryStatement( sql, scroll || useScrollableResultSetToSkip, scrollMode ); } try { int col = 1; //TODO: can we limit stored procedures ?! if ( useLimit && dialect.bindLimitParametersFirst() ) { col += bindLimitParameters( st, col, selection ); } if (callable) { col = dialect.registerResultSetOutParameter( (CallableStatement)st, col ); } col += bindParameterValues( st, queryParameters, col, session ); if ( useLimit && !dialect.bindLimitParametersFirst() ) { col += bindLimitParameters( st, col, selection ); } if ( !useLimit ) { setMaxRows( st, selection ); } if ( selection != null ) { if ( selection.getTimeout() != null ) { st.setQueryTimeout( selection.getTimeout().intValue() ); } if ( selection.getFetchSize() != null ) { st.setFetchSize( selection.getFetchSize().intValue() ); } } } catch ( SQLException sqle ) { session.getBatcher().closeQueryStatement( st, null ); throw sqle; } catch ( HibernateException he ) { session.getBatcher().closeQueryStatement( st, null ); throw he; } return st; } /** * Some dialect-specific LIMIT clauses require the maximium last row number * (aka, first_row_number + total_row_count), while others require the maximum * returned row count (the total maximum number of rows to return). * * @param selection The selection criteria * @param dialect The dialect * @return The appropriate value to bind into the limit clause. */ private static int getMaxOrLimit(final RowSelection selection, final Dialect dialect) { final int firstRow = getFirstRow( selection ); final int lastRow = selection.getMaxRows().intValue(); if ( dialect.useMaxForLimit() ) { return lastRow + firstRow; } else { return lastRow; } } /** * Bind parameter values needed by the dialect-specific LIMIT clause. * * @param statement The statement to which to bind limit param values. * @param index The bind position from which to start binding * @param selection The selection object containing the limit information. * @return The number of parameter values bound. * @throws java.sql.SQLException Indicates problems binding parameter values. */ private int bindLimitParameters( final PreparedStatement statement, final int index, final RowSelection selection) throws SQLException { Dialect dialect = getFactory().getDialect(); if ( !dialect.supportsVariableLimit() ) { return 0; } if ( !hasMaxRows( selection ) ) { throw new AssertionFailure( "no max results set" ); } int firstRow = getFirstRow( selection ); int lastRow = getMaxOrLimit( selection, dialect ); boolean hasFirstRow = firstRow > 0 && dialect.supportsLimitOffset(); boolean reverse = dialect.bindLimitParametersInReverseOrder(); if ( hasFirstRow ) { statement.setInt( index + ( reverse ? 1 : 0 ), firstRow ); } statement.setInt( index + ( reverse || !hasFirstRow ? 0 : 1 ), lastRow ); return hasFirstRow ? 2 : 1; } /** * Use JDBC API to limit the number of rows returned by the SQL query if necessary */ private void setMaxRows( final PreparedStatement st, final RowSelection selection) throws SQLException { if ( hasMaxRows( selection ) ) { st.setMaxRows( selection.getMaxRows().intValue() + getFirstRow( selection ) ); } } /** * Bind all parameter values into the prepared statement in preparation * for execution. * * @param statement The JDBC prepared statement * @param queryParameters The encapsulation of the parameter values to be bound. * @param startIndex The position from which to start binding parameter values. * @param session The originating session. * @return The number of JDBC bind positions actually bound during this method execution. * @throws SQLException Indicates problems performing the binding. */ protected int bindParameterValues( PreparedStatement statement, QueryParameters queryParameters, int startIndex, SessionImplementor session) throws SQLException { int span = 0; span += bindPositionalParameters( statement, queryParameters, startIndex, session ); span += bindNamedParameters( statement, queryParameters.getNamedParameters(), startIndex + span, session ); return span; } /** * Bind positional parameter values to the JDBC prepared statement. * <p/> * Postional parameters are those specified by JDBC-style ? parameters * in the source query. It is (currently) expected that these come * before any named parameters in the source query. * * @param statement The JDBC prepared statement * @param queryParameters The encapsulation of the parameter values to be bound. * @param startIndex The position from which to start binding parameter values. * @param session The originating session. * @return The number of JDBC bind positions actually bound during this method execution. * @throws SQLException Indicates problems performing the binding. * @throws org.hibernate.HibernateException Indicates problems delegating binding to the types. */ protected int bindPositionalParameters( final PreparedStatement statement, final QueryParameters queryParameters, final int startIndex, final SessionImplementor session) throws SQLException, HibernateException { final Object[] values = queryParameters.getFilteredPositionalParameterValues(); final Type[] types = queryParameters.getFilteredPositionalParameterTypes(); int span = 0; for ( int i = 0; i < values.length; i++ ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -