New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix for MySql INSERTS with autoincrement #32
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,9 +15,13 @@ | |
*/ | ||
package org.polyjdbc.core.query; | ||
|
||
import org.polyjdbc.core.key.KeyGenerator; | ||
import org.polyjdbc.core.transaction.Transaction; | ||
import org.polyjdbc.core.type.ColumnTypeMapper; | ||
import org.polyjdbc.core.util.StringBuilderUtil; | ||
|
||
import java.sql.SQLException; | ||
|
||
/** | ||
* Builds insert query, use {@link QueryFactory#insert() } to create new instance. | ||
* | ||
|
@@ -30,7 +34,7 @@ | |
* | ||
* @author Adam Dubiel | ||
*/ | ||
public class InsertQuery { | ||
public abstract class InsertQuery { | ||
|
||
private static final int VALUES_LENGTH = 50; | ||
|
||
|
@@ -40,12 +44,6 @@ public class InsertQuery { | |
|
||
private final StringBuilder values = new StringBuilder(VALUES_LENGTH); | ||
|
||
private String sequenceField; | ||
|
||
private String sequenceName; | ||
|
||
private boolean sequenceValueSet; | ||
|
||
InsertQuery(ColumnTypeMapper typeMapper) { | ||
this.query = new Query(typeMapper); | ||
} | ||
|
@@ -73,23 +71,11 @@ public InsertQuery into(String tableName) { | |
* Insert next sequence value into column of given name. Only one sequenced | ||
* column per table is supported so far. | ||
*/ | ||
public InsertQuery sequence(String sequenceField, String sequenceName) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. after these changes API will look quite ugly:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, this API is not changed, the sequence() method is still in the same place :) |
||
this.sequenceField = sequenceField; | ||
this.sequenceName = sequenceName; | ||
return value(sequenceField, sequenceField); | ||
} | ||
public abstract InsertQuery sequence(String sequenceField, String sequenceName); | ||
|
||
boolean sequenceSet() { | ||
return sequenceName != null; | ||
} | ||
|
||
String getSequenceName() { | ||
return sequenceName; | ||
} | ||
abstract boolean isIdInserted(); | ||
|
||
String getSequenceField() { | ||
return sequenceField; | ||
} | ||
abstract long generateSequenceValue(KeyGenerator keyGenerator, Transaction transaction) throws SQLException; | ||
|
||
/** | ||
* Insert value into column of given name. Object is automatically translated | ||
|
@@ -100,24 +86,11 @@ String getSequenceField() { | |
public InsertQuery value(String fieldName, Object value) { | ||
valueNames.append(fieldName).append(", "); | ||
values.append(":").append(fieldName).append(", "); | ||
query.setArgument(fieldName, value); | ||
setArgument(fieldName, value); | ||
return this; | ||
} | ||
|
||
/** | ||
* Manually set sequenced field value. | ||
*/ | ||
public InsertQuery sequenceValue(long value) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you removed public method - this is a breaking change, is it neccessary? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this method is used by polyjdbc clients.
and QueryRunner increments the sequence and saves the last value. Why to bypass the flow? |
||
query.setArgument(sequenceField, value); | ||
sequenceValueSet = true; | ||
return this; | ||
} | ||
|
||
/** | ||
* Returns true if sequenced field value was set manually and there is no | ||
* need to use sequence generator. | ||
*/ | ||
public boolean isSequenceValueSet() { | ||
return sequenceValueSet; | ||
void setArgument(String fieldName, Object value) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Chyba nie rozumiem, nie dodawałem żadnych delegatorów. Co dokładnie 'breaks everything'? Jedyna zmiana w API to usunięcie możliwości ustawiania ręcznie ID, więc 2 metod: Te metody są a) niepotrzebne, b) nie mają sensu dla MySql, btw kto chciałby robić coś takiego ?
Jeśli nie chcę używać sekwencji to po prostu ich nie używam i ustawiam ID wprost:
|
||
query.setArgument(fieldName, value); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.polyjdbc.core.query; | ||
|
||
import org.polyjdbc.core.key.KeyGenerator; | ||
import org.polyjdbc.core.transaction.Transaction; | ||
import org.polyjdbc.core.type.ColumnTypeMapper; | ||
|
||
import java.sql.SQLException; | ||
|
||
public class InsertWithAutoincrement extends InsertQuery { | ||
|
||
public InsertWithAutoincrement(ColumnTypeMapper typeMapper) { | ||
super(typeMapper); | ||
} | ||
private boolean isIdInserted = false; | ||
|
||
@Override | ||
public InsertQuery sequence(String sequenceField, String sequenceName) { | ||
//pretend that DB has sequences as we don't want to complicate clients' code | ||
isIdInserted = true; | ||
return this; | ||
} | ||
|
||
@Override | ||
boolean isIdInserted() { | ||
return isIdInserted; | ||
} | ||
|
||
@Override | ||
long generateSequenceValue(KeyGenerator keyGenerator, Transaction transaction) throws SQLException { | ||
throw new RuntimeException("not implemented"); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package org.polyjdbc.core.query; | ||
|
||
import org.polyjdbc.core.key.KeyGenerator; | ||
import org.polyjdbc.core.transaction.Transaction; | ||
import org.polyjdbc.core.type.ColumnTypeMapper; | ||
|
||
import java.sql.SQLException; | ||
|
||
class InsertWithSequence extends InsertQuery { | ||
private String sequenceField; | ||
private String sequenceName; | ||
|
||
InsertWithSequence(ColumnTypeMapper typeMapper) { | ||
super(typeMapper); | ||
} | ||
|
||
@Override | ||
public InsertQuery sequence(String sequenceField, String sequenceName) { | ||
this.sequenceField = sequenceField; | ||
this.sequenceName = sequenceName; | ||
return value(sequenceField, sequenceField); | ||
} | ||
|
||
@Override | ||
boolean isIdInserted() { | ||
return sequenceName != null; | ||
} | ||
|
||
@Override | ||
long generateSequenceValue(KeyGenerator keyGenerator, Transaction transaction) throws SQLException { | ||
long key = keyGenerator.generateKey(sequenceName, transaction); | ||
setArgument(sequenceField, key); | ||
return key; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package org.polyjdbc.core.key | ||
|
||
import org.polyjdbc.core.PolyJDBC | ||
import spock.lang.Shared | ||
import spock.lang.Specification | ||
|
||
import static org.polyjdbc.core.key.PolyFactory.insertAndSelectOneRecord | ||
|
||
class MySqlAutoincrementInsertTest extends Specification { | ||
@Shared PolyJDBC polyJDBC | ||
|
||
def setupSpec() { | ||
this.polyJDBC = createPoly() | ||
|
||
if (!polyJDBC.schemaInspector().relationExists('test')) { | ||
PolyFactory.createSchema(polyJDBC) | ||
} | ||
} | ||
|
||
private PolyJDBC createPoly() { | ||
PolyFactory.newPolyForMySql() | ||
} | ||
|
||
def "should insert records with autoincremented id"(){ | ||
given: | ||
def recordsToInsert = 100 | ||
def inserted = 0 | ||
|
||
when: | ||
recordsToInsert.times { | ||
def selected = insertAndSelectOneRecord(it, this.polyJDBC) | ||
if (selected == it) inserted ++ | ||
} | ||
|
||
then: | ||
inserted == recordsToInsert | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package org.polyjdbc.core.key | ||
|
||
import org.polyjdbc.core.PolyJDBC | ||
import org.polyjdbc.core.PolyJDBCBuilder | ||
import org.polyjdbc.core.dialect.DialectRegistry | ||
import org.polyjdbc.core.infrastructure.DataSourceFactory | ||
import org.polyjdbc.core.query.mapper.ObjectMapper | ||
import org.polyjdbc.core.schema.model.Schema | ||
|
||
import java.sql.ResultSet | ||
import java.sql.SQLException | ||
|
||
class PolyFactory { | ||
|
||
static PolyJDBC newPolyForPostgres() { | ||
def dialect = DialectRegistry.POSTGRES.dialect | ||
def dataSource = DataSourceFactory.create(dialect, 'jdbc:postgresql://localhost:5432/polly', 'javers', 'javers') | ||
|
||
PolyJDBCBuilder.polyJDBC(dialect, null).connectingToDataSource(dataSource).build() | ||
} | ||
|
||
static PolyJDBC newPolyForMySql() { | ||
def dialect = DialectRegistry.MYSQL.dialect | ||
def dataSource = DataSourceFactory.create(dialect, 'jdbc:mysql://localhost/polly', 'javers', '') | ||
|
||
PolyJDBCBuilder.polyJDBC(dialect, null).connectingToDataSource(dataSource).build() | ||
} | ||
|
||
static void createSchema(PolyJDBC polyJDBC) { | ||
def schema = new Schema(polyJDBC.dialect(), null); | ||
|
||
schema.addRelation("test") | ||
.withAttribute().longAttr("id").withAdditionalModifiers("AUTO_INCREMENT").and() | ||
.withAttribute().integer("some_count").and() | ||
.constrainedBy().primaryKey("pk_test").using("id").and() | ||
.build() | ||
schema.addSequence("seq_test").build() | ||
|
||
def manager = polyJDBC.schemaManager() | ||
manager.create(schema) | ||
polyJDBC.close(manager) | ||
} | ||
|
||
static int insertAndSelectOneRecord(long value, PolyJDBC polly) { | ||
def insertQuery = polly.query().insert().into("test").sequence("id", "seq_test") | ||
.value("some_count", value) | ||
def queryRunner = polly.queryRunner() | ||
|
||
long insertedId = queryRunner.insert(insertQuery) | ||
|
||
def selectQuery = polly.query().select("some_count").from("test").where("id = $insertedId"); | ||
def selected = queryRunner.queryUnique(selectQuery, new ObjectMapper() { | ||
Object createObject(ResultSet resultSet) throws SQLException { | ||
resultSet.getLong("some_count") | ||
} | ||
}) | ||
println "inserted $value at $insertedId, selected: $selected, thread: " + Thread.currentThread().name | ||
queryRunner.commitAndClose() | ||
|
||
selected | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you expand this message a bit?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will change to
throw new RuntimeException("Not implemented. Can't generate key on AutoIncremented");