Java 8中引入了Stream API和Lambda功能 ,使我们能够从JDBC ResultSet优雅地转换为仅提供映射功能的对象流。 这种功能当然可以是lambda。 基本上,这个想法是使用ResultSet作为Supplier来生成Stream:

public class ResultSetSupplier implements Supplier<T>{private final ResultSet rs;private final Function<ResultSet, T> mappingFunction;private ResultSetSupplier(ResultSet rs,Function<ResultSet, T> mappingFunction) {this.rs = rs;this.mappingFunction = mappingFunction;}@Overridepublic T get() {try {if (rs.next())return mappingFunction.apply(rs);} catch (SQLException e) {e.printStackTrace();}return null;}}

参数mappingFunction可能是lambda表达式,用于从ResultSet构建T实例。 就像ActiveRecord模式一样,此类ResultSet中的每一行都映射到T的实例,其中列是T的属性。让我们考虑类City

public class City{String city;String country;public City(String city, String country) {this.city = city;this.country = country;}public String getCountry() {return country;}@Overridepublic String toString() {return "City [city=" + city + ", country=" + country + ";]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((city == null) ? 0 : city.hashCode());result = prime * result+ ((country == null) ? 0 : country.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;City other = (City) obj;if (city == null) {if (other.city != null)return false;} else if (!city.equals(other.city))return false;if (country == null) {if (other.country != null)return false;} else if (!country.equals(other.country))return false;return true;}}

City对象的映射函数可以是lambda表达式,如下所示:

(ResultSet rs) -> {try{return new City(rs.getString("city"), rs.getString("country"));} catch (Exception e) {return null;}}

我们假设数据库列分别称为citycountry 。 尽管PreparedStatementResultSet都实现了AutoCloseable接口,但必须提供resultSet才能创建对象流,但在关闭流时也必须关闭此类resultSet。 一种可能的方法是使用代理来拦截对象流上的方法调用。 因此,当在代理上调用close()方法时,它将在提供的resultSet上调用close() 。 为了能够提供所有Stream功能,所有方法调用也将在对象流上被调用。 使用代理很容易实现。 我们来看一下。 我们将有一个代理工厂和一个调用处理程序:

public class ResultSetStreamInvocationHandler<T> implements InvocationHandler{private Stream<T> stream; // proxy will intercept method calls to such streamprivate PreparedStatement st;private ResultSet rs;public void setup(PreparedStatement st, Function<ResultSet, T> mappingFunction)throws SQLException{// PreparedStatement must be already setup in order// to just call executeQuery()this.st = st;rs = st.executeQuery();stream = Stream.generate(new ResultSetSupplier(rs, mappingFunction));}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {if (method == null)throw new RuntimeException("null method null");// implement AutoCloseable for PreparedStatement// as calling close() more than once has no effectsif (method.getName().equals("close") && args == null){// invoked close(), no argumentsif (st != null){st.close(); // closes ResultSet too}}return method.invoke(stream, args);}private class ResultSetSupplier implements Supplier<T>{private final ResultSet rs;private final Function<ResultSet, T> mappingFunction;private ResultSetSupplier(ResultSet rs, Function<ResultSet, T> mappingFunction) {this.rs = rs;this.mappingFunction = mappingFunction;}@Overridepublic T get() {try {if (rs.next())return mappingFunction.apply(rs);} catch (SQLException e) {e.printStackTrace();}return null;}
}}

请注意如何使用invoke来拦截方法调用。 在接近的情况下()被调用时, 关闭()调用的PreparedStatement为好。 对于每个调用的方法,将在代理的流中调用相应的方法调用。 和工厂:

public class ResultSetStream<T>{@SuppressWarnings("unchecked")public Stream<T> getStream(PreparedStatement st,Function<ResultSet, T> mappingFunction) throws SQLException{final ResultSetStreamInvocationHandler<T> handler =new ResultSetStreamInvocationHandler<T>();handler.setup(st, mappingFunction);Stream<T> proxy = (Stream<T>) Proxy.newProxyInstance(getClass().getClassLoader(),new Class<?>[] {Stream.class},handler);return proxy;}
}

综上所述,让我们编写一个简单的测试来显示用法。 Mockito将用于模拟PreparedStatementResultSet以避免对实际数据库运行测试。

public class ResultSetStreamTest {private class City{String city;String country;public City(String city, String country) {this.city = city;this.country = country;}public String getCountry() {return country;}@Overridepublic String toString() {return "City [city=" + city + ", country=" + country + "]";}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + getOuterType().hashCode();result = prime * result + ((city == null) ? 0 : city.hashCode());result = prime * result+ ((country == null) ? 0 : country.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;City other = (City) obj;if (!getOuterType().equals(other.getOuterType()))return false;if (city == null) {if (other.city != null)return false;} else if (!city.equals(other.city))return false;if (country == null) {if (other.country != null)return false;} else if (!country.equals(other.country))return false;return true;}private ResultSetStreamTest getOuterType() {return ResultSetStreamTest.this;}}private String[][] data = new String[][]{{"Karachi", "Pakistan"},{"Istanbul", "Turkey"},{"Hong Kong", "China"},{"Saint Petersburg", "Russia"},{"Sydney", "Australia"},{"Berlin", "Germany"},{"Madrid", "Spain"}};private int timesCalled;private PreparedStatement mockPST;private ResultSet mockRS;@Beforepublic void setup() throws SQLException{timesCalled = -1;mockRS = mock(ResultSet.class);mockPST = mock(PreparedStatement.class);when(mockRS.next()).thenAnswer(new Answer<Boolean>() {@Overridepublic Boolean answer(InvocationOnMock invocation) throws Throwable {if (timesCalled++ >= data.length)return false;return true;}});when(mockRS.getString(eq("city"))).thenAnswer(new Answer<String>() {@Overridepublic String answer(InvocationOnMock invocation) throws Throwable {return data[timesCalled][0];}});when(mockRS.getString(eq("country"))).thenAnswer(new Answer<String>() {@Overridepublic String answer(InvocationOnMock invocation) throws Throwable {return data[timesCalled][1];}});when(mockPST.executeQuery()).thenReturn(mockRS);}@Testpublic void simpleTest() throws SQLException{try (Stream<City> testStream = new ResultSetStream<City>().getStream(mockPST,(ResultSet rs) -> {try {return new City(rs.getString("city"), rs.getString("country"));} catch (Exception e) {return null;}})){Iterator<City> cities = testStream.filter(city -> !city.getCountry().equalsIgnoreCase("China")).limit(3).iterator();assertTrue(cities.hasNext());assertEquals(new City("Karachi", "Pakistan"), cities.next());assertTrue(cities.hasNext());assertEquals(new City("Istanbul", "Turkey"), cities.next());assertTrue(cities.hasNext());assertEquals(new City("Saint Petersburg", "Russia"), cities.next());assertFalse(cities.hasNext());}}}
  • 在Github上下载完整的源代码。

翻译自: https://www.javacodegeeks.com/2014/09/creating-an-object-stream-from-a-jdbc-resultset.html

从JDBC ResultSet创建对象流相关推荐

