【发布时间】:2019-04-28 09:55:11
【问题描述】:
我创建了一个带有 spring boot 的项目。我有 hikariConfig 来创建用于连接池的数据源,并将 autocommmit 属性设置为 false。使用在 DataSourceTransactionManager 的 @Transaction 注释的方法中运行的 jdbcTemplate 进行批量插入。程序执行后,我无法看到数据被插入到 Db 中。如果我在 hikariconfig 中使自动提交为真,它就可以正常工作。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Component
@EnableTransactionManagement
public class DataSourceConfig {
@Bean (name = "dateSourceForSqlServer")
public DataSource dataSourceForSqlServer () {
HikariConfig hikariConfig = new HikariConfig();
hikariConfig.setConnectionTimeout(10000L);
hikariConfig.setIdleTimeout(10000L);
hikariConfig.setMinimumIdle(1);
hikariConfig.setMaximumPoolSize(1);
hikariConfig.setMaxLifetime(600000L);
hikariConfig.setConnectionTestQuery("select 1");
hikariConfig.setValidationTimeout(4000L);
hikariConfig.setJdbcUrl("jdbc:sqlserver://localhost:1433;database=invt_mgmt");
hikariConfig.setUsername("sa");
hikariConfig.setPassword("sql_server_pass_123");
hikariConfig.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
hikariConfig.setAutoCommit(false);
return new HikariDataSource(hikariConfig);
}
@Bean (name = "jdbcTemplateForSqlServer")
public JdbcTemplate jdbcTemplateForSqlServer () {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(dataSourceForSqlServer());
return jdbcTemplate;
}
@Primary
@Bean(name = "invtMgmtTxMangerForSqlServer")
public DataSourceTransactionManager transactionManager() {
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSourceForSqlServer());
return manager;
}
}
@Component
public class startBean {
@Autowired
private Business Business;
@PostConstruct
public void startApp() throws SQLException {
Business.insertContainerHierarchy();
Business.insertContainerHierarchy();
}
}
@Component
class public Business {
@Autowired
@Qualifier("jdbcTemplateForSqlServer")
private JdbcTemplate jdbcTemplateForSqlServer;
String insertIntStudent = "INSERT INTO student (id, name) Values(?, ?)";
@Transactional(value = "invtMgmtTxMangerForSqlServer")
public void insertContainerHierarchy () throws SQLException {
System.out.println(TransactionSynchronizationManager.isActualTransactionActive());
System.out.println(TransactionSynchronizationManager.getCurrentTransactionName());
Date start = new Date();
for (int i = 0; i < 500; i++) {
System.out.println(i);
jdbcTemplateForSqlServer.batchUpdate(insertIntStudent, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setInt(1, i);
ps.setString(2, String.valueOf(i));
}
@Override
public int getBatchSize() {
return 1000;
}
});
}
System.out.println(new Date().getTime() - start.getTime());
}
}
我使用了TransactionSynchronizationManager.isActualTransactionActive(),它在方法执行时返回true。
第一季度。为什么数据没有被插入,Transaction 应该在方法执行后自动提交?
第二季度。如果使用spring事务,数据库连接自动提交值会有什么不同吗?
第三季度。目前我如何能够在自动提交设置为 true 的情况下插入?
【问题讨论】:
-
一目了然,示例代码看起来有点奇怪。您有一个包含 500 次迭代的循环,但您使用的是批处理大小为 1000 的 BatchPreparedStatementSetter(这意味着 setValues 将被调用 1000 次)。您真的要插入 500 x 1000 = 500,000 行吗?并且当 for 循环迭代时,下一组插入可能会导致 student.id 上的主键违规。
-
对 id 或 name 没有唯一约束。它是一个虚拟项目,我正在寻找批处理性能,所以是 500 * 1000 行。
标签: java sql-server spring spring-boot spring-transactions