KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jdbc > support > incrementer > HsqlMaxValueIncrementer


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

16
17 package org.springframework.jdbc.support.incrementer;
18
19 import java.sql.Connection JavaDoc;
20 import java.sql.ResultSet JavaDoc;
21 import java.sql.SQLException JavaDoc;
22 import java.sql.Statement JavaDoc;
23
24 import javax.sql.DataSource JavaDoc;
25
26 import org.springframework.dao.DataAccessException;
27 import org.springframework.dao.DataAccessResourceFailureException;
28 import org.springframework.jdbc.datasource.DataSourceUtils;
29 import org.springframework.jdbc.support.JdbcUtils;
30
31 /**
32  * Class to increment maximum value of a given HSQL table with the equivalent
33  * of an auto-increment column. Note: If you use this class, your HSQL key
34  * column should <i>NOT</i> be auto-increment, as the sequence table does the job.
35  *
36  * <p>The sequence is kept in a table. There should be one sequence table per
37  * table that needs an auto-generated key.
38  *
39  * <p>Example:
40  *
41  * <pre class="code">create table tab (id int not null primary key, text varchar(100));
42  * create table tab_sequence (value identity);
43  * insert into tab_sequence values(0);</pre>
44  *
45  * If cacheSize is set, the intermediate values are served without querying the
46  * database. If the server or your application is stopped or crashes or a transaction
47  * is rolled back, the unused values will never be served. The maximum hole size in
48  * numbering is consequently the value of cacheSize.
49  *
50  * @author Isabelle Muszynski
51  * @author Jean-Pierre Pawlak
52  * @author Thomas Risberg
53  */

54 public class HsqlMaxValueIncrementer extends AbstractDataFieldMaxValueIncrementer {
55
56     /** The name of the column for this sequence */
57     private String JavaDoc columnName;
58
59     /** The number of keys buffered in a cache */
60     private int cacheSize = 1;
61
62     private long[] valueCache = null;
63
64     /** The next id to serve from the value cache */
65     private int nextValueIndex = -1;
66
67
68     /**
69      * Default constructor.
70      **/

71     public HsqlMaxValueIncrementer() {
72     }
73
74     /**
75      * Convenience constructor.
76      * @param ds the DataSource to use
77      * @param incrementerName the name of the sequence/table to use
78      * @param columnName the name of the column in the sequence table to use
79      **/

80     public HsqlMaxValueIncrementer(DataSource JavaDoc ds, String JavaDoc incrementerName, String JavaDoc columnName) {
81         setDataSource(ds);
82         setIncrementerName(incrementerName);
83         this.columnName = columnName;
84         afterPropertiesSet();
85     }
86
87     /**
88      * Set the name of the column in the sequence table.
89      */

90     public void setColumnName(String JavaDoc columnName) {
91         this.columnName = columnName;
92     }
93
94     /**
95      * Return the name of the column in the sequence table.
96      */

97     public String JavaDoc getColumnName() {
98         return this.columnName;
99     }
100
101     /**
102      * Set the number of buffered keys.
103      */

104     public void setCacheSize(int cacheSize) {
105         this.cacheSize = cacheSize;
106     }
107
108     /**
109      * Return the number of buffered keys.
110      */

111     public int getCacheSize() {
112         return this.cacheSize;
113     }
114
115     public void afterPropertiesSet() {
116         super.afterPropertiesSet();
117         if (this.columnName == null) {
118             throw new IllegalArgumentException JavaDoc("columnName is required");
119         }
120     }
121
122
123     protected synchronized long getNextKey() throws DataAccessException {
124         if (this.nextValueIndex < 0 || this.nextValueIndex >= getCacheSize()) {
125             /*
126             * Need to use straight JDBC code because we need to make sure that the insert and select
127             * are performed on the same connection (otherwise we can't be sure that last_insert_id()
128             * returned the correct value)
129             */

130             Connection JavaDoc con = DataSourceUtils.getConnection(getDataSource());
131             Statement JavaDoc stmt = null;
132             try {
133                 stmt = con.createStatement();
134                 DataSourceUtils.applyTransactionTimeout(stmt, getDataSource());
135                 this.valueCache = new long[getCacheSize()];
136                 this.nextValueIndex = 0;
137                 for (int i = 0; i < getCacheSize(); i++) {
138                     stmt.executeUpdate("insert into " + getIncrementerName() + " values(null)");
139                     ResultSet JavaDoc rs = stmt.executeQuery("select max(identity()) from " + getIncrementerName());
140                     try {
141                         if (!rs.next()) {
142                             throw new DataAccessResourceFailureException("identity() failed after executing an update");
143                         }
144                         this.valueCache[i] = rs.getLong(1);
145                     }
146                     finally {
147                         JdbcUtils.closeResultSet(rs);
148                     }
149                 }
150                 long maxValue = this.valueCache[(this.valueCache.length - 1)];
151                 stmt.executeUpdate("delete from " + getIncrementerName() + " where " + this.columnName + " < " + maxValue);
152             }
153             catch (SQLException JavaDoc ex) {
154                 throw new DataAccessResourceFailureException("Could not obtain identity()", ex);
155             }
156             finally {
157                 JdbcUtils.closeStatement(stmt);
158                 DataSourceUtils.releaseConnection(con, getDataSource());
159             }
160         }
161         return this.valueCache[this.nextValueIndex++];
162     }
163
164 }
165
Popular Tags