Ibatis startBatch() работает только с собственными транзакциями запуска и принятия SqlMapClient, а не с управляемыми Spring
Я обнаружил, что, хотя у меня есть код, обернутый транзакциями Spring, и он фиксирует / откатывает, когда я ожидал, чтобы использовать пакетную обработку JDBC при использовании Ibatis и Spring, мне нужно использовать явные методы транзакции SqlMapClient.
Т.е. это делает группировку, как я ожидал:
dao.getSqlMapClient().startTransaction();
dao.getSqlMapClient().startBatch();
int i = 0;
for (MyObject obj : allObjects)
{
dao.storeChange(obj);
i++;
if (i % DB_BATCH_SIZE == 0)
{
dao.getSqlMapClient().executeBatch();
dao.getSqlMapClient().startBatch();
}
}
dao.getSqlMapClient().executeBatch();
dao.getSqlMapClient().commitTransaction();
но если у меня нет операторов открытия и закрытия транзакций, и я полагаюсь на Spring для управления вещами (что я и хочу делать!), пакетирование просто не произойдет.
Учитывая, что Spring, по-видимому, в противном случае справляется со своей стороной сделки по управлению транзакциями, кто-нибудь может посоветовать какие-либо известные здесь проблемы?
(База данных - это MySQL; я знаю о проблемах, связанных с ее псевдопакетным подходом JDBC с переписыванием операторов INSERT, здесь это определенно не проблема)
2 ответа
Выяснив причину этого, прочитав различные ресурсы, методом проб и ошибок, я записал наши результаты здесь, так как это может помочь кому-то еще.
Оказывается, что различные поведения были вызваны нашими классами DAO, расширяющими Spring SqlMapClientTemplate. В этом классе у вас есть два "выбора" (я говорю "выбор; один правильный, другой действительно нет"):
прямое использование insert (), update () и т.д.; используя полные объекты Spring полностью
getSqlMapClient().insert(), update() и т.д.; на самом деле этот работает с использованием объекта com.ibatis..., возвращаемого getSqlMapClient(), а не Spring
Оба обычно работают, но из моего прочтения первый вариант лучше, например, если вы используете Spring, вы хотите быть полностью основанным на Spring, а не "выпрыгивать" на объекты Ibatis.
Теперь SqlMapClientTemplate не предоставляет доступ к startBatch() / executeBatch() напрямую, только удобный метод вставки (), update (), поэтому такой код необходим для подобных вещей. Приведенный ниже код полностью работает с нашими транзакциями, управляемыми Spring, а не с явным кодом startTransaction().
(отказ от ответственности, это может содержать ошибки из-за моего "анонимного" рабочего кода для ясности)
public class MyFunkyDao extends SqlMapClientDaoSupport
{
private static final int DB_BATCH_SIZE = 1000;
public void storeMyData(final List<MyData> listData)
{
getSqlMapClientTemplate().execute( new SqlMapClientCallback()
{
@Override
public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException
{
int count = 0, total = 0;
Map<String, Object> params = new HashMap<String, Object>();
executor.startBatch();
for (MyData data: listData)
{
params.put("param name 1", data.getValue());
executor.insert("insertData", params);
count++;
if (count % DB_BATCH_SIZE == 0)
{
total += executor.executeBatch();
executor.startBatch();
}
params.clear();
}
total += executor.executeBatch();
return new Integer(total);
}
});
}
}
Причина в том. Если вы не открываете транзакцию. iBatis выполнит транзакцию после вызова оператора вставки. Для получения дополнительной информации вы можете проверить код в com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate