首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 数据库 > 其他数据库 >

Spring札记6-JDBC的集成

2012-10-11 
Spring笔记6---JDBC的集成一. 无论采用何种持久化技术,JDBC始终都是它们的支撑件,如果没有底层的JDBC,ORM

Spring笔记6---JDBC的集成

一. 无论采用何种持久化技术,JDBC始终都是它们的支撑件,如果没有底层的JDBC,ORM是没有办法操控RDBMS的。

??Spring 对 JDBC的集成主要包含了:

??1.提供各种模板类,简化了对RDBMS的CRUD操作,这些模板包括 ? ? ? ? ? ? ? ? ? ?

?? ? JdbcTemplate,NamedParameterJdbcTemplate,SimpleJdbcTemplate等等。这些模板类都是线程安全的,即在多线程环境中能始终保持一致的行为,尤其是Web环境。

?

??2.提供了各种DaoSupport辅助类,进一步简化了模板类的使用。?比如

?? ? JdbcDaoSupport,NamedParameterJdbcDaoSupport,SimpleJdbcDaoSupport。

?

??3.提供了SimpleJdbcInsert和SimpleJdbcCall辅助类。

?

??4.提供了各种数据源类,借助DI容器实现了DataSource的灵活配置。

?

??5.提供了更多高级辅助类,比如:

?? ? ?将JDBC CRUD操作建模成JAVA对象、LOB处理、操控存储过程、大批量数据处理、获得和生成主键等。

?

二. JdbcTemplate是JDBC集成的核心类,简化了JDBC API的使用。

?

1. 不用重新写调用java.sql.Connection对象的语句。

?

?

jdbcTemplate.execute(new ConnectionCallback(){   public Object doInConnectin(Connection con) throws SQLException,DataAccessException{      log.info(con.getMetaData().getDriverName);      return null;  }});

?? ?*Spring 自身会从数据源中获得一Connection对象,并传入到doInConnection回调方法中。

?

2. 有若干方法用于执行静态SQL语句,即使用java.sql.Statement API.

?

?

..... execute(....) throws ......... query(.....) throws .......... queryForObject (.....) throws .......... queryForList (.....) throws .......... queryForMap (.....) throws .......... queryForRowSet (.....) throws .....int  update (.....) throws .....int[]  batchUpdate (.....) throws .....

?? *结果集处理接口:ResultSetExtractor,RowCallbackHandler,RowMapper(线程安全,用的最多,包含许多子集,例如ColumnMapRowMapper,BeanPropertyRowMapper).

?

3. 有若干方法用于执行动态sql语句,即使用java.sql.PrepareStatement API.

?

?

..... execute(....) throws ......... query(.....) throws .......... queryForObject (.....) throws .......... queryForList (.....) throws .......... queryForMap (.....) throws .......... queryForRowSet (.....) throws .....int  update (.....) throws .....int[]  batchUpdate (.....) throws .....
?

?*大多方法都含有Object[] args参数,即这些方法都会采用预编译语句,执行效率更高。Hibernate就大量采用了预编译语句。

?

4. 有若干方法用于执行RDBMS的存储操作,即使用java.sql.CallableStatement API.

?

?

..... execute(....) throws ....Map call(CallablestatementCreator csc,List declaredParameters) throws DataAccessException;
?

三. JdbcDaoSupport是建立在JdbcTemplate基础上的支持类,其辅助类会自动创建相应模板类。

?

?? ?在使用JdbcDaoSupportImpl实现类之前,需要配置示例如下:

?

?

<bean id="jdbcDaoSupport" ref="dataSource"/><bean>

?

?? ?或者直接提供一个JdbcTemplate给JdbcDaoSupportImpl,如下配置:

?

?

<bean id="jdbcDaoSupport" ref="jdbcTemplate"/><bean>
?

四. SimpleJdbcDaoSupport及NamedParameterJdbcDaoSupport;NamedParameterJdbcTemplate及 ? ? SimpleJdbcTemplate的相应支持类。

?

?例如:SimpleJdbcInsert和SimpleJdbcCall支持辅助类,前者用于操作表,后者用于操作存储过程或函数,它们的某些功能比SimpleJdbcTemplate更为强大,而且都是线程安全的。

?

*.SimpleJdbcInsert的usingGeneratedKeyColumns()能自动生成主键id,例子如下:

?

?

ownerInsert = new SimpleJdbcInsert(dataSource).withTableName("owner").usingGeneratedKeyColumns("id");param = new HashMap<String,Object>();param.put("fistname","Nedd");param.put("lastname","Want");log.info(ownerInsert.executeAndReturnKey(param));

