Как установить autocommit в false в spring шаблоне jdbc

В настоящее время я устанавливаю autocommit в false в spring путем добавления свойства к идентификатору datasource bean, как показано ниже:

   <property name="defaultAutoCommit" value="false" /> 

Но перед выполнением моей процедуры мне нужно добавить его специально в одном java-методе. Я использовал приведенный ниже фрагмент кода.

  getJdbcTemplate().getDataSource().getConnection().setAutoCommit(false);

Но вышеприведенная строка не устанавливала autoocommit в false?
Я что-то пропустил?
или любую альтернативу для установки autocommit в конкретном java-методе spring

Спасибо

Ответ 1

Проблема в том, что вы устанавливаете autocommit для Connection, но JdbcTemplate не запоминает это Connection; вместо этого он получает новое Connection для каждой операции, и это может или не может быть одним и тем же экземпляром Connection, в зависимости от вашей реализации DataSource. Поскольку defaultAutoCommit не является свойством DataSource, у вас есть два варианта:

  1. Предполагая, что ваш конкретный источник данных имеет установщик для defaultAutoCommit (например, org.apache.commons.dbcp.BasicDataSource), defaultAutoCommit DataSource к конкретной реализации. Конечно, это означает, что вы больше не можете изменять свой DataSource в конфигурации Spring, что противоречит цели внедрения зависимости.

((BasicDataSource)getJdbcTemplate().getDataSource()).setDefaultAutoCommit(false);

  1. Установите DataSource для реализации оболочки, которая устанавливает AutoCommit в false каждый раз, когда вы выбираете соединение.

    final DataSource ds = getJdbcTemplate().getDataSource();
    getJdbcTemplate().setDataSource(new DataSource(){
      // You'll need to implement all the methods, simply delegating to ds
    
      @Override
      public Connection getConnection() throws SQLException {
        Connection c = ds.getConnection();
        c.setAutoCommit(false);
        return c;
      }
    });
    

Ответ 2

Вам нужно получить текущее соединение. например.

Connection conn = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
    try {
        conn.setAutoCommit(false);

        /**
         * Your Code
         */
        conn.commit();
    } catch (SQLException e) {
        conn.rollback();
        e.printStackTrace();
    }

Ответ 3

Я только столкнулся с этим и думал, что решение поможет кому-то, даже если это слишком поздно.

Как сказал Йосеф, соединение, которое вы получаете, вызывая getJdbcTemplate().getDataSource().getConnection() может или не может быть тем, которое используется для связи с базой данных для вашей операции.

Вместо этого, если ваше требование состоит в том, чтобы просто протестировать ваш сценарий, а не фиксировать данные, у вас может быть источник данных Apache Commons DBCP с автоматической фиксацией, установленной на ошибку. Определение бина дано ниже:

/**
 * A datasource with auto commit set to false.
 */
@Bean
public DataSource dbcpDataSource() throws Exception {
    BasicDataSource ds = new BasicDataSource();
    ds.setUrl(url);
    ds.setUsername(username);
    ds.setPassword(password);
    ds.setDefaultAutoCommit(false);
    ds.setEnableAutoCommitOnReturn(false);
    return ds;
}

// Create either JdbcTemplate or NamedParameterJdbcTemplate as per your needs
@Bean
public NamedParameterJdbcTemplate dbcpNamedParameterJdbcTemplate() throws Exception {
    return new NamedParameterJdbcTemplate(dbcpDataSource());
}

И использовать этот источник данных для любых таких операций.

Если вы хотите зафиксировать свои транзакции, я предлагаю вам иметь еще один компонент источника данных с автоматическим фиксированием, установленным в true что является поведением по умолчанию.

Надеюсь, это поможет кому-то!

Ответ 4

Вы должны будете сделать для каждого оператора, который выполняет jdbcTemplate. Потому что для каждого jdbcTemplate.execute() и т.д. Он получает новое соединение из пула соединений источника данных. Таким образом, вам нужно будет установить его для соединения, которое jdbcTemplate использует для этого запроса. Так что вам придется сделать что-то вроде

 jdbcTemplate.execute("<your sql query", new PreparedStatementCallback<Integer>(){

        @Override
        public  Integer doInPreparedStatement(PreparedStatement stmt) throws SQLException, DataAccessException 
        {
            Connection cxn = stmt.getConnection();
            // set autocommit for that cxn object to false
            cxn.setAutoCommit(false);
            // set parameters etc in the stmt
            ....
            ....
            cxn.commit();
            // restore autocommit to true for that cxn object. because if the same object is obtained from the CxnPool later, autocommit will be false
            cxn.setAutoCommit(true);
            return 0;

        }
    });

Надеюсь это поможет

Ответ 5

В некоторых случаях вы можете просто добавить @Transactional в метод, например, после некоторой пакетной вставки, выполните commit наконец.

Ответ 6

Я публикую это, потому что искал это везде: я использовал свойство конфигурации в Spring boot, чтобы добиться установки режима автоматической фиксации по умолчанию с помощью:

spring.datasource.hikari.autocommit: false