有彩蛋哦!!!(或者公众号内点击网赚获取彩蛋)
首先已经按照官方推荐方式将Activiti与Spring事务整合在了一起,今天调整表结构之后开启流程抛出异常,业务代码回滚了;但是Activiti的数据没有回滚,回想起来这次做的流程比较简单没有出现异常,Acitiviti配置有之前做个流程引擎的搭建的,自己没有测过事务这块。
刚开始是怀疑Acitivi事务并没有和Spring整合在一起,看了下官方配置没有毛病。然后debug开启流程源码,发现是直接提交到数据库中的,我看了下配置文件配置的auto-commit的确为false,百思不得其解。在翻日志的时候发现一个 AutoCommit 模式设置为“true”时,无法调用回滚操作 这个和配置文件中的不一致,悄悄翻看HikariDataSource源码(我公司用HikariDataSource号称性能最好的数据库连接池)。
调用的构造器 public HikariDataSource() { super(); fastPathPool = null; } /** 默认构造器 * Default constructor */ public HikariConfig() { dataSourceProperties = new Properties(); healthCheckProperties = new Properties(); 默认值 minIdle = -1; maxPoolSize = -1; maxLifetime = MAX_LIFETIME; connectionTimeout = CONNECTION_TIMEOUT; validationTimeout = VALIDATION_TIMEOUT; idleTimeout = IDLE_TIMEOUT; initializationFailTimeout = 1; 设置为了true isAutoCommit = true; 获取JVM系统变量 String systemProp = System.getProperty("hikaricp.configurationFile"); if (systemProp != null) { loadProperties(systemProp); } } 到这里只知道默认isAutoCommit为true,我们都知道数据库连接池维护的是一个线程池,到目前为止没有看到线程池信息,线程池的创建时在获取连接时进行的 public Connection getConnection() throws SQLException { if (isClosed()) { throw new SQLException("HikariDataSource " + this + " has been closed."); } if (fastPathPool != null) { return fastPathPool.getConnection(); } // See http://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java HikariPool result = pool; if (result == null) { synchronized (this) { result = pool; 如果为null创建连接池 if (result == null) { validate(); LOGGER.info("{} - Starting...", getPoolName()); try { pool = result = new HikariPool(this); this.seal(); } catch (PoolInitializationException pie) { if (pie.getCause() instanceof SQLException) { throw (SQLException) pie.getCause(); } else { throw pie; } } LOGGER.info("{} - Start completed.", getPoolName()); } } } return result.getConnection(); } 创建连接池 public HikariPool(final HikariConfig config) { 设置连接池信息 super(config); this.connectionBag = new ConcurrentBag<>(this); this.suspendResumeLock = config.isAllowPoolSuspension() ? new SuspendResumeLock() : SuspendResumeLock.FAUX_LOCK; this.houseKeepingExecutorService = initializeHouseKeepingExecutorService(); checkFailFast(); if (config.getMetricsTrackerFactory() != null) { setMetricsTrackerFactory(config.getMetricsTrackerFactory()); } else { setMetricRegistry(config.getMetricRegistry()); } setHealthCheckRegistry(config.getHealthCheckRegistry()); registerMBeans(this); ThreadFactory threadFactory = config.getThreadFactory(); LinkedBlockingQueue<Runnable> addConnectionQueue = new LinkedBlockingQueue<>(config.getMaximumPoolSize()); this.addConnectionQueue = unmodifiableCollection(addConnectionQueue); this.addConnectionExecutor = createThreadPoolExecutor(addConnectionQueue, poolName + " connection adder", threadFactory, new ThreadPoolExecutor.DiscardPolicy()); this.closeConnectionExecutor = createThreadPoolExecutor(config.getMaximumPoolSize(), poolName + " connection closer", threadFactory, new ThreadPoolExecutor.CallerRunsPolicy()); this.leakTaskFactory = new ProxyLeakTaskFactory(config.getLeakDetectionThreshold(), houseKeepingExecutorService); this.houseKeeperTask = houseKeepingExecutorService.scheduleWithFixedDelay(new HouseKeeper(), 100L, HOUSEKEEPING_PERIOD_MS, MILLISECONDS); if (Boolean.getBoolean("com.zaxxer.hikari.blockUntilFilled") && config.getInitializationFailTimeout() > 1) { final long startTime = currentTime(); while (elapsedMillis(startTime) < config.getInitializationFailTimeout() && getTotalConnections() < config.getMinimumIdle()) { quietlySleep(MILLISECONDS.toMillis(100)); } } } PoolBase(final HikariConfig config) { this.config = config; this.networkTimeout = UNINITIALIZED; this.catalog = config.getCatalog(); this.schema = config.getSchema(); this.isReadOnly = config.isReadOnly(); 可以看到还是config中的值 this.isAutoCommit = config.isAutoCommit(); this.transactionIsolation = UtilityElf.getTransactionIsolation(config.getTransactionIsolation()); this.isQueryTimeoutSupported = UNINITIALIZED; this.isNetworkTimeoutSupported = UNINITIALIZED; this.isUseJdbc4Validation = config.getConnectionTestQuery() == null; this.isIsolateInternalQueries = config.isIsolateInternalQueries(); this.poolName = config.getPoolName(); this.connectionTimeout = config.getConnectionTimeout(); this.validationTimeout = config.getValidationTimeout(); this.lastConnectionFailure = new AtomicReference<>(); initializeDataSource(); } 到这里发现配置文件中auto-commit配置了没有用,因为它根本就不读,那么jdbcurl和 username,password怎么读的呢,是初始化database时读的,由于现在我们项目有两个数 据源,所以重写了平时业务需要的DataSource和JdbcTemplete @Bean @Primary @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource(DataSourceProperties properties) { return DataSourceBuilder.create(properties.getClassLoader()) .type(HikariDataSource.class) .url(properties.determineUrl()) .username(properties.determineUsername()) .password(properties.determinePassword()) .build(); } @Bean @Primary public JdbcTemplate jdbcTemplate(DataSourceProperties properties) { return new JdbcTemplate(dataSource(properties)); } **为什么auto-commit默认为true** 问了大牛之后这样说:auto-commit设置为true是为了保护那些不受事务管理的sql,如果有需要将获取到的连接设置为false,执行之后设置为true。Spring的事物管理就是这样设置的