?

五.内置的DataSource继承。

?

1.基于测试目的DriverManagerDataSource,SimpleDriverDataSource和SingleConnectionDataSource.

?

2.Apache DBCP数据源。(实现了连接池)

?

?

<bean id = "dataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" />
?

??上面的bean中配置了destroy-method属性,当销毁Spring DI容器时,BasicDataSource对象的close()方法便会被触发,从而优雅地关闭掉底层连接池持有的数据库连接。

?

3. 其他数据源。

?

?? *Java EE容器内置的数据源:能从JNDI树上查找到已经注册的DataSource实现。示例如下:

?

?

 <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/petclinic">
?

?

?

?? *LazyConnectionDataSourceProxy:会代理其他数据源。

?

?? *TransactionAwareDataSourceProxy:能使得当前的CRUD操作能够参与到Spring的受管事务中。如果当前不存在活动事务,则会使用默认行为,通常在开发中很少用到。

?

?? *UserCredentialsDataSourceAdapter: 将连接数据库的用户凭证信息(用户名,密码)传入到getConnection(String username,String password)方法中。一旦配置好后,客户每次获得数据库连接,都会调用getConnection方法。

?

?? *IsolationLevelDataSourceAdapter:启用isolationLevelName属性能指定隔离级别。继承于UserCredentialsDataSourceAdapter。

?

?? *WebSphereDataSourceAdapter:继承于IsolationLevelDataSourceAdapter,会从WebSphere容器获得数据源。并借助WebSphere专有的api达到启用自定义隔离级别的目的。

?

?? *IsolationLevelDataSourceRouter: 会根据当前Spring受管事务启用的隔离级别来选定合适的DataSource数据源。

?

六. 将JDBC操作建模成Java对象。

?

?? 1. SqlUpdate辅助类

?? 2. UpdatableSqlQuery辅助类

?? 3. MappingSqlQuery辅助类 :能将SQL select查询结果集自动转换成领域对象集合,返回给调用者。其子类必须实现mapRow()方法,它内置大量的execute()和findObject()方法。

?? 4. SqlFunction辅助类。

?

七. 与存储过程交互。

?

?? 1. JdbcTemplate针对存储过程提供的支持。

?

?

Object execute(CallableStatementCreator csc, CallableStatmentCallback action) throws DataAccessException;Object execute(String callString, CallableStatmentCallback action) throws DataAccessException;Object execute(CallableStatementCreator csc, List declaredParameters) throws DataAccessException;
?

?如果使用了CallableStatmentCallback回调接口,则要实现doInCallableStatement()方法。

?

?? 2. StoredProcedure辅助类。

?

?? 3. SimpleJdbcCall 辅助类。重要辅助类。

?

?

SimpleJdbcCall sjc = new SimpleJdbcCall(ds);sjc.withProcedureName("show_sal");sqlParameterSource sps = new MapSqlParameterSource().addValue("enames","SMITH").addValue("empnos",7369);log.info(sjc.execute(sps));
?

以上开发者直接将存储过程名告知withProcedureName()方法,并将参数提供给了execute方法。

?

如果需要制定传入传出参数,可借助SimpleJdbcCall内置的 declareParameters()方法,示例如下,SqlParameters用于指定传入参数,而SqlOutParameters用于指定传出参数:

?

?

SimpleJdbcCall sjc = new SimpleJdbcCall(ds).withProcedureName("show_sal");sjc.declareParameters(new SqlParameter("enames",Types.VARCHAR)).declareParameters(new SqlParameter("empnos",Types.VARCHAR)).declareParameters(new SqlParameter("sals",Types.FLOAT)).withoutProcedureColumnMetaDataAccess();sqlParameterSource sps = new MapSqlParameterSource().addValue("enames","SMITH").addValue("empnos",7369);log.info(sjc.execute(sps));
?

一旦启用了declareParameters()方法,withoutProcedureColumnMetaDataAccess()方法也就该被调用,从而避免再去从底层jdcb驱动获得RDBMS相关元数据,比如存储过程的输入输出参数。

?

?

八. 处理大批量数据。

?

1. JdbcTemplate内置的batchUpdate()方法。

?

?

int[] batchUpdate(String[] sql) throws DataAccessException;int[] batchUpdate(String[] sql,BatchPreparedStatementSetter pss) throws DataAccessException;

?

?

例如:

?

?