  1. 如何使用Java 8 FlatMap JDBC ResultSet?

    您还不喜欢机能吗? 这样标题可能不会引起您的共鸣-但文章会! 相信我. 本质上,我们想要这样: +------+------+------+ | col1 | col2 | col3 | +----- ...

  2. 由DB2分页想到的,关于JDBC ResultSet 处理大数据量

    最近在处理DB2 ,查询中,发现如下问题.如果一个查询 count(*),有几十万行,分页如何实现 select row_number() over (order by fid desc ) as r ...

  3. Java:将JDBC ResultSet作为JSON流式传输

    这篇文章展示了如何将java.sql.ResultSet转换为JSON并将其流回调用方. 如果要将大型数据集从JDBC数据源以JSON格式发送到Web应用程序,此功能很有用. 流式传输使您可以一点一点 ...

  4. 使用jOOQ的MockDataProvider破解简单的JDBC ResultSet缓存

    某些查询不应该一直访问数据库. 例如,当您查询主数据 (例如系统设置,语言,翻译等)时,您可能希望避免一直通过网络发送相同的愚蠢查询(和结果). 例如: SELECT * FROM languages ...

  5. JDBC ResultSet 可更新的结果集

    2019独角兽企业重金招聘Python工程师标准>>> 接着上一篇:可滚动的结果集: 1)com.microsoft.sqlserver.jdbc.SQLServerExceptio ...

  6. JDBC ResultSet分析

    JDBC1.0 .JDBC2.0 .JDBC3.0 中分别用以下方法创建Statement . JDBC1.0 : createStatement() JDBC2.0 : createStatemen ...

  7. jdbc如何写csv文件_Java:将JDBC结果集作为CSV流化

    jdbc如何写csv文件 在上一篇文章中 ,我展示了如何将java.sql.ResultSet转换为JSON并将其流回调用方. 这篇文章是关于以CSV格式流式传输. 流式传输使您可以一点一点地传输数据 ...

  8. q7goodies事例_Java 8 Friday Goodies:SQL ResultSet流

    q7goodies事例 在Data Geekery ,我们喜欢Java. 而且,由于我们真的很喜欢jOOQ的流畅的API和查询DSL ,我们对Java 8将为我们的生态系统带来什么感到非常兴奋. 我们 ...

  9. Java:以CSV格式流式传输JDBC结果集

    在上一篇文章中 ,我展示了如何将java.sql.ResultSet转换为JSON并将其流回调用方. 这篇文章是关于以CSV格式流式传输的. 流式传输使您可以一点一点地传输数据,而不必将所有数据都加载 ...

