技术开发 频道

使用JDBC进行数据访问

JDBC操作的Java对象化
org.springframework.jdbc.object包由一些允许你 以更面向对象的方式访问数据库的类组成。你可以执行查询并获得一个包含业务对象的List, 这些业务对象关系数据的字段值映射成它们的属性。你也可以执行存储过程,更新,删除和插入操作。 

SqlQuery
这是一个表示SQL查询的可重用的而且线程安全的对象。 子类必须实现newResultReader()方法来提供一个对象,它能在循环处理ResultSet的时候保存结果。 这个类很少被直接使用,而使用它的子类MappingSqlQuery,它提供多得多的方法 将数据行映射到Java类。MappingSqlQueryWithParameters 和UpdatableSqlQuery是继承SqlQuery的另外两个实现。

MappingSqlQuery
MappingSqlQuery是一个可以重用的查询对象, 它的子类必须实现抽象方法mapRow(ResultSet, int)来把JDBC ResultSet的每一行转换成对象。

在所有的SqlQuery实现中,这个类是最常使用并且也是最容易使用的。

下面是一个自定义查询的简单例子,它把customer表中的数据映射成叫做Customer的Java类。

private class CustomerMappingQuery extends MappingSqlQuery { public CustomerMappingQuery(DataSource ds) { super(ds, "SELECT id, name FROM customer WHERE id = ?"); super.declareParameter(new SqlParameter("id", Types.INTEGER)); compile(); } public Object mapRow(ResultSet rs, int rowNumber) throws SQLException { Customer cust = new Customer(); cust.setId((Integer) rs.getObject("id")); cust.setName(rs.getString("name")); return cust; } }

 
我们为customer查询提供一个构建方法,它只有数据源这一个参数。 在构建方法中,我们调用超类的构建方法,并将数据源和将要用来查询取得数据的SQL作为参数。 因为这个SQL将被用来建立PreparedStatement,所以它可以包含?来绑定执行时会得到的参数。 每一个参数必须通过declareParameter方法并传递给它一个SqlParameter来声明。 SqlParameter有一个名字和一个在java.sql.Types定义的JDBC类型。 在所有的参数都定义完后,我们调用compile方法建立随后会执行的PreparedStatement。

我们来看一段代码,来实例化这个自定义查询对象并执行:

public Customer getCustomer(Integer id) { CustomerMappingQuery custQry = new CustomerMappingQuery(dataSource); Object[] parms = new Object[1]; parms[0] = id; List customers = custQry.execute(parms); if (customers.size() > 0) return (Customer) customers.get(0); else return null; }


在例子中的这个方法通过一个参数id得到customer。在建立了CustomerMappingQuery 类的一个实例后,我们再创建一个数组,用来放置所有需要传递的参数。 在这个例子中只有一个Integer的参数需要传递。 现在我们使用这个数组执行查询,我们会得到一个List包含着Customer对象, 它对应查询返回结果的每一行。在这个例子中如果有匹配的话,只会有一个实体。

SqlUpdate
这个RdbmsOperation子类表示一个SQL更新操作。就像查询一样, 更新对象是可重用的。和所有的RdbmsOperation对象一样,更新可以有参数并定义在SQL中。

类似于查询对象中的execute()方法,这个类提供很多update()的方法。

这个类是具体的。通过SQL设定和参数声明,它可以很容易的参数化,虽然他也可以子例化 (例如增加自定义方法)。

import java.sql.Types; import javax.sql.DataSource; import org.springframework.jdbc.core.SqlParameter; import org.springframework.jdbc.object.SqlUpdate; public class UpdateCreditRating extends SqlUpdate { public UpdateCreditRating(DataSource ds) { setDataSource(ds); setSql("update customer set credit_rating = ? where id = ?"); declareParameter(new SqlParameter(Types.NUMERIC)); declareParameter(new SqlParameter(Types.NUMERIC)); compile(); } /** * @param id for the Customer to be updated * @param rating the new value for credit rating * @return number of rows updated */ public int run(int id, int rating) { Object[] params = new Object[] { new Integer(rating), new Integer(id)}; return update(params); } }


 StoredProcedure
这是RDBMS存储过程的对象抽象的超类。它是一个抽象类,它的执行方法都是protected的, 以避免被直接调用,而只能通过提供更严格形式的子类调用。

继承的sql属性是RDBMS中存储过程的名字。虽然这个类中提供的其他功能在JDBC3.0中也十分的重要, 但最值得注意的是JDBC3.0中的使用命名的参数。

下面是一段例子程序,它调用Oracle数据库提供的函数sysdate()。 要使用存储过程的功能,你必须创建一个继承StoredProcedure的类. 这里没有任何输入参数,但需要使用SqlOutParameter类声明一个date型的输出参数。 execute()方法会返回一个使用名字作为key来映射每一个被声明的输出参数的实体的Map。

import java.sql.Types; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.sql.DataSource; import org.springframework.jdbc.core.SqlOutParameter; import org.springframework.jdbc.datasource.*; import org.springframework.jdbc.object.StoredProcedure; public class TestSP { public static void main(String[] args) { System.out.println("DB TestSP!"); TestSP t = new TestSP(); t.test(); System.out.println("Done!"); } void test() { DriverManagerDataSource ds = new DriverManagerDataSource(); ds.setDriverClassName("oracle.jdbc.driver.OracleDriver"); ds.setUrl("jdbc:oracle:thin:@localhost:1521:mydb"); ds.setUsername("scott"); ds.setPassword("tiger"); MyStoredProcedure sproc = new MyStoredProcedure(ds); Map res = sproc.execute(); printMap(res); } private class MyStoredProcedure extends StoredProcedure { public static final String SQL = "sysdate"; public MyStoredProcedure(DataSource ds) { setDataSource(ds); setFunction(true); setSql(SQL); declareParameter(new SqlOutParameter("date", Types.DATE)); compile(); } public Map execute() { Map out = execute(new HashMap()); return out; } } private static void printMap(Map r) { Iterator i = r.entrySet().iterator(); while (i.hasNext()) { System.out.println((String) i.next().toString()); } } }

SqlFunction
SQL "function"封装返回单一行结果的查询。默认的情况返回一个int,当然我们可以重载它, 通过额外返回参数得到其他类型。这和使用JdbcTemplate的 queryForXxx方法很相似。使用SqlFunction的好处是 不用必须在后台建立JdbcTemplate。

这个类的目的是调用SQL function,使用像"select user()"或者"select sysdate from dual" 得到单一的结果。它不是用来调用复杂的存储功能也不是用来使用CallableStatement 来调用存储过程或者存储功能。对于这类的处理应当使用StoredProcedure或者SqlCall。

这是一个具体的类,它通常不需要子类化。使用这个包的代码可以通过声明SQL和参数创建这个类型的对象, 然后能重复的使用run方法执行这个function。下面是一个得到一张表的行数的例子:

public int countRows() { SqlFunction sf = new SqlFunction(dataSource, "select count(*) from mytable"); sf.compile(); return sf.run(); }

原文地址

0
相关文章