解决方案 »

  1.   

    我在公司的项目里是这样解决这个问题的,我们也用到了Spring的声明式事务,因为是AOP的方式所以只有在方法执行完成后才会去commit或者rollback,这里需要在如果rollback后完成一些善后动作.我们的做法是这样.
    public class OnCallDataSource implements DataSource {
      private DataSource dataSource;    public OnCallDataSource(DataSource dataSource) {
            this.dataSource = dataSource;
            DataSourceUtil.OnCallHouse.allowCall();
        }    public Connection getConnection() throws SQLException {
            return new OnCallConnection(dataSource.getConnection());
        }    //其他方法都是直接委托给原来的DataSource.
    }
    对.就是返回一个我们自己的Connection实现,这个实现包装了原有的正常Connection.
    public class OnCallConnection implements Connection {    private Connection conn;    public OnCallConnection(Connection conn) throws SQLException {
            this.conn = conn;
            this.conn.setAutoCommit(false);
        }    public void commit() throws SQLException {
            this.conn.commit();
            executeCalls(
                    DataSourceUtil.OnCallHouse.getCalls(
                    DataSourceUtil.OnCallHouse.COMMIT_CALLS));
        }    public void rollback() throws SQLException {
            this.conn.rollback();
            executeCalls(
                    DataSourceUtil.OnCallHouse.getCalls(
                    DataSourceUtil.OnCallHouse.ROLLBACK_CALLS));
        }    public void rollback(Savepoint savepoint) throws SQLException {
            this.conn.rollback(savepoint);
            executeCalls(DataSourceUtil.OnCallHouse.getCalls(
                    DataSourceUtil.OnCallHouse.ROLLBACK_CALLS));
        }    private void executeCalls(List<Runnable> calls) {
            if (calls.isEmpty()) {
                return;
            }        Runnable call = null;
            int size = calls.size();
            for (int i = 0; i < size; i++) {
                call = calls.get(i);
                try {
                    call.run();
                } catch (Exception ex) {
                    LOG.errorLog(ex);
                }
            }
            DataSourceUtil.OnCallHouse.clear();
        }//同OnCallDataSource
    }
    最后是那个临时储存回调方法的地方OnCallHouse其实就是利用ThreadLocal来储存回调任务列表的.