import java.sql.PreparedStatement;\r
import java.sql.ResultSet;\r
import java.sql.SQLException;\r
+import java.sql.SQLFeatureNotSupportedException;\r
+import java.sql.Savepoint;\r
import java.sql.Statement;\r
import java.util.ArrayList;\r
import java.util.Collections;\r
private static final Map<Object, Token> TOKENS;\r
\r
private static final Map<String, Class<? extends SQLDialect>> DIALECTS;\r
-\r
+ \r
private final Connection conn;\r
private final Map<Class<?>, TableDefinition<?>> classMap = Collections\r
.synchronizedMap(new HashMap<Class<?>, TableDefinition<?>>());\r
}\r
\r
public <T> void insertAll(List<T> list) {\r
- for (T t : list) {\r
- insert(t);\r
+ if (list.size() == 0) {\r
+ return;\r
+ }\r
+ Savepoint savepoint = null;\r
+ try {\r
+ Class<?> clazz = list.get(0).getClass();\r
+ TableDefinition<?> def = define(clazz).createIfRequired(this);\r
+ savepoint = prepareSavepoint();\r
+ for (T t : list) {\r
+ PreparedStatement ps = def.createInsertStatement(this, t, false);\r
+ int rc = ps.executeUpdate();\r
+ if (rc == 0) {\r
+ throw new IciqlException("Failed to insert {0}. Affected rowcount == 0.", t);\r
+ }\r
+ }\r
+ commit(savepoint);\r
+ } catch (SQLException e) {\r
+ rollback(savepoint);\r
+ throw new IciqlException(e);\r
+ } catch (IciqlException e) {\r
+ rollback(savepoint);\r
+ throw e;\r
}\r
}\r
\r
public <T> List<Long> insertAllAndGetKeys(List<T> list) {\r
List<Long> identities = new ArrayList<Long>();\r
- for (T t : list) {\r
- identities.add(insertAndGetKey(t));\r
+ if (list.size() == 0) {\r
+ return identities;\r
+ }\r
+ Savepoint savepoint = null;\r
+ try {\r
+ Class<?> clazz = list.get(0).getClass();\r
+ TableDefinition<?> def = define(clazz).createIfRequired(this);\r
+ savepoint = prepareSavepoint();\r
+ for (T t : list) {\r
+ long key = def.insert(this, t, true);\r
+ identities.add(key);\r
+ }\r
+ commit(savepoint);\r
+ } catch (IciqlException e) {\r
+ rollback(savepoint);\r
+ throw e;\r
}\r
return identities;\r
}\r
\r
public <T> void updateAll(List<T> list) {\r
- for (T t : list) {\r
- update(t);\r
+ if (list.size() == 0) {\r
+ return;\r
+ }\r
+ Savepoint savepoint = null;\r
+ try {\r
+ Class<?> clazz = list.get(0).getClass();\r
+ TableDefinition<?> def = define(clazz).createIfRequired(this);\r
+ savepoint = prepareSavepoint();\r
+ for (T t : list) {\r
+ def.update(this, t);\r
+ }\r
+ commit(savepoint);\r
+ } catch (IciqlException e) {\r
+ rollback(savepoint);\r
+ throw e;\r
}\r
}\r
\r
public <T> void deleteAll(List<T> list) {\r
- for (T t : list) {\r
- delete(t);\r
+ if (list.size() == 0) {\r
+ return;\r
+ }\r
+ Savepoint savepoint = null;\r
+ try {\r
+ Class<?> clazz = list.get(0).getClass();\r
+ TableDefinition<?> def = define(clazz).createIfRequired(this);\r
+ savepoint = prepareSavepoint();\r
+ for (T t : list) {\r
+ def.delete(this, t);\r
+ }\r
+ commit(savepoint);\r
+ } catch (IciqlException e) {\r
+ rollback(savepoint);\r
+ throw e;\r
}\r
}\r
\r
throw IciqlException.fromSQL(sql, e);\r
}\r
}\r
+ \r
+ Savepoint prepareSavepoint() {\r
+ // create a savepoint\r
+ Savepoint savepoint = null;\r
+ try {\r
+ conn.setAutoCommit(false);\r
+ savepoint = conn.setSavepoint();\r
+ } catch (SQLFeatureNotSupportedException e) {\r
+ // jdbc driver does not support save points \r
+ } catch (SQLException e) {\r
+ throw new IciqlException(e, "Could not create save point");\r
+ }\r
+ return savepoint;\r
+ }\r
+ \r
+ void commit(Savepoint savepoint) {\r
+ if (savepoint != null) {\r
+ try {\r
+ conn.commit();\r
+ conn.setAutoCommit(true);\r
+ } catch (SQLException e) {\r
+ throw new IciqlException(e, "Failed to commit pending transactions");\r
+ }\r
+ }\r
+ }\r
+ \r
+ void rollback(Savepoint savepoint) {\r
+ if (savepoint != null) {\r
+ try {\r
+ conn.rollback(savepoint);\r
+ conn.setAutoCommit(true);\r
+ } catch (SQLException s) {\r
+ throw new IciqlException(s, "Failed to rollback transactions");\r
+ }\r
+ }\r
+ }\r
\r
@SuppressWarnings("unchecked")\r
<T> TableDefinition<T> getTableDefinition(Class<T> clazz) {\r
package com.iciql;\r
\r
import java.lang.reflect.Field;\r
+import java.sql.PreparedStatement;\r
import java.sql.ResultSet;\r
import java.sql.SQLException;\r
import java.util.ArrayList;\r
// return the value unchanged\r
return value;\r
}\r
+ \r
+ PreparedStatement createInsertStatement(Db db, Object obj, boolean returnKey) {\r
+ SQLStatement stat = new SQLStatement(db);\r
+ StatementBuilder buff = new StatementBuilder("INSERT INTO ");\r
+ buff.append(db.getDialect().prepareTableName(schemaName, tableName)).append('(');\r
+ for (FieldDefinition field : fields) {\r
+ if (skipInsertField(field, obj)) {\r
+ continue;\r
+ }\r
+ buff.appendExceptFirst(", ");\r
+ buff.append(db.getDialect().prepareColumnName(field.columnName));\r
+ }\r
+ buff.append(") VALUES(");\r
+ buff.resetCount();\r
+ for (FieldDefinition field : fields) {\r
+ if (skipInsertField(field, obj)) {\r
+ continue;\r
+ }\r
+ buff.appendExceptFirst(", ");\r
+ buff.append('?');\r
+ Object value = getValue(obj, field);\r
+ if (value == null && !field.nullable) {\r
+ // try to interpret and instantiate a default value\r
+ value = ModelUtils.getDefaultValue(field, db.getDialect().getDateTimeClass());\r
+ }\r
+ stat.addParameter(value);\r
+ }\r
+ buff.append(')');\r
+ stat.setSQL(buff.toString());\r
+ IciqlLogger.insert(stat.getSQL());\r
+ return stat.prepare(returnKey);\r
+ }\r
\r
long insert(Db db, Object obj, boolean returnKey) {\r
SQLStatement stat = new SQLStatement(db);\r