
com.zaxxer.sansorm.internal.OrmWriter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sansorm Show documentation
Show all versions of sansorm Show documentation
A "No-ORM" sane SQL <-> Java object mapping library
/*
Copyright 2012, Brett Wooldridge
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package com.zaxxer.sansorm.internal;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* OrmWriter
*/
public class OrmWriter extends OrmBase
{
private static final int CACHE_SIZE = Integer.getInteger("com.zaxxer.sansorm.statementCacheSize", 500);
private static Map createStatementCache;
private static Map updateStatementCache;
static {
createStatementCache = Collections.synchronizedMap(new LinkedHashMap(CACHE_SIZE) {
private static final long serialVersionUID = 4559270460685275064L;
@Override
protected boolean removeEldestEntry(java.util.Map.Entry eldest)
{
return this.size() > CACHE_SIZE;
}
});
updateStatementCache = Collections.synchronizedMap(new LinkedHashMap(CACHE_SIZE) {
private static final long serialVersionUID = -5324251353646078607L;
@Override
protected boolean removeEldestEntry(java.util.Map.Entry eldest)
{
return this.size() > CACHE_SIZE;
}
});
}
public static void insertListBatched(Connection connection, Iterable iterable) throws SQLException
{
Iterator iterableIterator = iterable.iterator();
if (!iterableIterator.hasNext()) {
return;
}
Class> clazz = iterableIterator.next().getClass();
Introspected introspected = Introspector.getIntrospected(clazz);
final boolean hasSelfJoinColumn = introspected.hasSelfJoinColumn();
if (hasSelfJoinColumn) {
throw new RuntimeException("insertListBatched() is not supported for objects with self-referencing columns due to Derby limitations");
}
String[] columnNames = introspected.getInsertableColumns();
PreparedStatement stmt = createStatementForInsert(connection, introspected, columnNames);
int[] parameterTypes = getParameterTypes(stmt);
for (T item : iterable) {
int parameterIndex = 1;
for (String column : columnNames) {
int parameterType = parameterTypes[parameterIndex - 1];
Object object = mapSqlType(introspected.get(item, column), parameterType);
if (object != null && !(hasSelfJoinColumn && introspected.isSelfJoinColumn(column))) {
stmt.setObject(parameterIndex, object, parameterType);
}
else {
stmt.setNull(parameterIndex, parameterType);
}
++parameterIndex;
}
stmt.addBatch();
stmt.clearParameters();
}
stmt.executeBatch();
stmt.close();
}
public static void insertListNotBatched(Connection connection, Iterable iterable) throws SQLException
{
Iterator iterableIterator = iterable.iterator();
if (!iterableIterator.hasNext()) {
return;
}
Class> clazz = iterableIterator.next().getClass();
Introspected introspected = Introspector.getIntrospected(clazz);
final boolean hasSelfJoinColumn = introspected.hasSelfJoinColumn();
String[] idColumnNames = introspected.getIdColumnNames();
String[] columnNames = introspected.getInsertableColumns();
// Insert
PreparedStatement stmt = createStatementForInsert(connection, introspected, columnNames);
int[] parameterTypes = getParameterTypes(stmt);
for (T item : iterable) {
int parameterIndex = 1;
for (String column : columnNames) {
int parameterType = parameterTypes[parameterIndex - 1];
Object object = mapSqlType(introspected.get(item, column), parameterType);
if (object != null && !(hasSelfJoinColumn && introspected.isSelfJoinColumn(column))) {
stmt.setObject(parameterIndex, object, parameterType);
}
else {
stmt.setNull(parameterIndex, parameterType);
}
++parameterIndex;
}
stmt.executeUpdate();
// Set auto-generated ID
ResultSet generatedKeys = stmt.getGeneratedKeys();
if (generatedKeys != null) {
final String idColumn = idColumnNames[0];
while (generatedKeys.next()) {
introspected.set(item, idColumn, generatedKeys.getObject(1));
}
generatedKeys.close();
}
stmt.clearParameters();
}
stmt.close();
// If there is a self-referencing column, update it with the generated IDs
if (hasSelfJoinColumn) {
final String selfJoinColumn = introspected.getSelfJoinColumn();
final String idColumn = idColumnNames[0];
StringBuffer sql = new StringBuffer("UPDATE ").append(introspected.getTableName()).append(" SET ");
sql.append(selfJoinColumn).append("=? WHERE ").append(idColumn).append("=?");
stmt = connection.prepareStatement(sql.toString());
for (T item : iterable) {
Object referencedItem = introspected.get(item, selfJoinColumn);
if (referencedItem != null) {
stmt.setObject(1, introspected.getActualIds(referencedItem)[0]);
stmt.setObject(2, introspected.getActualIds(item)[0]);
stmt.addBatch();
stmt.clearParameters();
}
}
stmt.executeBatch();
}
}
public static T insertObject(Connection connection, T target) throws SQLException
{
Class> clazz = target.getClass();
Introspected introspected = Introspector.getIntrospected(clazz);
String[] columnNames = introspected.getInsertableColumns();
PreparedStatement stmt = createStatementForInsert(connection, introspected, columnNames);
setParamsExecuteClose(target, introspected, columnNames, stmt);
return target;
}
public static T updateObject(Connection connection, T target) throws SQLException
{
Class> clazz = target.getClass();
Introspected introspected = Introspector.getIntrospected(clazz);
String[] columnNames = introspected.getUpdatableColumns();
PreparedStatement stmt = createStatementForUpdate(connection, introspected, columnNames);
setParamsExecuteClose(target, introspected, columnNames, stmt);
return target;
}
public static int deleteObject(Connection connection, T target) throws SQLException
{
Class> clazz = target.getClass();
Introspected introspected = Introspector.getIntrospected(clazz);
return deleteObjectById(connection, clazz, introspected.getActualIds(target));
}
public static int deleteObjectById(Connection connection, Class clazz, Object... args) throws SQLException
{
Introspected introspected = Introspector.getIntrospected(clazz);
StringBuilder sql = new StringBuilder();
sql.append("DELETE FROM ").append(introspected.getTableName()).append(" WHERE ");
for (String idColumn : introspected.getIdColumnNames()) {
sql.append(idColumn).append("=? AND ");
}
sql.setLength(sql.length() - 5);
return executeUpdate(connection, sql.toString(), args);
}
public static int executeUpdate(Connection connection, String sql, Object... args) throws SQLException
{
PreparedStatement stmt = null;
try {
stmt = connection.prepareStatement(sql);
populateStatementParameters(stmt, args);
int rc = stmt.executeUpdate();
return rc;
}
finally {
if (stmt != null) {
stmt.close();
}
}
}
// -----------------------------------------------------------------------
// P R I V A T E M E T H O D S
// -----------------------------------------------------------------------
private static PreparedStatement createStatementForInsert(Connection connection, Introspected introspected, String[] columns) throws SQLException
{
String sql = createStatementCache.get(introspected);
if (sql == null) {
String tableName = introspected.getTableName();
StringBuilder sqlSB = new StringBuilder("INSERT INTO ").append(tableName).append('(');
StringBuilder sqlValues = new StringBuilder(") VALUES (");
for (String column : columns) {
sqlSB.append(column).append(',');
sqlValues.append("?,");
}
sqlValues.deleteCharAt(sqlValues.length() - 1);
sqlSB.deleteCharAt(sqlSB.length() - 1).append(sqlValues).append(')');
sql = sqlSB.toString();
createStatementCache.put(introspected, sql);
}
if (introspected.hasGeneratedId()) {
return connection.prepareStatement(sql, introspected.getIdColumnNames());
}
else {
return connection.prepareStatement(sql);
}
}
private static PreparedStatement createStatementForUpdate(Connection connection, Introspected introspected, String[] columnNames) throws SQLException
{
String sql = updateStatementCache.get(introspected);
if (sql == null) {
StringBuilder sqlSB = new StringBuilder("UPDATE ").append(introspected.getTableName()).append(" SET ");
for (String column : columnNames) {
sqlSB.append(column).append("=?,");
}
sqlSB.deleteCharAt(sqlSB.length() - 1);
String[] idColumnNames = introspected.getIdColumnNames();
if (idColumnNames.length > 0) {
sqlSB.append(" WHERE ");
for (String column : idColumnNames) {
sqlSB.append(column).append("=? AND ");
}
sqlSB.setLength(sqlSB.length() - 5);
}
sql = sqlSB.toString();
updateStatementCache.put(introspected, sql);
}
return connection.prepareStatement(sql);
}
private static void setParamsExecuteClose(T target, Introspected introspected, String[] columnNames, PreparedStatement stmt) throws SQLException
{
int[] parameterTypes = getParameterTypes(stmt);
int parameterIndex = 1;
for (String column : columnNames) {
int parameterType = parameterTypes[parameterIndex - 1];
Object object = mapSqlType(introspected.get(target, column), parameterType);
if (object != null) {
stmt.setObject(parameterIndex, object, parameterType);
}
else {
stmt.setNull(parameterIndex, parameterType);
}
++parameterIndex;
}
// If there is still a parameter left to be set, it's the ID used for an update
if (parameterIndex <= parameterTypes.length) {
for (Object id : introspected.getActualIds(target)) {
stmt.setObject(parameterIndex, id, parameterTypes[parameterIndex - 1]);
++parameterIndex;
}
}
stmt.executeUpdate();
if (introspected.hasGeneratedId()) {
// Set auto-generated ID
final String idColumn = introspected.getIdColumnNames()[0];
ResultSet generatedKeys = stmt.getGeneratedKeys();
if (generatedKeys != null && generatedKeys.next()) {
introspected.set(target, idColumn, generatedKeys.getObject(1));
generatedKeys.close();
}
}
stmt.close();
}
private static int[] getParameterTypes(PreparedStatement stmt) throws SQLException
{
ParameterMetaData metaData = stmt.getParameterMetaData();
int[] parameterTypes = new int[metaData.getParameterCount()];
for (int parameterIndex = 1; parameterIndex <= metaData.getParameterCount(); parameterIndex++) {
parameterTypes[parameterIndex - 1] = metaData.getParameterType(parameterIndex);
}
return parameterTypes;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy