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

SpringJdbcTemplate操作Clob跟Blob的通用类封装

2013-07-09 
SpringJdbcTemplate操作Clob和Blob的通用类封装? ? ? ? 项目中使用SpringJdbcTemplate来操作数据库,简单方

SpringJdbcTemplate操作Clob和Blob的通用类封装

? ? ? ? 项目中使用SpringJdbcTemplate来操作数据库,简单方便实用(根据项目需求选择技术),目前用到Oracle10g数据库,由于其操作大文本使用Clob类型,故而研究了下jdbctemplate对clob和Blob的操作。 ?

? ? ? ?jdbctemplate对clob和blob的操作使用起来也很简单,网友提供很多实例和代码。例如:

http://hi.baidu.com/sileader/item/0b3335f512378fb731c19999

主要是利用jdbctemplate提供的两个类来操作:LobCreator和LobHandler,具体使用方法可参考该链接。

但是如果某个Bean属性字段太多的话,代码写起来将会很麻烦。是否可以提供一种通用的方法,让每个业务方法操作数据库Clob和Blob时候也可以像操作其他基本数据类型一样,一句代码就完成。例如插入和修改Bean:

public <T> void saveOrUpdate(String sql, T bean) {namedParameterJdbcTemplate.update(sql, new BeanPropertySqlParameterSource(bean));}

?经过一些尝试和摸索,我使用反射和注解,写了一个通用类,可以操作查询、修改、添加,满足了项目中的需求。

1、定义了一个注解类,用于bean中属性上,主要是提供属性的数据库字段名以及其数据库类型。

