就 JdbcTemplate 上的各个方法来看,它封装了 JDBC 处理的细节,让您不用接触到底层的资料库 技术,然而 JdbcTemplate 的各个方法仍须熟悉如何使用 SQL 语法, 如果您想让一些程式开发人 员不用接触到 SQL 语法,在 Spring 中,您可以进一步建立可重用的操作物件,建立之后在进行 资料库设计时,将这些设计完成的 可重用物件给开发人员使用,他们就无需接触到 SQL 的细节, 从他们的观点来看,资料库操作更接近物件导向的操作方式。
Spring 提供 org.springframework.jdbc.object 套件,让您以更物件导向的方式来设计资料库操作方 面的程式,您只要事先 继承或直接实例化相对应的类别并编译,之后就可以重复利用这个实例, 呼叫它的方法来进行资料库相关操作,而不用接触 SQL 等相关细节。
org.springframework.jdbc.object.RdbmsOperation 是个抽象类,代表 RDBMS(Relational Database Management System )的 查 询、更 新 、预存 程 序等操 作 ,您可 以 使用其 子 类 org.springframework.jdbc.object.SqlUpdate、 org.springframework.jdbc.object.MappingSqlQuery 等 类别,它们被设计为执行绪安全(Thread‐ safe),所以您可以在多执行绪的环境下重复使用这些 类别的实例。
SqlFunction 用来调用 SQL Function,例如可以调用 COUNT(),然后返回一个整数表示查询到的资 料笔数,下面是一个例子:
SqlFunction sf = newSqlFunction(dataSource, "SELECT COUNT(*) from user"); sf.compile(); sf.run();
RdbmsOperation的子类别在设定好DataSource、SQL以及相关参数后,必须先呼叫compile()进行编 译,之后就可以重复使用这个实例,在设计时可以继承SqlFunction来封装SQL,例如修改使用 JdbcTemplate 的内容,新增一个类别如下所示:
package onlyfun.caterpillar; import javax.sql.DataSource; import org.springframework.jdbc.object.SqlFunction; public class UserFunction extends SqlFunction { public UserFunction(DataSource dataSource) { super(dataSource, "SELECT COUNT(*) from user"); compile(); } }
SqlUpdate 类别用来表示一个 SQL 的更新操作,您也可以设定相关参数,设计时也可以继承它来 进行 SQL 的封装,例如:
package onlyfun.caterpillar; import java.sql.Types; import javax.sql.DataSource; import org.springframework.jdbc.object.SqlUpdate; public class UserUpdate extends SqlUpdate { public UserUpdate(DataSource dataSource) { super(dataSource, "INSERT INTO user (name,age) VALUES(?,?)"); int[] types = {Types.VARCHAR, Types.INTEGER}; setTypes(types); compile(); } }
setTypes()方法用来设定 SQL 中"?"占位字元所要插入的数据类型,之后执行 update()方法时,可 以仅指定物件阵列作为引数来进行查询,每一个阵列值将实际取代"?"占位字元,例如可以这么 使用:
... SqlUpdate userUpdate = new UserUpdate(dataSource); ... userUpdate.update(new Object[] {user.getName(), user.getAge()});
SqlQuery 类别表示一个 SQL 查询操作,不过通常很少直接使用这个类,因为通常查询到资料之后, 会作一些处理,例如封装为 User 类别的实例,您可 以使用它的子类别 org.springframework.jdbc.object.MappingSqlMapping 来进行这个动作,例如:
package onlyfun.caterpillar; import java.sql.ResultSet; import java.sql.SQLException; import javax.sql.DataSource; import org.springframework.jdbc.object.MappingSqlQuery; public class UserQuery extends MappingSqlQuery { public UserQuery(DataSource dataSource) { super(dataSource, "SELECT * FROM user"); compile(); } protected Object mapRow(ResultSet rs, int rowNum) throws SQLException { User user = new User(); user.setId(new Integer(rs.getInt("id"))); user.setName(rs.getString("name")); user.setAge(new Integer(rs.getInt("age"))); return user; } }
设计好这个类别之后,您可以这么使用它:
... SqlQuery userQuery = new UserQuery(dataSource); ... List users = userQuery.execute();
执行完 execute()方法后,实际上传回的 List 中会有 User 类别的实例,当中并封装了查询后的每 一笔资料。 配合以上的几个实作,您可以再改写一下 IUserDAO 介面与 UserDAO 实作,例如:
package onlyfun.caterpillar; import java.util.List; public interface IUserDAO { public void insert(User user); public List allUser(); public int count(); }
假设您是程式开发人员,有其它的负责资料库存取方面的程式,并提供了以上的 UserFunction、 UserUpdate 与 UserQuery 类别,则 您可以不用关心实际的 SQL 是如何下达的,可以使用 UserFunction、UserUpdate 与 UserQuery 类别来设计您的 UserDAO 类 别:
package onlyfun.caterpillar; import java.util.List; import javax.sql.DataSource; import org.springframework.jdbc.object.SqlFunction; import org.springframework.jdbc.object.SqlQuery; import org.springframework.jdbc.object.SqlUpdate; public class UserDAO implements IUserDAO { private SqlUpdate userUpdate; private SqlQuery userQuery; private SqlFunction userFunction; public void setDataSource(DataSource dataSource) { userUpdate = new UserUpdate(dataSource); userQuery = new UserQuery(dataSource); userFunction = new UserFunction(dataSource); } public void insert(User user) { userUpdate.update(new Object[] {user.getName(), user.getAge()}); } public List allUser() { return userQuery.execute(); } public int count() { return userFunction.run(); } }
将 SQL 封装重用之后,从 UserDAO 程式撰写的角度来看,完全是物件操作的方式来进行,配合 程式的修改,可以写个简单的程式来看看运作是否正常:
• SpringDAODemo.java
package onlyfun.caterpillar; import org.springframework.context.ApplicationContext; import org.springframework.context. support.FileSystemXmlApplicationContext; import java.util.List; public class SpringDAODemo { public static void main(String[] args) { ApplicationContext context =new FileSystemXmlApplicationContext( "beans-config.xml"); User user = new User(); user.setName("just933"); user.setAge(new Integer(26)); IUserDAO userDAO =(IUserDAO) context.getBean("userDAO"); userDAO.insert(user); System.out.println("笔数: " + userDAO.count()); List list = userDAO.allUser(); for(int i = 0; i < list.size(); i++) { User next = (User) list.get(i); System.out.println("\n\tId:\t" + next.getId()); System.out.println("\tName:\t" + next.getName()); System.out.println("\tAge:\t" + next.getAge()); } } }