Spring JDBC是Spring所提供的持久层技术。主要目的是降低使用JDBC API的门槛,以一种更直接,更简洁的方式使用JDBC API。在Spring JDBC里用户仅需要做哪些比不可少的事,而将资源获取,Statement创建,异常处理,资源释放等繁杂而乏味的工作交交给Spring.一、使用Spring JDBC使用JDBC编写数据库的时候,由于JDBC API过于底层,开发者不但需要编写数据操作代码,还需要编写获得JDBC连接、异常处理、释放资源等。而Spring JDBC通过模板和回调机制大大降低了使用JDBC的复杂度,借助JdbcTemplate用户只需要编写实际操作的代码就可以了、1、使用JdbcTemplate创建一张表DriverManagerDataSource ds=new DriverManagerDataSource(); //创建数据源ds.setDriverClassName(com.mysql.jdbc.Driver);ds.setUrl("jdbc://localhost:3309/sampledb");ds.setUsername("root");ds.setPassword("1234");JdbcTemplate jdbcTemplate=new JdbcTemplate();//生成一个JdbcTemplate的实例jdbc.setDataSource(ds);String sql="create table t_user(user_id int primary key,user_name varchar(60))";//创建一张表jdbcTemplate.execute(sql);在上述中,使用DriverManagerDataSource创建一个数据源,紧接着,创建了一个JdbcTemplate对象,然后使用该对象执行SQL语句。JdbcTemplate是线程安全的所有的DAO都共享一个JdbcTemplate实例。因此上述中创建数据源和生成JdbcTemplate都可以在Spring配置文件中统一定义了。2、在DAO中使用JdbcTemplate@Repositorypublic class ViewSpaceDao { @Autowired private JdbcTemplate jdbcTemplate; public void initDb() { String sql = "create table t_user(user_id int primary key,user_name varchar(60))"; jdbcTemplate.execute(sql); }}在Spring配置文件中定义JdbcTemplate并注入每个DAO中。 <!--扫描包以注册注解声明的Bean--> <context:component-scan base-package="com.smart"/><!--配置数据源--> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}"/><!--声明JdbcTemplate--> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" p:dataSource-ref="dataSource"/> 在Spring配置文件中配置DAO一般分为4个步骤: 1)定义DataSource 2)定义JdbcTemplate 3)声明一个抽象的Bean,以便所有DAO复用配置JdbcTemplate属性的配置 4)配置具体的DAO 实战经验: Spring几乎为所有的模板类都提供相应的支持类,与JdbcTemplate对应的支持类为JdbcDaoSupport.JdbcDaoSupport内部定义了JdbcTemplate的成员变量,开发者可以通过扩展JdbcDaoSupport定义自己的Dao,但是随着Bean的注解配置逐渐成为主流配置方式。这种方法便不再可用,因为直接继承JdbcDaoSupport无法对JdbcTemplate成员变量应用@Autowired注解,所以,一般是自己定义一个BaseDao,在BaseDao中定义JdbcTemplate成员变量,并使用@Autowired注解。还会在BaseDao中定义一些通用的功能,如声明JdbcTemplate,分页查询等、二、基本的数据操作数据库的增删改查以及存储过程调用时最基本的数据库操作,JdbcTemplate提供了众多的方法,通过JdbcTemplate用户可以用最简单的方法完成这些数据操作。1、更改数据JdbcTemplate提供了若干update()方法,允许用户对数据表记录进行更改和删除操作。@Repositorypublic class ViewSpaceDao {@Autowired private JdbcTemplate jdbcTemplate; public void addViewSpace(final ViewSpace viewSpace) { final String sql = "INSERT INTO t_view_space(space_name,description,address) VALUES(?,?,?)"; Object[] params = new Object[] { viewSpace.getSpaceName(),viewSpace.getDescription(),viewSpace.getAddress() }; // 方式1 jdbcTemplate.update(sql, params);}}JdbcTemplate在内部通过PreparedStatement执行SQL语句,左移可以使用绑定参数的SQL语句。在sql中?代表一个占位符,而param中的是用于填充占位符的参数数组,在最后直接通过int update(String sql,Object[]args)方法进行表数据的更新通过update(String sql,Object[]args)方法为SQL语句的占位符绑定参数时,并没有显示指定对应字段的数据类型。Spring直接让PreparedStatement进行猜测。更好的方法是使用int update(String sql,Object[]args,int[]argTypes)显示指定每个占位符所对应的字段数据类型此时上述的 jdbcTemplate.update(sql, params);}就会变为jdbcTemplate.update(sql, params,new int[]{Types.VARCHAR,Types.VARCHAR});除了以上的两个update()方法,JdbcTemplate还提供了以下几个功能相似的重载方法int update(String sql):为不带占位符的SQL语句所提供的方法int update(String sql,Object...args):使用不定参数的方法int update(String sql,PreparedStatementSetterpss):PreparedStatementSetter是一个回调接口,他定义了一个void setValues(PreparedStatement ps)接口方法。JdbcTemplate使用SQL语句创建出PreparedStatement实例后,将调用接口执行绑定参数的操作。 jdbcTemplate.update(sql, new PreparedStatementSetter() { public void setValues(PreparedStatement ps) throws SQLException { ps.setString(1,forum.getForumName()); ps.setString(2, forum.getForumDesc()); } });int update(PreparedStatementCreator psc):这也是一个回调接口,他负责创建一个PreparedStatement实例,该接口回调定义了一个PreparedStatement createPrepareStatement(Connection con)方法 KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() { public PreparedStatement createPreparedStatement(Connection conn) throws SQLException { PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, viewSpace.getSpaceName()); ps.setString(2, viewSpace.getDescription()); ps.setString(3, viewSpace.getAddress()); return ps; } }, keyHolder); viewSpace.setSpaceId(keyHolder.getKey().intValue());protected int update(PreparedStatementCreator psc,PreparedStatementSetter pss):联合使用PreparedStatementCreator和PreparedStatementSetter回调。2、返回数据库的表自增主键值用户经常使用数据的自增字段作为表主键,即主键值不在应用层产生,而是在新增记录时数据库产生。当新增记录时允许将数据库自动产生的主键值绑定到Statement或PreparedStatement中,使用Statement时,可以通过如下方法绑定主键值。int executeUpdate(String sql,int autoGenerateKeys)也可以通过Connection创建绑定自增值的PreparedStatementPreparedStatement prepareStatement(String sql,int autoGenerateKeys)当autoGeneratedKeys参数设置为Statement.RETURN_GENERATED_KEYS值时即可绑定数据库产生的主键值,设置为Statement._NO_GENERATED_KEYS不绑定主键值Statement stmt=conn.createStatement();String sql="INSERT INTO T_VIEW(space_name,description)VALUES(‘拨浪鼓‘,‘国家级旅游度假区‘)";stmt.executeUpdate(sql,Statement.RETURN_GENERATED_KEYS);//指定绑定自增主键值if(rs.next()){int key=rs.getInt();}//获取对应的表自增主键值3、批量更改数据public int[] batchUpdate(String[]sql):多条SQL语句组成一个数组,该方法以批量方式执行这些SQL语句,Spring在内部使用JDBC提供的批量更新API完成操作,如果底层的Jdbc Driver不支持批量更新操作,Spring将采用逐条更新的方式模拟批量更新int[] batchUpdate(String sql,BatcgPreparedStatementSetter pss):使用本方法对于统一结构的带参SQL语句多次进行数据更次年操作。通过BatchPreparedStatementSETTER回调接口进行批量参数的绑定工作。而BatchPreparedStatementSetter又定义了两个方法 int getBatchSize():指定本批次的大小 void setValues(PreparedStatement ps ,int i):为指定的PreparedStatement设置参数 public void addViewSpaces(final List<ViewSpace> viewSpaces) { final String sql = "INSERT INTO t_view_space(space_name,description,address) VALUES(?,?,?)"; jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { public int getBatchSize() { return viewSpaces.size(); } public void setValues(PreparedStatement ps, int index) throws SQLException { ViewSpace viewSpace = viewSpaces.get(index); ps.setString(1, viewSpace.getSpaceName()); ps.setString(2, viewSpace.getDescription()); ps.setString(3, viewSpace.getAddress()); } }); jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { public int getBatchSize() { return viewSpaces.size(); } public void setValues(PreparedStatement ps, int index) throws SQLException { ViewSpace viewSpace = viewSpaces.get(index); ps.setString(1, viewSpace.getSpaceName()); ps.setString(2, viewSpace.getDescription()); ps.setString(3, viewSpace.getAddress()); } }); }BatchPreparedStatementSetter是一次性批量提交数据,而不会分批提交,getBatchSize()是整批的大小,所以,如果希望一个LIST钟的数据通过BatchPreparedStatementSETTER批量更新到数据库中getBatchSize()就应该设置为List的大小。4、数据查询使用RowCallbackHandler处理结果集Spring提供了org.springframework.jdbc.core.RowCallbackHandler回调接口,通过该接口可以定义如何从结果集中获取数据。该接口只有一个方法void processRow(ResultSet rs) throw SQLException.Spring会遍历结果集,对结果集中的每一行调用RowCallbackHandler回调接口处理数据,所以我们无须调用ResultSet的next()方法,而只是定义如何获取结果行中的数据的逻辑就可以了。示例:通过id获取数据 public ViewSpace getViewSpace(final int spaceId) { String sql = "SELECT space_name,description,address FROM t_view_space WHERE space_id=?"; final ViewSpace viewSpace = new ViewSpace(); jdbcTemplate.query(sql, new Object[] { spaceId }, new RowCallbackHandler() {//将结果集数据航中的数据抽取到viewSpace对象中 public void processRow(ResultSet rs) throws SQLException { viewSpace.setSpaceId(spaceId); viewSpace.setSpaceName(rs.getString("space_name")); viewSpace.setDescription(rs.getString("description")); viewSpace.setAddress(rs.getString("address")); } }); return viewSpace; }示例:返回多条数据 public List<ViewSpace> getViewSpaces(final int fromId, final int toId) { String sql = "SELECT space_id, SPACE_NAME,description,address FROM t_view_space WHERE space_id between ? and ?"; // 方法1:使用RowCallbackHandler接口 final List<ViewSpace> viewSpaces = new ArrayList<ViewSpace>(); jdbcTemplate.query(sql,new Object[]{fromId,toId},new RowCallbackHandler(){ public void processRow(ResultSet rs) throws//将结果集中的数据映射到List中 SQLException { viewSpace = new ViewSpace(); viewSpace.setSpaceId(rs.getInt("space_id")); viewSpace.setSpaceName(rs.getString("space_name")); viewSpace.setDescription(rs.getString("description")); viewSpace.setAddress(rs.getString("address")); viewSpaces.add(viewSpace); }}); return forums; }5、查询单值数据如果查询的结果仅有一个值,可以用更简单的方式获得结果的值。JdbcTemplate为获取结果集的单值数据提供了3个方法,分别用于获取int long 的单值,其他类型的单值以Object类型返回。int类型的单值查询接口:int queryForInt(String sql)int queryForInt(String sql,Object...args)int queryForInt(String sql,Object[]args,int[]argTypes)示例:public int getViewSpaceNum(){String sql="select count(*) from t_view_space ";return getJdbcTemplate。queryForInt(sql);}long类型的单值查询接口:long queryForLongString sql)long queryForLong(String sql,Object...args)long queryForLong(String sql,Object[]args,int[]argTypes)其他类型的单值查询接口:<T> queryForObject(String sql,Class<T>requiredType)<T> queryForObject(String sql,Object[]args,Class<T>requiredType)<T> queryForObject(String sql,Object[]args,int[]argTypes,Class<T>requiredType)<T> queryForObject(String sql,Object[]args,int[]argTypes,RowMapper<T>rowMapper)<T> queryForObject(String sql,Object[]args,RowMapper<T>rowMapper)<T> queryForObject(String sql,RowMapper<T>rowMapper)6、调用存储过程JdbcTemplate提供了两个调用存储过程的接口方法1)<T>T execute(String callString,CallableStatementCallback<T>action)用户同callString参数指定调用存储过程的SQL语句。第二个参数CallableStatementCallback<T>是一个回调接口,该接口只有一个方法T DoInCallableStatement(CallableStatement cs)影虎可以在该方法中进行输入参数绑定,输出参数注册一级返回数据处理等操作2)<T> T execute(CallableStatementCreator csc,CallableStatementCallback<T>action)该接口方法使用CallableStatementCreator创建CallableStatement,CallableStatementCreator定义了一个方法:CallableStatement createCallableStatement(Connection con),他使用Connection实例创建CallableStatement对象。CallableStatementCallable<T>负责处理存储过程的返回结果。Spring提供了创建CallableStatementCreator的工厂类CallableStatementCreatorFactory,通过该工厂类可以简化CallableStatementCreator的实例的创建工作。例如创建一个存出过场一个入参in_space_id一个出参out_numpublic int getViewPointNum(final int spaceId){ String sql="{call P_GET_VIEW_POINT_NUM(?,?)}";//调用存储过程的SQL语句 Integet num=jdbcTemplate.execute(sql,new CallableStatementCallback<Integer>(){ public Integer doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException{ cs.setInt(1,spaceId);//绑定入参 cs.registerOutParameter(2,Types.INTEGER);//注册输出参数 cs.execute(); return cs.getInt(2); }//获取输出参数的值 }); return num;}或者:public int getSpaceViewPointNum(final int spaceId) { String sql = "{call P_GET_VIEW_POINT_NUM(?,?)}"; CallableStatementCreatorFactory fac = new CallableStatementCreatorFactory(sql);//以一个SQL语句为入参创建CallableStatementCreator工厂实例 fac.addParameter(new SqlParameter("spaceId", Types.INTEGER));//设置存储过程的入参 fac.addParameter(new SqlOutParameter("pointNum", Types.INTEGER));//设置存储过程的出参 Map<String, Integer> paramsMap = new HashMap<String, Integer>(); paramsMap.put("spaceId", spaceId);//为前面的入参指定参数值 CallableStatementCreator csc = fac.newCallableStatementCreator(paramsMap); Integer num = jdbcTemplate.execute(csc, new CallableStatementCallback<Integer>() {//通过new CallableStatementCallback<Integer>创建一个CallableStatementCreator public Integer doInCallableStatement(CallableStatement cs) throws SQLException, DataAccessException { cs.execute(); return cs.getInt(2); } }); return num;} 三、BLOB/CLOB类型数据的操作1、插入Lob类型的数据用于保存数据的表有两个Lob字段,其中description是CLOB类型,而imageFile是BLOB类型package com.smart.dao; import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.sql.*; import java.util.HashMap;import java.util.List;import java.util.Map; import com.smart.domain.ViewPoint;import oracle.jdbc.OracleConnection;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.dao.DataAccessException;import org.springframework.jdbc.LobRetrievalFailureException;import org.springframework.jdbc.core.CallableStatementCallback;import org.springframework.jdbc.core.CallableStatementCreator;import org.springframework.jdbc.core.CallableStatementCreatorFactory;import org.springframework.jdbc.core.JdbcTemplate;import org.springframework.jdbc.core.RowMapper;import org.springframework.jdbc.core.SqlOutParameter;import org.springframework.jdbc.core.SqlParameter;import org.springframework.jdbc.core.support.AbstractLobCreatingPreparedStatementCallback;import org.springframework.jdbc.core.support.AbstractLobStreamingResultSetExtractor;import org.springframework.jdbc.datasource.DataSourceUtils;import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;import org.springframework.jdbc.support.lob.LobCreator;import org.springframework.jdbc.support.lob.LobHandler;import org.springframework.jdbc.support.rowset.SqlRowSet;import org.springframework.stereotype.Repository;import org.springframework.util.FileCopyUtils; @Repositorypublic class ViewPointDao { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private LobHandler lobHandler;//定义LobHandler属性 @Autowired private DataFieldMaxValueIncrementer incre;public void addViewPoint(final ViewPoint viewPoint) { String sql = " INSERT INTO t_view_point(point_id,space_id,point_name,ticket_price,img_file,description)" + " VALUES(?,?,?,?,?,?)"; jdbcTemplate.execute(sql, new AbstractLobCreatingPreparedStatementCallback(this.lobHandler) { protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException { //1:固定主键 //ps.setInt(1,1); //2:通过自增键指定主键值LobHandler属性 ps.setInt(1, incre.nextIntValue()); ps.setInt(2, viewPoint.getSpaceId()); ps.setString(3, viewPoint.getPointName()); ps.setDouble(4, viewPoint.getTicketPrice()); lobCreator.setClobAsString(ps, 6, viewPoint.getDescription());//设置Clob字段 lobCreator.setBlobAsBytes(ps, 5, viewPoint.getImgFile());//设置Blob字段 } }); }}首先在ViewPointDao中引入一个LobHandler属性,并通过jdbcTemplate.execute(sql, new AbstractLobCreatingPreparedStatementCallback(this.lobHandler)方法完成插入Lob数据的操作,通过匿名内部类的方式定义LobCreatingPreparedStatementCallback抽象类的子类,其构造函数需要一个LobHandler入参。在匿名类中实现了父类的抽象方法setValues(PreparedStatement ps,LobCreator lobCreator)在该方法中,通过lobCreator操作Lob对象。配置文件中做更改: <bean id="nativeJdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor" lazy-init="true"/> <bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"<!--使用设置本地JDBC对象抽取只要不是oracle9i则可以将OracleLobHandler改为DefaultLobHandler而且也不需要 <bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler"<!--使用设置本地JDBC对象抽取只要不是oracle9i则可以将OracleLobHandler改为DefaultLobHandler而且也不需要-p:nativeJdbcExtractor-ref="nativeJdbcExtractor"->--> lazy-init="true" p:nativeJdbcExtractor-ref="nativeJdbcExtractor"/> 设置为lazy=true是因为nativeJdbcExtractor需要通过运行期的反射机制获取底层的jdbc对象,所以需要避免让Spring容器启动时就实例化这两个Bean LobHandler需要访问本地Jdbc对象,因此需要通过一个NativeJdbcExtractor Bean来完成任务2、以块数据方式获取Lob数据 用户可以直接以数据块的方式读取Lob数据:以String读取Clob字段的数据,而以byte[]读取Blob字段的数据。 public List<ViewPoint> getImgFiles(final int spaceId) { String sql = " SELECT point_id,img_file FROM t_view_point where point_id =? and img_file is not null "; return jdbcTemplate.query(sql, new Object[]{spaceId}, new RowMapper<ViewPoint>() { public ViewPoint mapRow(ResultSet rs, int rowNum)throws SQLException { int pointId = rs.getInt(1); byte[] attach = lobHandler.getBlobAsBytes(rs, 2);//以二进制的方式获取Blob数据 ViewPoint viewPoint = new ViewPoint(); viewPoint.setPointId(pointId); viewPoint.setImgFile(attach); return viewPoint; } }); } 通过JdbcTemplate的List<T>query(String sql;Object[]args,RowMapper rowMapper)接口处理行数据的映射,在RowMapper回调的mapRow()接口方法中,通过LobHandler以byte[]获取Blob字段的数据3、以流数据方式读取Lob数据 由于Lob数据的体积可能很大,如果直接以块的方式操作Lob数据,需要消耗大量的内存,直接影响到程序的整体运行,对于体积很大的Lob数据,可以使用流的方式进行访问,减少内存的占用,JdbcTemplate为此提供了一个Object query(String sql,Object[]args,ResultSetExtractor rse)fangfa ResultSetExtractor接口拥有一个处理流数据的抽象类org.springframework.jdbc.core.supportAbstractLobStreamingResultS,可以通过扩展此类用流的方式操作Lob字段的数据 public void getImgFile(final int pointId, final OutputStream os) {//用于接收Lob数据的输出流 String sql = " SELECT img_file FROM t_view_point where point_id =? "; jdbcTemplate.query(sql, new Object[]{pointId}, new AbstractLobStreamingResultSetExtractor() {//匿名内部类 protected void handleNoRowFound() throws LobRetrievalFailureException {//处理未找到数据行的情况 System.out.println("Not Found result!"); } public void streamData(ResultSet rs) throws SQLException, IOException {//以流的方式处理Lob字段 InputStream is = lobHandler.getBlobAsBinaryStream(rs, 1); if (is != null) { FileCopyUtils.copy(is, os); } } } ); } 通过扩展 AbstractLobStreamingResultSetExtractor抽象类在streamData(ResultSet rs)方法中以流的方式读取Lob字段数据。这里又利用了Spring的工具类FileCopyUtils,将输入流的数据复制到输出流中。在getImgFile方法中通过入参OutputStream接收Lob的数据 四、其他类型的JdbcTemplate 除了标准的JdbcTemplate之外,Spring还提供了两个好用的JDBC模板类,他们分别是NamedParameterJdbcTemplate和SimpleJdbcTemplate. 1、NamedParameterJdbcTemplate 在低版本的Spring中,用户只能使用?占位符声明参数,并使用索引号绑定参数,使用这种方法绑定参数时,必须足够小心,以确保正确匹配。 @Repository public class ViewSpaceDao { @Autowired private JdbcTemplate jdbcTemplate; @Autowired private NamedParameterJdbcTemplate namedParameterJdbcTemplate; public void addViewSpaceByNamedParams(final ViewSpace viewSpace) { final String sql = "INSERT INTO t_view_space(space_name,description,address) VALUES(:spaceName,:description,:address)";//定义参数源 SqlParameterSource sps = new BeanPropertySqlParameterSource(viewSpace);//定义命名参数 namedParameterJdbcTemplate.update(sql, sps);//使用模板方法 } }需要在Spring的配置文件中添加<bean id="namedParamJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> <constructor-arg ref="dataSource"/> </bean> 在SQL语句中,声明命名参数的格式是:paramName,在这个示例中使用BeanPropertySqlParameterSource提供参数源,他接受一个JavaBean作为构造函数的入参,和标准的JdbcTemplate一样,NamedParameterJdbcTemplate提供了很多的数据访问方法,这些方法大多都拥有一个SqlParameterSource入参,用来提供参数源上述中的spaceName等都是和Sql语句中命名参数匹配,如果数据表记录没有对应的领域对象MapSqlParameterSource sps=new MapSqlParameterSource().addValue("spaceName",viewSpace.getSpaceName()).addValue("address",viewSpace.getAddress());五、使用OO方式访问数据库org.springframework.jdbc.object包下的类允许用户以更加面向对象的方式访问数据库,用户通常也可以直接使用JdbcTemplate完成类似的操作,相对于把一个查询操作封装成一个类而言,我们直接调用JdbcTemplate方法更加简洁,更容易理解。1、使用MappingSqlQuery查询数据SqlQuery是一个可重用,线程安全的类,它封装了一个SQL查询。用户很少需要直接使用SqlQuery,因为其子类MappingSqlQuery作为一个更加易用的实现类能够将结果集中的行映射为Java对象,SqlQuery还有两个扩展类,分别是MappingSqlQueryWithParameters和UpdateableSqlQuery@Repositorypublic class ViewSpaceOODao { @Autowired private DataSource dataSource; private ViewSpaceQuery viewSpaceQuery;//①声明ViewSpaceQuery变量 @PostConstruct public void init() { this.viewSpaceQuery = new ViewSpaceQuery(this.dataSource); //②初始化ForumQuery对象 this.viewSpaceInsert = new ViewSpaceInsert(this.dataSource); this.viewPointNum = new GetViewPointNum(this.dataSource); this.viewSpaceNumCount = new SqlFunction<Integer>(dataSource, "SELECT COUNT(*) FROM t_view_space"); this.viewSpaceNumCount.compile(); }public ViewSpace getViewSpace(int spaceId) { return viewSpaceQuery.findObject(spaceId); //③执行查询并返回结果 } //④定义MappingSqlQuery private class ViewSpaceQuery extends MappingSqlQuery<ViewSpace> { public ViewSpaceQuery(DataSource ds) {//⑤定义查询语句并预编译 super(ds, "SELECT space_id,space_name, description FROM t_view_space WHERE space_id=?"); declareParameter(new SqlParameter(Types.INTEGER)); compile();//⑤-1不能忘记这行编译语句,否则会发生错误 } public ViewSpace mapRow(ResultSet rs, int rownum) throws SQLException {//⑥ ViewSpace viewSpace = new ViewSpace(); viewSpace.setSpaceId(rs.getInt("space_id")); viewSpace.setSpaceName(rs.getString("space_name")); viewSpace.setDescription(rs.getString("description")); return viewSpace; } } 使用MappingSqlQuery一般分为以下3个步骤: 1)定义子类,在子类中声明SQL语句并定义行数据映射逻辑 2)声明子类来的变量并实例化该类 3)使用MappingSqlQuery的方法执行数据查询操作 2、使用SqlUpdate更新数据 @Repository public class ViewSpaceOODao { @Autowired private DataSource dataSource; private ViewSpaceQuery viewSpaceQuery;//①声明ViewSpaceQuery变量 private ViewSpaceInsert viewSpaceInsert; @PostConstruct public void init() { this.viewSpaceQuery = new ViewSpaceQuery(this.dataSource); //②初始化ForumQuery对象 this.viewSpaceInsert = new ViewSpaceInsert(this.dataSource); } //①新增Forum对象 public void addViewSpace(ViewSpace viewSpace) { viewSpaceInsert.insert(viewSpace); } //②扩展SqlUpdate定义子类 private class ViewSpaceInsert extends SqlUpdate { public ViewSpaceInsert(DataSource ds) {//③定义SQL语句并预编译 super(ds, "INSERT INTO t_view_space(space_name, description) VALUES(:spaceName,:description)"); declareParameter(new SqlParameter("spaceName", Types.VARCHAR)); declareParameter(new SqlParameter("description", Types.VARCHAR)); compile(); } } 3、使用StoredProcedure执行存储过程 @Repository public class ViewSpaceOODao { @Autowired private DataSource dataSource; private ViewSpaceQuery viewSpaceQuery;//①声明ViewSpaceQuery变量 private ViewSpaceInsert viewSpaceInsert; private GetViewPointNum viewPointNum; @PostConstruct public void init() { this.viewSpaceQuery = new ViewSpaceQuery(this.dataSource); //②初始化ForumQuery对象 this.viewSpaceInsert = new ViewSpaceInsert(this.dataSource); this.viewPointNum = new GetViewPointNum(this.dataSource); } public int getViewPointNum(int userId) { return viewPointNum.getViewPointNum(userId); } //①扩展StoredProcedure private class GetViewPointNum extends StoredProcedure { private static final String SQL = "P_GET_VIEW_POINT_NUM";//②定义存储过程名 public GetViewPointNum(DataSource ds) { setDataSource(ds); setSql(SQL); //③声明入参 declareParameter(new SqlParameter("spaceId", Types.INTEGER)); //④声明出参 declareParameter(new SqlOutParameter("outNum", Types.INTEGER)); compile(); } public int getViewPointNum(int userId) {//⑤执行存储过程并返回结果 Map<String, Integer> map = new HashMap<String, Integer>(); map.put("userId", userId); Map<String, Object> outMap = execute(map); return (Integer) outMap.get("outNum"); } } } 通过StoredProcedure执行存储过程SQL语句只需指定存储过程的名,不通过占位符声明入参和出参。而通过declareParameter()方法声明入参合成出参。 4、SqlFunction类 SqlFunction操作类封装了一个SQL函数包装器,该包装器适用于查询并返回一个单行结果集的访问操作。默认返回的是一个int值,不过更推荐使用JdbcTemplate中的queryForXxx()方法返回单值数据 @Repository public class ViewSpaceOODao { @Autowired private DataSource dataSource; private SqlFunction<Integer> viewSpaceNumCount; @PostConstruct public void init() { this.viewSpaceNumCount = new SqlFunction<Integer>(dataSource, "SELECT COUNT(*) FROM t_view_space"); this.viewSpaceNumCount.compile(); } public int getViewSpaceNum() { return viewSpaceNumCount.run(); } }
时间: 2024-10-26 11:56:26