final int[] no= new int[]{324,543,1234,421,32142,3212};jdbcTemplate.batchUpdate("update emp set sal = ? where empno = ?",new BatchPreparedStatementSetter(){ public void setValues(PreparedStatement ps,int i) throws SQLException{  ps.setInt(1,no[i]);  ps.setFloat(2,no[i]);}  public int getBatchSize(){    return no.length;}}){}
?

?

2. SimpleJdbcTemplate内置的batchUpdate方法。

?

int[] batchUpdate(String sql,Map[] batchValues) ;int[] batchUpdate(String sql,SqlParameterSource[] batchArgs) ;int[] batchUpdate(String sql,List<Object> batchArgs);int[] batchUpdate(String sql,List<Object> batchArgs,int[] argTypes);
?

List对象作为参数示例:

?

SimpleJdbcTemplate sjt = xxx.getBean("simpleJdbcTemplate");List<Object[]> paramList = new ArrayList<Object[]>();paramList.add(new Integer[]{2342,23423});paramList.add(new Integer[]{2342,23423});paramList.add(new Integer[]{2342,23423});paramList.add(new Integer[]{2342,23423});paramList.add(new Integer[]{2342,23423});sjt.batchUpdate("update emp set sal = ? where empno = ?",paramList);

?最后一sql语句也可以将sql类型告知给batchUpdate(),如下:

?

sjt.batchUpdate("update emp set sal = ? where empno = ?",paramList,new int[]{Types.INTEGER,Types.FLOAT});
?

?

九. 基于JDBC的LOB集成支持。

?

为操控LOB字段,Spring能应用需要启用LobHandler继承链。当前,Spring内置了DefaultLobHandler和OracleLobHandler实现类。通常除了Oracle数据库外,开发者可直接配置DefaultLobHandler实例即可。

如果用OracleLobHandler,还的为它配置NativeJdbcExtractor对象,以获得底层数据库的原生连接。

?

<bean id="imageDatabase" p:dataSource-ref="dataSource" p:lobHandler-ref="defaultLobHandler"/><bean id="defaultLobHandler" p:dataSource-ref="dataSource" lazy-init="true"/>
?

1. 读取

?

借用了AbstractLobStreamingResultSetExtractor回调类,这里调用了LobHandler的getBlobAsBinaryStream()方法,即将Blob转换成了二进制流。

?

@Transactional(readOnly=true)public void streamImage(final name,final OutputStream contentstream) throws DataAccessException{   getJdbcTemplate().query{        "select content from imagedb where image_name=?",new Object[]{name}, new AbstractLobStreamingResultSetExtractor(){         protected void handleNoRowFound() throws LobRetrievalFailureException{              throw new EmptyResultDataAccessException(              "image with name '"+name+"' not found in database",1);           }    public void streamData(ResultSet rs) throws SQLException,IOException{   InputStream is = lobHandler.getBlobAsBinaryStream(rs,1);   if(is!=null){      FileCopyUtils.copy(is.contentstream);  }  }     }  }}
?

2.存储

?

要使用LobHandler内置的LobCreator对象。需要启用AbstractLobCreatingPreparedStatementCallback回调类。借助LobCreator的setBlobAsBinaryStream()方法能将输入流存储到Blob字段中。setClobAsString()方法能将大文本块存储到Clob字段中。

?

@Transactionalpublic void storeImage(  final String name,   final InputStream contentstream,  final int contentLength,  final String description) throws DataAccessException{  getJdbcTemplate().execute("insert into imagedb(image_name,content,description) values (?,?,?)",new AbstractLobCreatingPreparedStatementCallback(this.lobHandler)){ protected void setValues(                PreparedStatement ps, LobCreator lobCreator       ) throws SQLException{         ps.setString(1,name);         lobCreator.setBlobAsBinaryStream(             ps,2,contentstream,contentlength);         lobCreator.setClobAsString(ps,3,description);        }        }     );}
?

十. 获得和生成主键。

?

KeyHolder kh = new GeneratedKeyHolder();int update(PreparedStatementCreator psc,KeyHolder generatedKeyHolder) throws DataAccessException;
?

?

十一. 还需要注意的。

?

1. 要合理设置Statement的fetchSize大小,即JdbcTemplate的fetchSize变量取值。(查询时,权衡时间和空间的优化)。

?

2. 大批量存储时,开发者要控制每批数据的数据量。设置batchSize的大小。

?

3. 尽量采用PreparedStatement操控数据库,而不是Statement。

?

4. 充分挖掘JdbcTemplate,NamedParameterJdbcTemplate,SimpleJdbcTemplate,SimpleJdbcInsert,SimpleJdbcCall等辅助类的功能。不要直接使用Connection对象操控。

?

?

?

?

?

?

?

热点排行