最新文章

  1. div 隐藏_注入WordPress网站的隐藏垃圾邮件链接
  2. malloc和new出来的地址都是虚拟地址 你就说内存管理单元怎么可能让你直接操作硬件内存地址!...
  3. sqlserver order by自定义数字排序 其他_苹果cms怎么自定义伪静态规则?
  4. JQuery中text(),html(),val()的区别
  5. 新数据革命:开源图形化数据引擎Hawk5发布
  6. python安装opencv whl_Python 3.x 安装opencv+opencv_contrib的操作方法
  7. CentOS 6.5 安装mysql5.5
  8. 微信一键设置“姓氏头像”,学起来!
  9. KMP算法的浅显解释
  10. 我的世界网易版java材质包下载_我的世界超强光影SMUS网易专版
  11. html鼠标右键代码,Html鼠标右键菜单代码
  12. D. Relatively Prime Graph codeforces 1009 D
  13. 生物信息电脑运行环境搭建-Python R Linux
  14. 小学生心算CAI系统
  15. 金额换算(数字换汉字)
  16. ARM服务器搭载的操作系统
  17. JavaScript 的 Math.floor() 函数
  18. golang的timer的一些坑
  19. Google reCAPTCHA ----------验证码
  20. 个人建设网站流程解说,手把手教你如何在阿里云上搭建自己的网站

热门文章

  1. tomcat(4)Tomcat的默认连接器
  2. leetcode初级算法4.只出现一次的数字
  3. ibm收购red hat_IBM将收购Red Hat:面向Java的初衷
  4. vue中生产模式和调试模式_为什么在生产中进行调试是如此诱人?
  5. apache pulsar_Apache Pulsar:分布式Pub-Sub消息系统
  6. 使用实例工厂方法实例化_一些工厂实例
  7. 敏捷中gwt含义_在GWT中序列化/反序列化Json
  8. drools6.5_Drools 6.5.0.Final可用
  9. dojo还有人用吗_我的Dojo中有一个Mojo(如何编写Maven插件)
  10. 有效Java第三版的源代码已更新为使用较新的功能