用 Java 8 lambda 优化 JDBC

首先创建一个函数接口 ResultSetProcessor

@FunctionalInterface
public interface ResultSetProcessor {
    public void process(ResultSet resultSet, long currentRow) throws SQLException;
}

下面做个简单查询案例,使用这个接口遍历

public static void select(Connection connection, String sql, ResultSetProcessor processor, Object... params) {
        try (PreparedStatement ps = connection.prepareStatement(sql)) {
            int cnt = 0;
            for (Object param : params) 
                ps.setObject(++cnt, param));
            
            try (ResultSet rs = ps.executeQuery()) {
                long rowCnt = 0;
                while (rs.next()) 
                    processor.process(rs, rowCnt++);
                
            } catch (SQLException e) {
                throw new DataAccessException(e);
            }
        } catch (SQLException e) {
            throw new DataAccessException(e);
        }
}

调用这个 select 语句如下:

select(connection, "select * from MY_TABLE",(rs, cnt)-> {       
   System.out.println(rs.getInt(1)+" "+cnt)
});

select 的第三个参数 ResultSetProcessor 这是个函数,所以我们传入的是一个匿名函数。

Streams API

Java 8 提供了更强大的 Streams API,我们可以对 ResultSet 处理更加强大。创建一个自己的 Tuple 类型,代表 ResultSet 中一行记录。下面我们将一个查询和 ResultSet 包装在一个 Iterator 中:

public class ResultSetIterator implements Iterator {
    private ResultSet rs;
    private PreparedStatement ps;
    private Connection connection;
    private String sql;

    public ResultSetIterator(Connection connection, String sql) {
        assert connection != null;
        assert sql != null;
        this.connection = connection;
        this.sql = sql;
    }

    public void init() {
        try {
            ps = connection.prepareStatement(sql);
            rs = ps.executeQuery();

        } catch (SQLException e) {
            close();
            throw new DataAccessException(e);
        }
    }

    @Override
    public boolean hasNext() {
        if (ps == null) {
            init();
        }
        try {
            boolean hasMore = rs.next();
            if (!hasMore) {
                close();
            }
            return hasMore;
        } catch (SQLException e) {
            close();
            throw new DataAccessException(e);
        }

    }

    private void close() {
        try {
            rs.close();
            try {
                ps.close();
            } catch (SQLException e) {
                //nothing we can do here
            }
        } catch (SQLException e) {
            //nothing we can do here
        }
    }

    @Override
    public Tuple next() {
        try {
            return SQL.rowAsTuple(sql, rs);
        } catch (DataAccessException e) {
            close();
            throw e;
        }
    }
}

这是一个遍历器,每次返回 ResultSet 的一行记录,返回类型是我们定义 Tuple。关于 tuple 定义可见源码。我们和 Stream 绑定在一起如下:

public static Stream stream(final Connection connection, final String sql, final Object... parms)  {
  return StreamSupport
                .stream(Spliterators.spliteratorUnknownSize(
                        new ResultSetIterator(connection, sql), 0), false);
}

Java 8 提供 StreamSupport 静态方法 .stream 来创建 java.util.stream.Stream 实例,同时还需要 java.util.stream.Spliterator,这是一个用来遍历和分区一个序列元素(集合)的特殊类型,有了它才能并行处理我们饿操作,而 Spliterators 这是能够对已经存在的集合如 java.util.Iterator 提供并行操作。我们调用上面 stream 如下:

long result = stream(connection, "select TEST_ID from TEST_TABLE")
           .filter((t) -> t.asInt("TEST_ID") % 2 == 0)
           .limit(100)
           .count();

这是查询所有的 TEST_ID,然后过滤掉所有非偶数,最后再运行一个计数。非常简单明了。如果你使用 ORM/JPA 等框架,可能无法让自己的 SQL 代码如此优雅直接了,它类似 Hibernate 的 criteria。

本教程源码下载 https://github.com/jexenberger/lambda-tuples

原文:https://dzone.com/articles/adding-java-8-lambda-goodness

©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页