001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jdbc.support.incrementer;
018
019import java.sql.Connection;
020import java.sql.ResultSet;
021import java.sql.SQLException;
022import java.sql.Statement;
023import javax.sql.DataSource;
024
025import org.springframework.dao.DataAccessException;
026import org.springframework.dao.DataAccessResourceFailureException;
027import org.springframework.jdbc.datasource.DataSourceUtils;
028import org.springframework.jdbc.support.JdbcUtils;
029
030/**
031 * Abstract base class for {@link DataFieldMaxValueIncrementer} implementations that use
032 * a database sequence. Subclasses need to provide the database-specific SQL to use.
033 *
034 * @author Juergen Hoeller
035 * @since 26.02.2004
036 * @see #getSequenceQuery
037 */
038public abstract class AbstractSequenceMaxValueIncrementer extends AbstractDataFieldMaxValueIncrementer {
039
040        /**
041         * Default constructor for bean property style usage.
042         * @see #setDataSource
043         * @see #setIncrementerName
044         */
045        public AbstractSequenceMaxValueIncrementer() {
046        }
047
048        /**
049         * Convenience constructor.
050         * @param dataSource the DataSource to use
051         * @param incrementerName the name of the sequence/table to use
052         */
053        public AbstractSequenceMaxValueIncrementer(DataSource dataSource, String incrementerName) {
054                super(dataSource, incrementerName);
055        }
056
057
058        /**
059         * Executes the SQL as specified by {@link #getSequenceQuery()}.
060         */
061        @Override
062        protected long getNextKey() throws DataAccessException {
063                Connection con = DataSourceUtils.getConnection(getDataSource());
064                Statement stmt = null;
065                ResultSet rs = null;
066                try {
067                        stmt = con.createStatement();
068                        DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
069                        rs = stmt.executeQuery(getSequenceQuery());
070                        if (rs.next()) {
071                                return rs.getLong(1);
072                        }
073                        else {
074                                throw new DataAccessResourceFailureException("Sequence query did not return a result");
075                        }
076                }
077                catch (SQLException ex) {
078                        throw new DataAccessResourceFailureException("Could not obtain sequence value", ex);
079                }
080                finally {
081                        JdbcUtils.closeResultSet(rs);
082                        JdbcUtils.closeStatement(stmt);
083                        DataSourceUtils.releaseConnection(con, getDataSource());
084                }
085        }
086
087        /**
088         * Return the database-specific query to use for retrieving a sequence value.
089         * <p>The provided SQL is supposed to result in a single row with a single
090         * column that allows for extracting a {@code long} value.
091         */
092        protected abstract String getSequenceQuery();
093
094}