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;
023
024import javax.sql.DataSource;
025
026import org.springframework.dao.DataAccessException;
027import org.springframework.dao.DataAccessResourceFailureException;
028import org.springframework.jdbc.datasource.DataSourceUtils;
029import org.springframework.jdbc.support.JdbcUtils;
030
031/**
032 * Abstract base class for {@link DataFieldMaxValueIncrementer} implementations that use
033 * a database sequence. Subclasses need to provide the database-specific SQL to use.
034 *
035 * @author Juergen Hoeller
036 * @since 26.02.2004
037 * @see #getSequenceQuery
038 */
039public abstract class AbstractSequenceMaxValueIncrementer extends AbstractDataFieldMaxValueIncrementer {
040
041        /**
042         * Default constructor for bean property style usage.
043         * @see #setDataSource
044         * @see #setIncrementerName
045         */
046        public AbstractSequenceMaxValueIncrementer() {
047        }
048
049        /**
050         * Convenience constructor.
051         * @param dataSource the DataSource to use
052         * @param incrementerName the name of the sequence/table to use
053         */
054        public AbstractSequenceMaxValueIncrementer(DataSource dataSource, String incrementerName) {
055                super(dataSource, incrementerName);
056        }
057
058
059        /**
060         * Executes the SQL as specified by {@link #getSequenceQuery()}.
061         */
062        @Override
063        protected long getNextKey() throws DataAccessException {
064                Connection con = DataSourceUtils.getConnection(getDataSource());
065                Statement stmt = null;
066                ResultSet rs = null;
067                try {
068                        stmt = con.createStatement();
069                        DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
070                        rs = stmt.executeQuery(getSequenceQuery());
071                        if (rs.next()) {
072                                return rs.getLong(1);
073                        }
074                        else {
075                                throw new DataAccessResourceFailureException("Sequence query did not return a result");
076                        }
077                }
078                catch (SQLException ex) {
079                        throw new DataAccessResourceFailureException("Could not obtain sequence value", ex);
080                }
081                finally {
082                        JdbcUtils.closeResultSet(rs);
083                        JdbcUtils.closeStatement(stmt);
084                        DataSourceUtils.releaseConnection(con, getDataSource());
085                }
086        }
087
088        /**
089         * Return the database-specific query to use for retrieving a sequence value.
090         * <p>The provided SQL is supposed to result in a single row with a single
091         * column that allows for extracting a {@code long} value.
092         */
093        protected abstract String getSequenceQuery();
094
095}