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);
            }
        });
    }
}

Ссылка: http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/orm/ibatis/SqlMapClientTemplate.html

Причина в том. Если вы не открываете транзакцию. iBatis выполнит транзакцию после вызова оператора вставки. Для получения дополнительной информации вы можете проверить код в com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate

Другие вопросы по тегам