spring AbstractIdentityColumnMaxValueIncrementer 源码

  • 2022-08-08
  • 浏览 (385)

spring AbstractIdentityColumnMaxValueIncrementer 代码

文件路径:/spring-jdbc/src/main/java/org/springframework/jdbc/support/incrementer/AbstractIdentityColumnMaxValueIncrementer.java

/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.jdbc.support.incrementer;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.support.JdbcUtils;

/**
 * Abstract base class for {@link DataFieldMaxValueIncrementer} implementations
 * which are based on identity columns in a sequence-like table.
 *
 * @author Juergen Hoeller
 * @author Thomas Risberg
 * @since 4.1.2
 */
public abstract class AbstractIdentityColumnMaxValueIncrementer extends AbstractColumnMaxValueIncrementer {

	private boolean deleteSpecificValues = false;

	/** The current cache of values. */
	private long[] valueCache;

	/** The next id to serve from the value cache. */
	private int nextValueIndex = -1;


	/**
	 * Default constructor for bean property style usage.
	 * @see #setDataSource
	 * @see #setIncrementerName
	 * @see #setColumnName
	 */
	public AbstractIdentityColumnMaxValueIncrementer() {
	}

	public AbstractIdentityColumnMaxValueIncrementer(DataSource dataSource, String incrementerName, String columnName) {
		super(dataSource, incrementerName, columnName);
	}


	/**
	 * Specify whether to delete the entire range below the current maximum key value
	 * ({@code false} - the default), or the specifically generated values ({@code true}).
	 * The former mode will use a where range clause whereas the latter will use an in
	 * clause starting with the lowest value minus 1, just preserving the maximum value.
	 */
	public void setDeleteSpecificValues(boolean deleteSpecificValues) {
		this.deleteSpecificValues = deleteSpecificValues;
	}

	/**
	 * Return whether to delete the entire range below the current maximum key value
	 * ({@code false} - the default), or the specifically generated values ({@code true}).
	 */
	public boolean isDeleteSpecificValues() {
		return this.deleteSpecificValues;
	}


	@Override
	protected synchronized long getNextKey() throws DataAccessException {
		if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) {
			/*
			* Need to use straight JDBC code because we need to make sure that the insert and select
			* are performed on the same connection (otherwise we can't be sure that @@identity
			* returns the correct value)
			*/
			Connection con = DataSourceUtils.getConnection(getDataSource());
			Statement stmt = null;
			try {
				stmt = con.createStatement();
				DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
				this.valueCache = new long[getCacheSize()];
				this.nextValueIndex = 0;
				for (int i = 0; i < getCacheSize(); i++) {
					stmt.executeUpdate(getIncrementStatement());
					ResultSet rs = stmt.executeQuery(getIdentityStatement());
					try {
						if (!rs.next()) {
							throw new DataAccessResourceFailureException("Identity statement failed after inserting");
						}
						this.valueCache[i] = rs.getLong(1);
					}
					finally {
						JdbcUtils.closeResultSet(rs);
					}
				}
				stmt.executeUpdate(getDeleteStatement(this.valueCache));
			}
			catch (SQLException ex) {
				throw new DataAccessResourceFailureException("Could not increment identity", ex);
			}
			finally {
				JdbcUtils.closeStatement(stmt);
				DataSourceUtils.releaseConnection(con, getDataSource());
			}
		}
		return this.valueCache[this.nextValueIndex++];
	}


	/**
	 * Statement to use to increment the "sequence" value.
	 * @return the SQL statement to use
	 */
	protected abstract String getIncrementStatement();

	/**
	 * Statement to use to obtain the current identity value.
	 * @return the SQL statement to use
	 */
	protected abstract String getIdentityStatement();

	/**
	 * Statement to use to clean up "sequence" values.
	 * <p>The default implementation either deletes the entire range below
	 * the current maximum value, or the specifically generated values
	 * (starting with the lowest minus 1, just preserving the maximum value)
	 * - according to the {@link #isDeleteSpecificValues()} setting.
	 * @param values the currently generated key values
	 * (the number of values corresponds to {@link #getCacheSize()})
	 * @return the SQL statement to use
	 */
	protected String getDeleteStatement(long[] values) {
		StringBuilder sb = new StringBuilder(64);
		sb.append("delete from ").append(getIncrementerName()).append(" where ").append(getColumnName());
		if (isDeleteSpecificValues()) {
			sb.append(" in (").append(values[0] - 1);
			for (int i = 0; i < values.length - 1; i++) {
				sb.append(", ").append(values[i]);
			}
			sb.append(')');
		}
		else {
			long maxValue = values[values.length - 1];
			sb.append(" < ").append(maxValue);
		}
		return sb.toString();
	}

}

相关信息

spring 源码目录

相关文章

spring AbstractColumnMaxValueIncrementer 源码

spring AbstractDataFieldMaxValueIncrementer 源码

spring AbstractSequenceMaxValueIncrementer 源码

spring DataFieldMaxValueIncrementer 源码

spring Db2LuwMaxValueIncrementer 源码

spring Db2MainframeMaxValueIncrementer 源码

spring DerbyMaxValueIncrementer 源码

spring H2SequenceMaxValueIncrementer 源码

spring HanaSequenceMaxValueIncrementer 源码

spring HsqlMaxValueIncrementer 源码

0  赞