@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2008 the original author or authors .
* Copyright 2002 - 2017 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 .
@ -33,14 +33,14 @@ import org.springframework.jdbc.support.JdbcUtils;
@@ -33,14 +33,14 @@ import org.springframework.jdbc.support.JdbcUtils;
* key column should < i > NOT < / i > be auto - increment , as the sequence table does the job .
*
* < p > The sequence is kept in a table ; there should be one sequence table per
* table that needs an auto - generated key . The table type of the sequence table
* should be MyISAM so the sequences are allocated without regard to any
* transactions that might be in progress .
* table that needs an auto - generated key . The storage engine used by the sequence table
* can be MYISAM or INNODB since the sequences are allocated using a separate connection
* without being affected by any other transactions that might be in progress .
*
* < p > Example :
*
* < pre class = "code" > create table tab ( id int unsigned not null primary key , text varchar ( 100 ) ) ;
* create table tab_sequence ( value int not null ) type = MYISAM ;
* create table tab_sequence ( value int not null ) ;
* insert into tab_sequence values ( 0 ) ; < / pre >
*
* If "cacheSize" is set , the intermediate values are served without querying the
@ -48,6 +48,10 @@ import org.springframework.jdbc.support.JdbcUtils;
@@ -48,6 +48,10 @@ import org.springframework.jdbc.support.JdbcUtils;
* is rolled back , the unused values will never be served . The maximum hole size in
* numbering is consequently the value of cacheSize .
*
* < p > It is possible to avoid acquiring a new connection for the incrementer by setting the
* "useNewConnection" property to false . In this case you < i > MUST < / i > use a non - transactional
* storage engine like MYISAM when defining the incrementer table .
*
* @author Jean - Pierre Pawlak
* @author Thomas Risberg
* @author Juergen Hoeller
@ -63,6 +67,9 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
@@ -63,6 +67,9 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
/** The max id to serve */
private long maxId = 0 ;
/** Whether or not to use a new connection for the incrementer */
private boolean useNewConnection = false ;
/ * *
* Default constructor for bean property style usage .
@ -76,7 +83,7 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
@@ -76,7 +83,7 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
/ * *
* Convenience constructor .
* @param dataSource the DataSource to use
* @param incrementerName the name of the sequence / table to use
* @param incrementerName the name of the sequence table to use
* @param columnName the name of the column in the sequence table to use
* /
public MySQLMaxValueIncrementer ( DataSource dataSource , String incrementerName , String columnName ) {
@ -84,23 +91,61 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
@@ -84,23 +91,61 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
}
/ * *
* Set whether to use a new connection for the incrementer .
* < p > { @code true } is necessary to support transactional storage engines ,
* using an isolated separate transaction for the increment operation .
* { @code false } is sufficient if the storage engine of the sequence table
* is non - transactional ( like MYISAM ) , avoiding the effort of acquiring an
* extra { @code Connection } for the increment operation .
* < p > Default is { @code false } in the Spring Framework 4 . 3 . x line .
* @since 4 . 3 . 6
* @see DataSource # getConnection ( )
* /
public void setUseNewConnection ( boolean useNewConnection ) {
this . useNewConnection = useNewConnection ;
}
@Override
protected synchronized long getNextKey ( ) throws DataAccessException {
if ( this . maxId = = this . nextId ) {
/ *
* 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 last_insert_id ( )
* returned the correct value )
* If useNewConnection is true , then we obtain a non - managed connection so our modifications
* are handled in a separate transaction . If it is false , then we use the current transaction ' s
* connection relying on the use of a non - transactional storage engine like MYISAM for the
* incrementer table . We also 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 last_insert_id ( )
* returned the correct value ) .
* /
Connection con = DataSourceUtils . getConnection ( getDataSource ( ) ) ;
Connection con = null ;
Statement stmt = null ;
boolean mustRestoreAutoCommit = false ;
try {
if ( this . useNewConnection ) {
con = getDataSource ( ) . getConnection ( ) ;
if ( con . getAutoCommit ( ) ) {
mustRestoreAutoCommit = true ;
con . setAutoCommit ( false ) ;
}
}
else {
con = DataSourceUtils . getConnection ( getDataSource ( ) ) ;
}
stmt = con . createStatement ( ) ;
DataSourceUtils . applyTransactionTimeout ( stmt , getDataSource ( ) ) ;
if ( ! this . useNewConnection ) {
DataSourceUtils . applyTransactionTimeout ( stmt , getDataSource ( ) ) ;
}
// Increment the sequence column...
String columnName = getColumnName ( ) ;
stmt . executeUpdate ( "update " + getIncrementerName ( ) + " set " + columnName +
" = last_insert_id(" + columnName + " + " + getCacheSize ( ) + ")" ) ;
try {
stmt . executeUpdate ( "update " + getIncrementerName ( ) + " set " + columnName +
" = last_insert_id(" + columnName + " + " + getCacheSize ( ) + ")" ) ;
}
catch ( SQLException ex ) {
throw new DataAccessResourceFailureException ( "Could not increment " + columnName + " for " +
getIncrementerName ( ) + " sequence table" , ex ) ;
}
// Retrieve the new max of the sequence column...
ResultSet rs = stmt . executeQuery ( VALUE_SQL ) ;
try {
@ -119,7 +164,24 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
@@ -119,7 +164,24 @@ public class MySQLMaxValueIncrementer extends AbstractColumnMaxValueIncrementer
}
finally {
JdbcUtils . closeStatement ( stmt ) ;
DataSourceUtils . releaseConnection ( con , getDataSource ( ) ) ;
if ( con ! = null ) {
if ( this . useNewConnection ) {
try {
con . commit ( ) ;
if ( mustRestoreAutoCommit ) {
con . setAutoCommit ( true ) ;
}
}
catch ( SQLException ignore ) {
throw new DataAccessResourceFailureException (
"Unable to commit new sequence value changes for " + getIncrementerName ( ) ) ;
}
JdbcUtils . closeConnection ( con ) ;
}
else {
DataSourceUtils . releaseConnection ( con , getDataSource ( ) ) ;
}
}
}
}
else {