001package com.avaje.ebean.config.dbplatform; 002 003import java.sql.Connection; 004import java.sql.PreparedStatement; 005import java.sql.ResultSet; 006import java.sql.SQLException; 007 008import javax.persistence.PersistenceException; 009import javax.sql.DataSource; 010 011import com.avaje.ebean.Transaction; 012import org.slf4j.Logger; 013import org.slf4j.LoggerFactory; 014 015/** 016 * A very simple Database sequence based IdGenerator. 017 * <p> 018 * One which batch requests sequence Id's would be better for performance. 019 * </p> 020 */ 021public class SimpleSequenceIdGenerator implements PlatformIdGenerator { 022 023 private static final Logger logger = LoggerFactory.getLogger(SimpleSequenceIdGenerator.class); 024 025 private final String sql; 026 027 private final DataSource dataSource; 028 029 private final String seqName; 030 031 /** 032 * Construct given a dataSource and sql to return the next sequence value. 033 */ 034 public SimpleSequenceIdGenerator(DataSource dataSource, String sql, String seqName) { 035 this.dataSource = dataSource; 036 this.sql = sql; 037 this.seqName = seqName; 038 } 039 040 public String getName() { 041 return seqName; 042 } 043 044 public boolean isDbSequence() { 045 return true; 046 } 047 048 public void preAllocateIds(int batchSize) { 049 // just ignore this 050 } 051 052 public Object nextId(Transaction t) { 053 054 boolean useTxnConnection = t != null; 055 056 Connection c = null; 057 PreparedStatement pstmt = null; 058 ResultSet rset = null; 059 try { 060 c = useTxnConnection ? t.getConnection() : dataSource.getConnection(); 061 pstmt = c.prepareStatement(sql); 062 rset = pstmt.executeQuery(); 063 if (rset.next()) { 064 return rset.getInt(1); 065 } else { 066 String m = "Always expecting 1 row from " + sql; 067 throw new PersistenceException(m); 068 } 069 } catch (SQLException e) { 070 throw new PersistenceException("Error getting sequence nextval", e); 071 072 } finally { 073 if (useTxnConnection) { 074 closeResources(rset, pstmt, null); 075 } else { 076 closeResources(rset, pstmt, c); 077 } 078 } 079 } 080 081 private void closeResources(ResultSet rset, PreparedStatement pstmt, Connection c) { 082 try { 083 if (rset != null) { 084 rset.close(); 085 } 086 } catch (SQLException e) { 087 logger.error("Error closing ResultSet", e); 088 } 089 try { 090 if (pstmt != null) { 091 pstmt.close(); 092 } 093 } catch (SQLException e) { 094 logger.error("Error closing PreparedStatement", e); 095 } 096 try { 097 if (c != null) { 098 c.close(); 099 } 100 } catch (SQLException e) { 101 logger.error("Error closing Connection", e); 102 } 103 } 104 105}