【问题标题】:How to set autocommit to false in spring jdbc template如何在spring jdbc模板中将自动提交设置为false
【发布时间】:2014-10-01 14:17:35
【问题描述】:

目前,我通过向数据源 bean id 添加属性,在 spring 中将 autocommit 设置为 false,如下所示:

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

但是在执行我的程序之前,我需要将它专门添加到单个 java 方法中。 我使用了下面的代码 sn-p。

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

但上面的行没有将 autocommit 设置为 false?
我错过了什么吗?
或通过spring在特定java方法中设置自动提交的任何替代方法

谢谢

【问题讨论】:

  • 我知道可以通过属性标签将自动提交设置为 false 到数据源 bean id.. 但我不想以这种方式设置它。我想在java数据库业务逻辑方法中设置autocommit false
  • @shirish : 你提供的链接告诉我我已经做了什么......!
  • 为什么?如果您使用事务管理器,默认情况下会禁用自动提交。您的方法不起作用,因为它会给您一个非托管连接(如果您运行 x 次,其中 x 是池中的连接数,您的池将被耗尽)。
  • @M.Denium。你能帮助我如何做到这一点以及使用事务管理器的设置是什么

标签: spring spring-mvc spring-jdbc spring-transactions


【解决方案1】:

问题是您在Connection 上设置自动提交,但JdbcTemplate 不记得Connection;相反,它会为每个操作获取一个新的Connection,这可能是也可能不是相同的Connection 实例,具体取决于您的DataSource 实现。由于defaultAutoCommit 不是DataSource 上的属性,您有两种选择:

  1. 假设您的具体数据源具有defaultAutoCommit 的设置器(例如org.apache.commons.dbcp.BasicDataSource),请将DataSource 转换为您的具体实现。当然,这意味着您不能再在 Spring 配置中更改 DataSource,这违背了依赖注入的目的。

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

【讨论】:

  • 我们获取结果时是否必须提交
  • @Haider 关于 Oracle 不。 Savepoint 在 dml 语句之前创建。还要记住,在 ddl stmt 上发生了隐式提交。
【解决方案2】:

您需要获取当前连接。例如

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

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

【讨论】:

    【解决方案3】:

    我只是遇到了这个问题,并认为即使为时已晚,该解决方案也会对某人有所帮助。

    正如 Yosef 所说,您通过调用 getJdbcTemplate().getDataSource().getConnection() 方法获得的连接可能是也可能不是用于与数据库进行通信以进行操作的连接。

    相反,如果您的要求只是测试您的脚本,而不是提交数据,您可以将自动提交设置为错误的 Apache Commons DBCP 数据源。 bean定义如下:

    /**
     * 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());
    }
    

    并将此数据源用于任何此类操作。

    如果您希望提交事务,我建议您再设置一个数据源 bean,并将自动提交设置为 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;
      
              }
          });
      

      希望对你有帮助

      【讨论】:

      • 如果commit() 抛出异常而cxn.setAutoCommit(true) 没有执行怎么办?
      • @broc.seib 公平点,cxn.setAutoCommit(true) 应该在 finally 块中。但我希望答案能说明如何在 JDBCTemplate 中将 autocommit 设置为 false
      【解决方案5】:

      在某些情况下,您可以在方法中添加 @Transactional,例如经过一些批量插入后,最后执行提交。

      【讨论】:

        【解决方案6】:

        我发布这个是因为我到处都在寻找它:我在 Spring boot 中使用配置属性来实现设置默认自动提交模式:

        spring.datasource.hikari.auto-commit: false
        

        Spring Boot 2.4.x Doc for Hikari

        【讨论】:

        • 谢谢!这在我的 spring-boot 项目中有效,而不是 spring.datasource.auto-commit=false!
        【解决方案7】:

        5 年后仍然是一个有效的问题,我以这种方式解决了我的问题:

        1. 使用connection.setAutoCommit(false)设置连接;
        2. 使用该连接创建一个 jbc 模板;
        3. 做好你的工作并承诺。
            Connection connection = dataSource.getConnection();
            connection.setAutoCommit(false);
            JdbcTemplate jdbcTemplate = 
            new  JdbcTemplate(newSingleConnectionDataSource(connection, true));
            // ignore case in mapping result
            jdbcTemplate.setResultsMapCaseInsensitive(true);
            // do your stuff
            connection.commit();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-03-27
          • 2015-04-13
          • 1970-01-01
          • 2019-07-30
          • 1970-01-01
          • 1970-01-01
          • 2013-04-24
          • 1970-01-01
          相关资源
          最近更新 更多