/** * @description  * @author aokunsang * @date 2013-7-4 */@Target({ElementType.FIELD,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME) @Documented@Inheritedpublic @interface PmcColumn {/** * 数据库中字段类型 * @return */int type();/** * 数据库中字段名 * @return */String columnName();/** * 查询时候是否忽略 * @return */boolean ignore() default false;}

?2、定义一个反射的工具类,反射操作属性字段的setter和getter方法注入和获取属性值、

/** * @description 对bean的反射操作 * @author aokunsang * @date 2013-7-3 */public class BeanUtils {  /**      * @param obj 操作的对象      * @param att 操作的属性      * */public static Object getter(Object obj, String att) {         try {             Method method = obj.getClass().getMethod("get" + StringUtils.capitalize(att));             return method.invoke(obj);         } catch (Exception e) {             e.printStackTrace();         }return null;     }    /**     * 注入数据     * @param obj   类的实例     * @param att   属性名     * @param value 注入数据内容     * @param type  返回的数据类型     *      */public static void setter(Object obj, String att, Object value, Class<?> type) {         try {             Method method = obj.getClass().getMethod("set" + StringUtils.capitalize(att), type);             method.invoke(obj, value);         } catch (Exception e) {             e.printStackTrace();         }    }/** * 获取某个属性字段的ignore信息 * @param field * @return */public static boolean getPmcColumnIgnore(Field field){Annotation annotation = field.getAnnotation(PmcColumn.class);boolean ignore = false;if(annotation!=null){ignore = ((PmcColumn)annotation).ignore();}return ignore;}/** * 获取某个属性的Type信息 * @param field * @return */public static int getPmcColumnType(Field field){Annotation annotation = field.getAnnotation(PmcColumn.class);int type = Types.VARCHAR;if(annotation!=null){type = ((PmcColumn)annotation).type();}return type;}/** * 获取某个属性的数据库中字段名 * @param field * @return */public static String getPmcColumnName(Field field){Annotation annotation = field.getAnnotation(PmcColumn.class);String columnName = "";if(annotation!=null){columnName = ((PmcColumn)annotation).columnName();}return columnName;}}

?3、定义一个对sql语句的转换类,sql语句进行转变,变成需要的字符串。

如:insert into t1 values(:a,:b,:c) ?----> ? insert into t1(A,B,C) values(?,?,?);

或者update t1 set A=:a,B=:b where C=:c ? ----> update t1 set A=?,B=? where C=?

/** * @description 工具类 * @author aokunsang * @date 2013-1-9 */public class Util {/** * 分割插入、修改的sql语句 * @param sql * @param columnMaps   <属性名,数据库中字段名> * @return */public static Map<String,List<String>> spQuerysql(String sql,Map<String,String> columnMaps){if(StringUtils.isEmpty(sql)) return null;String _sql = sql + " ";String key = _sql.replaceAll(":(.+?),\\s*", "?,").replaceAll(":(.+?)[)]\\s*", "?)").replaceAll(":(.+?)\\s+", "? ");Map<String,List<String>> result = new HashMap<String, List<String>>();List<String> fieldList = new LinkedList<String>();Pattern pattern = Pattern.compile(":(.+?)[)|,|\\s*]");Matcher matcher = pattern.matcher(_sql);StringBuffer insertString = new StringBuffer();while(matcher.find()){String value = matcher.group(1);fieldList.add(value);insertString.append(columnMaps.get(value)+ ",");}if(fieldList.isEmpty() || key.equals(_sql)) return null;StringBuffer key_sb = new StringBuffer(key);if(!key.trim().matches("insert\\s*into\\s*[\\w|_]+?\\(.*?\\)\\s*values.*") && !key.trim().contains("update")){  //判断insert语句是否有数据库字段,比如:insert into t1(ID,NAME) key_sb.insert(key_sb.indexOf("values")-1, "("+insertString.substring(0,insertString.length()-1)+")");}result.put(key_sb.toString(), fieldList);return result;}}

?4、定义一个对clob和blob的通用类[[关键类],也可以说是已经存在的Dao类的扩展类。

/** * @description 增强版数据库操作类[添加对clob和blob的部分操作] * @author aokunsang * @date 2013-7-4 */public class StGenericDao extends GenericDao {/** * 查询单条记录 * @param <T> * @param sql * @param clazz * @param args * @return */public <T> T _find(String sql,final Class<T> clazz,Object... args){printSqlInfo(sql,args!=null ? Arrays.toString(args) : "");try {return jdbcTemplate.queryForObject(sql,new RowMapper<T>(){@Overridepublic T mapRow(ResultSet rs, int rownum) throws SQLException {    T bean = null;try {bean = clazz.newInstance();Field[] fields = clazz.getDeclaredFields();   //获取所有属性for(Field field : fields){if(field.getAnnotation(PmcColumn.class)==null) continue;if(BeanUtils.getPmcColumnIgnore(field)) continue;switch(BeanUtils.getPmcColumnType(field)) {  //如果Bean中增加了类型,需要在这里以及下面方法中添加casecase Types.CLOB:{BeanUtils.setter(bean, field.getName(), lobHandler.getClobAsString(rs, BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.BLOB:{BeanUtils.setter(bean, field.getName(), lobHandler.getBlobAsBytes(rs, BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.TIMESTAMP:{BeanUtils.setter(bean, field.getName(),rs.getTimestamp(BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.DATE:{BeanUtils.setter(bean, field.getName(),rs.getDate(BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.INTEGER:{BeanUtils.setter(bean, field.getName(),rs.getInt(BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.VARCHAR:{BeanUtils.setter(bean, field.getName(),rs.getString(BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.NUMERIC:{ BeanUtils.setter(bean, field.getName(),rs.getLong(BeanUtils.getPmcColumnName(field)), field.getType());break;}case Types.FLOAT:{BeanUtils.setter(bean, field.getName(),rs.getFloat(BeanUtils.getPmcColumnName(field)), field.getType());break;}}}} catch (Exception e) {e.printStackTrace();}return bean;}},args);} catch (EmptyResultDataAccessException e) {return null;} catch (DataAccessException e) {throw new DaoRuntimeException("----------数据库错误saveOrUpdate()------", e);}}/** * 添加或修改某条记录 * @param <T> * @param sql * @param bean */public <T> void _saveOrUpdate(String sql,final T bean){final Map<String,Integer> columnTypes = new HashMap<String,Integer>();Map<String,String> columnMaps = new HashMap<String,String>();Field[] fields = bean.getClass().getDeclaredFields();   //获取所有属性for(Field field : fields){columnTypes.put(field.getName(), BeanUtils.getPmcColumnType(field));columnMaps.put(field.getName(), BeanUtils.getPmcColumnName(field));}final Map<String,List<String>> resultMap = Util.spQuerysql(sql,columnMaps);if(resultMap==null) throw new PmcRuntimeException(String.format("你提供的SQL语句有问题,请详细检查再次尝试运行。SQL:[s%]",sql));Object[] validSql = resultMap.keySet().toArray();   //改变后的Sql语句printSqlInfo(sql+"<<----->>"+validSql[0].toString(),"");   //打印改变前后的sql语句final List<String> fieldList = resultMap.get(validSql[0]);   //对应插入的bean字段jdbcTemplate.execute(validSql[0].toString(),new AbstractLobCreatingPreparedStatementCallback(this.lobHandler) {@Overrideprotected void setValues(PreparedStatement ps, LobCreator lobCreater)throws SQLException, DataAccessException {for(int i=0,length=fieldList.size();i<length;i++){String filedValue = fieldList.get(i);switch (columnTypes.get(filedValue)) {case Types.CLOB:{lobCreater.setClobAsString(ps, i+1, BeanUtils.getter(bean, filedValue)==null ? null : BeanUtils.getter(bean, filedValue).toString());break;}case Types.BLOB:{lobCreater.setBlobAsBytes(ps, i+1, BeanUtils.getter(bean, filedValue)==null ? null : (byte[])BeanUtils.getter(bean, filedValue));break;}case Types.TIMESTAMP:{ps.setTimestamp(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Timestamp)BeanUtils.getter(bean, filedValue));break;}case Types.DATE:{ps.setDate(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Date)BeanUtils.getter(bean, filedValue));break;}case Types.INTEGER:{ps.setInt(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Integer)BeanUtils.getter(bean, filedValue));break;}case Types.VARCHAR:{ps.setString(i+1, BeanUtils.getter(bean, filedValue)==null ? null : BeanUtils.getter(bean, filedValue).toString());break;}case Types.NUMERIC:{ps.setLong(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Long)BeanUtils.getter(bean, filedValue));break;}case Types.FLOAT:{ps.setFloat(i+1, BeanUtils.getter(bean, filedValue)==null ? null : (Float)BeanUtils.getter(bean, filedValue));break;}}}}});}}

?5、对JDBC的配置文件修改,添加lobHandler类,并且注入到StGenericDao中。

  <!-- JDBC上传附件时候使用 --> <bean id="lobHandler" />          <!-- 默认数据源[showsql-是否显示sql语句] 如果需要操作clob和blob,则声明StGenericDao-->     <bean id="genericDao" ref="dataSource"></property>     <property name="showsql" value="true"></property>     <property name="lobHandler" ref="lobHandler"></property>     </bean>

?如何使用以上方法,需要注意以下2个方面:

其一:如果某个Bean类中包括Clob和Blob字段,那么该Bean的字段类型需要加入PmcColumn注解。如:

/** * @description  * @author aokunsang * @date 2013-7-4 */public class TDemo implements Serializable{@PmcColumn(columnName="ID",type=Types.NUMERIC)private Long id;@PmcColumn(columnName="NAME",type=Types.VARCHAR)private String name;@PmcColumn(columnName="DEMO_PIC",type=Types.BLOB)private byte[] pic;       //BLOB类型,属性字段类型为byte[]@PmcColumn(columnName="CONTENT",type=Types.CLOB)private String content;   //CLOB类型,属性字段类型为Stringsetter and  getter...}

?其二:Service业务方法中注入StGenericdao类,使用其方法即可;当然如果你操作的Bean类没有Clob和Blob类型字段就无需写PmcColumn注解,注入IGenericDao接口也可以。

/** * @description  * @author aokunsang * @date 2013-7-4 */@Servicepublic class DemoServiceImpl implements IDemoService{@Resource(name="genericDao")private StGenericDao genericDao;public void saveDemo(TDemo demo){genericDao._saveOrUpdate("insert into tdemo values(:id,:name,:pic,:content)",demo);}}

热点排行