mirror of
https://github.com/Rogiel/l2jserver2
synced 2025-12-05 23:22:47 +00:00
Implements bulk and transactioned inserts, updates and deletes
This commit is contained in:
@@ -71,6 +71,24 @@ public abstract class AbstractDAO<T extends Model<?>, I extends ID<?>>
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean insert(T object) {
|
||||
return insertObjects(object) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean update(T object) {
|
||||
return updateObjects(object) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean delete(T object) {
|
||||
return deleteObjects(object) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new Iterator<T>() {
|
||||
|
||||
@@ -454,7 +454,6 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService
|
||||
* <ul>
|
||||
* <li>INSERT INTO</li>
|
||||
* <li>UPDATE</li>
|
||||
* <li>DELETE FROM</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
@@ -501,45 +500,64 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService
|
||||
Preconditions.checkNotNull(conn, "conn");
|
||||
|
||||
log.debug("Starting INSERT/UPDATE query execution");
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
int rows = 0;
|
||||
while (iterator.hasNext()) {
|
||||
final T object = iterator.next();
|
||||
final String queryString = query();
|
||||
|
||||
log.debug("Preparing statement for {}: {}", object, queryString);
|
||||
log.debug("Preparing statement for {}", queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(queryString,
|
||||
Statement.RETURN_GENERATED_KEYS);
|
||||
try {
|
||||
int rows = 0;
|
||||
while (iterator.hasNext()) {
|
||||
final T object = iterator.next();
|
||||
|
||||
log.debug("Parametizing statement {} with {}", st, object);
|
||||
this.parametize(st, object);
|
||||
log.debug("Parametizing statement {} with {}", st,
|
||||
object);
|
||||
this.parametize(st, object);
|
||||
|
||||
log.debug("Sending query to database for {}", object);
|
||||
rows = st.executeUpdate();
|
||||
log.debug("Query inserted or updated {} rows for {}", rows,
|
||||
object);
|
||||
log.debug("Sending query to database for {}", object);
|
||||
rows += st.executeUpdate();
|
||||
log.debug("Query inserted or updated {} rows for {}",
|
||||
rows, object);
|
||||
|
||||
// update object desire --it has been realized
|
||||
if (object instanceof Model && rows > 0) {
|
||||
log.debug("Updating Model ObjectDesire to NONE");
|
||||
((Model<?>) object).setObjectDesire(ObjectDesire.NONE);
|
||||
// update object desire --it has been realized
|
||||
if (object instanceof Model && rows > 0) {
|
||||
log.debug("Updating Model ObjectDesire to NONE");
|
||||
((Model<?>) object)
|
||||
.setObjectDesire(ObjectDesire.NONE);
|
||||
|
||||
final Mapper<? extends ID<?>> mapper = keyMapper();
|
||||
if (mapper == null)
|
||||
continue;
|
||||
final ResultSet rs = st.getGeneratedKeys();
|
||||
log.debug("Mapping generated keys with {} using {}",
|
||||
mapper, rs);
|
||||
while (rs.next()) {
|
||||
final ID<?> generatedID = mapper.map(rs);
|
||||
log.debug("Generated ID for {} is {}", object,
|
||||
generatedID);
|
||||
((Model<ID<?>>) object).setID(generatedID);
|
||||
mapper.map(rs);
|
||||
final Mapper<? extends ID<?>> mapper = keyMapper();
|
||||
if (mapper == null)
|
||||
continue;
|
||||
final ResultSet rs = st.getGeneratedKeys();
|
||||
try {
|
||||
log.debug(
|
||||
"Mapping generated keys with {} using {}",
|
||||
mapper, rs);
|
||||
while (rs.next()) {
|
||||
final ID<?> generatedID = mapper.map(rs);
|
||||
log.debug("Generated ID for {} is {}",
|
||||
object, generatedID);
|
||||
((Model<ID<?>>) object).setID(generatedID);
|
||||
mapper.map(rs);
|
||||
}
|
||||
} finally {
|
||||
rs.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
} finally {
|
||||
st.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
conn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
conn.setAutoCommit(true);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -573,6 +591,143 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This query is used for the following statements:
|
||||
* <ul>
|
||||
* <li>DELETE FROM</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
* @param <T>
|
||||
* the query return type
|
||||
*/
|
||||
public static abstract class DeleteQuery<T> implements Query<Integer> {
|
||||
/**
|
||||
* The logger
|
||||
*/
|
||||
private final Logger log = LoggerFactory.getLogger(DeleteQuery.class);
|
||||
|
||||
/**
|
||||
* The {@link DatabaseService}
|
||||
*/
|
||||
private final AbstractJDBCDatabaseService database;
|
||||
/**
|
||||
* The iterator
|
||||
*/
|
||||
private final Iterator<T> iterator;
|
||||
|
||||
/**
|
||||
* Creates a new query for <tt>objects</tt>
|
||||
*
|
||||
* @param database
|
||||
* the {@link DatabaseService}
|
||||
* @param objects
|
||||
* the object list
|
||||
*/
|
||||
@SafeVarargs
|
||||
public DeleteQuery(AbstractJDBCDatabaseService database, T... objects) {
|
||||
this(database, new ArrayIterator<T>(objects));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new query for objects in <tt>iterator</tt>
|
||||
*
|
||||
* @param database
|
||||
* the {@link DatabaseService}
|
||||
* @param iterator
|
||||
* the object iterator
|
||||
*/
|
||||
public DeleteQuery(AbstractJDBCDatabaseService database,
|
||||
Iterator<T> iterator) {
|
||||
this.iterator = iterator;
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer query(Connection conn) throws SQLException {
|
||||
Preconditions.checkNotNull(conn, "conn");
|
||||
|
||||
log.debug("Starting DELETE query execution");
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
|
||||
final String queryString = query();
|
||||
|
||||
log.debug("Preparing statement for {}", queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(queryString);
|
||||
|
||||
try {
|
||||
int rows = 0;
|
||||
while (iterator.hasNext()) {
|
||||
final T object = iterator.next();
|
||||
|
||||
log.debug("Parametizing statement {} with {}", st,
|
||||
object);
|
||||
this.parametize(st, object);
|
||||
|
||||
log.debug("Sending query to database for {}", object);
|
||||
rows = st.executeUpdate();
|
||||
log.debug("Query deleted {} rows for {}", rows, object);
|
||||
|
||||
dispose(object);
|
||||
if (object instanceof Model) {
|
||||
database.removeCache(((Model<?>) object)
|
||||
.getObjectDesire());
|
||||
}
|
||||
}
|
||||
conn.commit();
|
||||
return rows;
|
||||
} finally {
|
||||
st.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
conn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
conn.setAutoCommit(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the <b>prepared</b> query for execution
|
||||
*
|
||||
* @return the <b>prepared</b> query
|
||||
*/
|
||||
protected abstract String query();
|
||||
|
||||
/**
|
||||
* Set the parameters for in <tt>statement</tt> for <tt>object</tt>
|
||||
*
|
||||
* @param st
|
||||
* the prepared statement
|
||||
* @param object
|
||||
* the object
|
||||
* @throws SQLException
|
||||
* if any SQL error occur
|
||||
*/
|
||||
protected abstract void parametize(PreparedStatement st, T object)
|
||||
throws SQLException;
|
||||
|
||||
/**
|
||||
* Disposes all object related resources, such as IDs.
|
||||
*
|
||||
* @param object
|
||||
* the object that was been deleted
|
||||
*/
|
||||
protected abstract void dispose(T object);
|
||||
|
||||
/**
|
||||
* Return the key mapper. Can be null if no generated keys are used or
|
||||
* are not important.
|
||||
*
|
||||
* @return the key mapper
|
||||
*/
|
||||
protected Mapper<? extends ID<?>> keyMapper() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An select query that returns a list of objects of type <tt>T</tt>
|
||||
*
|
||||
@@ -597,31 +752,38 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService
|
||||
final String queryString = query();
|
||||
log.debug("Preparing statement with {}", queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(query());
|
||||
try {
|
||||
log.debug("Parametizing statement {}", st);
|
||||
parametize(st);
|
||||
|
||||
log.debug("Parametizing statement {}", st);
|
||||
parametize(st);
|
||||
log.debug("Sending query to database for {}", st);
|
||||
st.execute();
|
||||
|
||||
log.debug("Sending query to database for {}", st);
|
||||
st.execute();
|
||||
|
||||
final List<T> list = CollectionFactory.newList();
|
||||
final ResultSet rs = st.getResultSet();
|
||||
final Mapper<T> mapper = mapper();
|
||||
log.debug("Database returned {}", rs);
|
||||
while (rs.next()) {
|
||||
log.debug("Mapping row with {}", mapper);
|
||||
final T obj = mapper.map(rs);
|
||||
if (obj == null) {
|
||||
log.debug("Mapper {} returned a null row", mapper);
|
||||
continue;
|
||||
final List<T> list = CollectionFactory.newList();
|
||||
final ResultSet rs = st.getResultSet();
|
||||
try {
|
||||
final Mapper<T> mapper = mapper();
|
||||
log.debug("Database returned {}", rs);
|
||||
while (rs.next()) {
|
||||
log.debug("Mapping row with {}", mapper);
|
||||
final T obj = mapper.map(rs);
|
||||
if (obj == null) {
|
||||
log.debug("Mapper {} returned a null row", mapper);
|
||||
continue;
|
||||
}
|
||||
if (obj instanceof Model) {
|
||||
((Model<?>) obj).setObjectDesire(ObjectDesire.NONE);
|
||||
}
|
||||
log.debug("Mapper {} returned {}", mapper, obj);
|
||||
list.add(obj);
|
||||
}
|
||||
return list;
|
||||
} finally {
|
||||
rs.close();
|
||||
}
|
||||
if (obj instanceof Model) {
|
||||
((Model<?>) obj).setObjectDesire(ObjectDesire.NONE);
|
||||
}
|
||||
log.debug("Mapper {} returned {}", mapper, obj);
|
||||
list.add(obj);
|
||||
} finally {
|
||||
st.close();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -679,26 +841,34 @@ public abstract class AbstractJDBCDatabaseService extends AbstractService
|
||||
final String queryString = query();
|
||||
log.debug("Preparing statement with {}", queryString);
|
||||
final PreparedStatement st = conn.prepareStatement(query());
|
||||
try {
|
||||
log.debug("Parametizing statement {}", st);
|
||||
parametize(st);
|
||||
|
||||
log.debug("Parametizing statement {}", st);
|
||||
parametize(st);
|
||||
log.debug("Sending query to database for {}", st);
|
||||
st.execute();
|
||||
|
||||
log.debug("Sending query to database for {}", st);
|
||||
st.execute();
|
||||
|
||||
final ResultSet rs = st.getResultSet();
|
||||
final Mapper<T> mapper = mapper();
|
||||
log.debug("Database returned {}", rs);
|
||||
while (rs.next()) {
|
||||
log.debug("Mapping row {} with {}", rs, mapper);
|
||||
final T object = mapper.map(rs);
|
||||
if (object instanceof Model) {
|
||||
((Model<?>) object).setObjectDesire(ObjectDesire.NONE);
|
||||
final ResultSet rs = st.getResultSet();
|
||||
try {
|
||||
final Mapper<T> mapper = mapper();
|
||||
log.debug("Database returned {}", rs);
|
||||
while (rs.next()) {
|
||||
log.debug("Mapping row {} with {}", rs, mapper);
|
||||
final T object = mapper.map(rs);
|
||||
if (object instanceof Model) {
|
||||
((Model<?>) object)
|
||||
.setObjectDesire(ObjectDesire.NONE);
|
||||
}
|
||||
log.debug("Mapper {} returned {}", mapper, object);
|
||||
return object;
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
rs.close();
|
||||
}
|
||||
log.debug("Mapper {} returned {}", mapper, object);
|
||||
return object;
|
||||
} finally {
|
||||
st.close();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.util.Iterator;
|
||||
|
||||
import com.l2jserver.model.Model;
|
||||
import com.l2jserver.model.id.ID;
|
||||
import com.l2jserver.service.cache.IgnoreCaching;
|
||||
|
||||
/**
|
||||
* The Data Access Object interface used used to retrieve, save and remove
|
||||
@@ -63,7 +62,6 @@ public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
*
|
||||
* @return the list containing all {@link ID} objects
|
||||
*/
|
||||
@IgnoreCaching
|
||||
Collection<I> selectIDs();
|
||||
|
||||
/**
|
||||
@@ -75,7 +73,6 @@ public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
* @return true if the row was inserted or updated
|
||||
* @see DataAccessObject#save(Model, boolean)
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean save(O object);
|
||||
|
||||
/**
|
||||
@@ -88,7 +85,6 @@ public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
* will force an save, even if the object has not changed
|
||||
* @return true if the row was inserted or updated
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean save(O object, boolean force);
|
||||
|
||||
/**
|
||||
@@ -98,9 +94,17 @@ public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
* the object
|
||||
* @return true if the row was inserted
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean insert(O object);
|
||||
|
||||
/**
|
||||
* Inserts several instances in the database using a transaction (if possible).
|
||||
*
|
||||
* @param objects
|
||||
* the objects
|
||||
* @return the number of inserted rows
|
||||
*/
|
||||
int insertObjects(@SuppressWarnings("unchecked") O... objects);
|
||||
|
||||
/**
|
||||
* Updates the instance in the database.
|
||||
*
|
||||
@@ -108,9 +112,17 @@ public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
* the object
|
||||
* @return true if the row was updated
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean update(O object);
|
||||
|
||||
/**
|
||||
* Updates several instances in the database using a transaction (if possible).
|
||||
*
|
||||
* @param objects
|
||||
* the objects
|
||||
* @return the number of updated rows
|
||||
*/
|
||||
int updateObjects(@SuppressWarnings("unchecked") O... objects);
|
||||
|
||||
/**
|
||||
* Deletes the instance in the database.
|
||||
*
|
||||
@@ -118,6 +130,14 @@ public interface DataAccessObject<O extends Model<?>, I extends ID<?>> extends
|
||||
* the object
|
||||
* @return true if the row was deleted
|
||||
*/
|
||||
@IgnoreCaching
|
||||
boolean delete(O object);
|
||||
|
||||
/**
|
||||
* Deletes several instances in the database using an transaction (if possible).
|
||||
*
|
||||
* @param objects
|
||||
* the objects
|
||||
* @return the numver of deleted rows
|
||||
*/
|
||||
int deleteObjects(@SuppressWarnings("unchecked") O... objects);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of l2jserver2 <l2jserver2.com>.
|
||||
*
|
||||
* l2jserver2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* l2jserver2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with l2jserver2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.l2jserver.util.factory.CollectionFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class ArrayUtils {
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("unchecked")
|
||||
public final static <T> T[] copyArrayExcept(T[] array, T... except) {
|
||||
final List<T> values = CollectionFactory.newList();
|
||||
for (final T item : array) {
|
||||
if (Arrays.binarySearch(except, item) < 0) {
|
||||
values.add(item);
|
||||
}
|
||||
}
|
||||
return (T[]) values.toArray();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of l2jserver2 <l2jserver2.com>.
|
||||
*
|
||||
* l2jserver2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* l2jserver2 is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with l2jserver2. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.l2jserver.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author <a href="http://www.rogiel.com">Rogiel</a>
|
||||
*
|
||||
*/
|
||||
public class ArrayUtilsTest extends ArrayUtils {
|
||||
@Test
|
||||
public void testCopyArrayExcept() {
|
||||
final String str1 = "one";
|
||||
final String str2 = "two";
|
||||
final String str3 = "three";
|
||||
|
||||
String[] arr = new String[] { str1, str2, str3 };
|
||||
|
||||
Assert.assertTrue(Arrays.equals(new String[] { str1, str3 },
|
||||
ArrayUtils.copyArrayExcept(arr, str2)));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user