Spring JdbcTemplate共通の汎型dao 3を実現する:動的sqlを構築する.
71287 ワード
Spring JdbcTemplateは汎用の汎型dao一を実現します。
Spring JdbcTemplate共通の汎型dao二を実現します。自分の名前をNameHandlerに変換します。
Spring JdbcTemplate共通の汎型dao 3を実現する:動的sqlを構築する。
Spring JdbcTemplateは汎用的な汎型dao 4を実現します。ユニバーサルカスタムはJavaBenのRowMapperに変換して実現します。
動的sqlを構築するということは、つまりスペルsql文です.ここでは、入ってきたエンティティパラメータ、属性の価値あるスペルをsqlに入れて、nullの場合は無視します.これを実現するにはもちろん、Javaの反射機能を利用して、代表的なinsert文の構築を見てみます.
周知のように、Javaの反射は性能が低いです.また、性能の良い第三者がcglibのように実現しています.ここでは使用されていません.私の実測では両者の差は大きくない.
ただし、ここでは属性の操作方式を使っていません.つまり、Jdk反射で属性を取得したget DecleadFields()の方法を使っていません.BenInfoとPropertyDescriptorを使っています.後者の動作効率は前者よりはるかに高いです.
私の実測では、12つの属性を持つJavaBeanのダイナミックsqlを構築し、10万回の所要時間は900ミリ秒前後で、完全に受け入れられます.もちろん、ここではJavaBeanの情報をキャッシュしています.キャッシュしないと、いくつかのレベルが消費されます.
以下に完全なコードを貼り付けます.
BenInfoを取得する時にClass Utilsを書いて実現しました.中はBean情報をキャッシュしました.プロジェクトはspringを使用していますので、本来はspringから提供されたBeanUtils.get ProptyDescripter()の方法を使用しています.中には同じキャッシュがありますが、この方法は本体類の親類の属性情報も取得します.PropertyDescriptorの中では判断できません.これは直接接続によってスティッチングsqlのエラーを引き起こします.どのフィールドが現在の表を操作するために必要なのか分かりません.仕方がないです.jdk自身のIntropector類を調べたら、中には次のような方法があります.
つまり、どのカテゴリーで属性の取得を停止するかを指定することができます.これはまさに私たちが必要としています.残念なことに、springはパッケージ化されていません.springの実現を参考にして、WeakhashMapを使ってメモリのオーバーフローを防ぐために、Introptor自身のキャッシュをタイムリーにクリアします.
Spring JdbcTemplate共通の汎型dao二を実現します。自分の名前をNameHandlerに変換します。
Spring JdbcTemplate共通の汎型dao 3を実現する:動的sqlを構築する。
Spring JdbcTemplateは汎用的な汎型dao 4を実現します。ユニバーサルカスタムはJavaBenのRowMapperに変換して実現します。
動的sqlを構築するということは、つまりスペルsql文です.ここでは、入ってきたエンティティパラメータ、属性の価値あるスペルをsqlに入れて、nullの場合は無視します.これを実現するにはもちろん、Javaの反射機能を利用して、代表的なinsert文の構築を見てみます.
/**
* insert
*
* @param entity
* @param nameHandler
* @return
*/publicstaticSqlContext buildInsertSql(Object entity,NameHandler nameHandler){Class<?> clazz = entity.getClass();String tableName = nameHandler.getTableName(clazz.getSimpleName());String primaryName = nameHandler.getPrimaryName(clazz.getSimpleName());StringBuilder sql =newStringBuilder("insert into ");List<Object>params=newArrayList<Object>();
sql.append(tableName);// BeanInfo beanInfo =ClassUtils.getSelfBeanInfo(clazz);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
sql.append("(");StringBuilder args =newStringBuilder();
args.append("(");for(PropertyDescriptor pd : pds){Object value = getReadMethodValue(pd.getReadMethod(), entity);if(value ==null){continue;}
sql.append(nameHandler.getColumnName(pd.getName()));
args.append("?");params.add(value);
sql.append(",");
args.append(",");}
sql.deleteCharAt(sql.length()-1);
args.deleteCharAt(args.length()-1);
args.append(")");
sql.append(")");
sql.append(" values ");
sql.append(args);returnnewSqlContext(sql, primaryName,params);}
周知のように、Javaの反射は性能が低いです.また、性能の良い第三者がcglibのように実現しています.ここでは使用されていません.私の実測では両者の差は大きくない.
ただし、ここでは属性の操作方式を使っていません.つまり、Jdk反射で属性を取得したget DecleadFields()の方法を使っていません.BenInfoとPropertyDescriptorを使っています.後者の動作効率は前者よりはるかに高いです.
私の実測では、12つの属性を持つJavaBeanのダイナミックsqlを構築し、10万回の所要時間は900ミリ秒前後で、完全に受け入れられます.もちろん、ここではJavaBeanの情報をキャッシュしています.キャッシュしないと、いくつかのレベルが消費されます.
以下に完全なコードを貼り付けます.
/**
* sql
*
* User: liyd
* Date: 2/13/14
* Time: 10:03 AM
*/publicclassSqlUtils{/** */privatestaticfinalLogger LOG =LoggerFactory.getLogger(SqlUtils.class);/**
* insert
*
* @param entity
* @param nameHandler
* @return
*/publicstaticSqlContext buildInsertSql(Object entity,NameHandler nameHandler){Class<?> clazz = entity.getClass();String tableName = nameHandler.getTableName(clazz.getSimpleName());String primaryName = nameHandler.getPrimaryName(clazz.getSimpleName());StringBuilder sql =newStringBuilder("insert into ");List<Object>params=newArrayList<Object>();
sql.append(tableName);// BeanInfo beanInfo =ClassUtils.getSelfBeanInfo(clazz);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
sql.append("(");StringBuilder args =newStringBuilder();
args.append("(");for(PropertyDescriptor pd : pds){Object value = getReadMethodValue(pd.getReadMethod(), entity);if(value ==null){continue;}
sql.append(nameHandler.getColumnName(pd.getName()));
args.append("?");params.add(value);
sql.append(",");
args.append(",");}
sql.deleteCharAt(sql.length()-1);
args.deleteCharAt(args.length()-1);
args.append(")");
sql.append(")");
sql.append(" values ");
sql.append(args);returnnewSqlContext(sql, primaryName,params);}/**
* sql
*
* @param entity
* @param nameHandler
* @return
*/publicstaticSqlContext buildUpdateSql(Object entity,NameHandler nameHandler){Class<?> clazz = entity.getClass();StringBuilder sql =newStringBuilder();List<Object>params=newArrayList<Object>();String tableName = nameHandler.getTableName(clazz.getSimpleName());String primaryName = nameHandler.getPrimaryName(clazz.getSimpleName());// BeanInfo beanInfo =ClassUtils.getSelfBeanInfo(clazz);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
sql.append("update ");
sql.append(tableName);
sql.append(" set ");Object primaryValue =null;for(PropertyDescriptor pd : pds){Object value = getReadMethodValue(pd.getReadMethod(), entity);if(value ==null){continue;}String columnName = nameHandler.getColumnName(pd.getName());if(primaryName.equalsIgnoreCase(columnName)){
primaryValue = value;}
sql.append(columnName);
sql.append(" = ");
sql.append("?");params.add(value);
sql.append(",");}
sql.deleteCharAt(sql.length()-1);
sql.append(" where ");
sql.append(primaryName);
sql.append(" = ?");params.add(primaryValue);returnnewSqlContext(sql, primaryName,params);}/**
*
*
* @param entity
* @param nameHandler
*/publicstaticSqlContext buildQueryCondition(Object entity,NameHandler nameHandler){// BeanInfo beanInfo =ClassUtils.getSelfBeanInfo(entity.getClass());// PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(entityClass);PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();StringBuilder condition =newStringBuilder();List<Object>params=newArrayList<Object>();int count =0;for(PropertyDescriptor pd : pds){Object value = getReadMethodValue(pd.getReadMethod(), entity);if(value ==null){continue;}if(count >0){
condition.append(" and ");}
condition.append(nameHandler.getColumnName(pd.getName()));
condition.append(" = ?");params.add(value);
count++;}returnnewSqlContext(condition,null,params);}/**
*
*
* @param readMethod
* @param entity
* @return
*/privatestaticObject getReadMethodValue(Method readMethod,Object entity){if(readMethod ==null){returnnull;}try{if(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())){
readMethod.setAccessible(true);}return readMethod.invoke(entity);}catch(Exception e){
LOG.error(" ", e);thrownewMincoderException(e);}}}
BenInfoを取得する時にClass Utilsを書いて実現しました.中はBean情報をキャッシュしました.プロジェクトはspringを使用していますので、本来はspringから提供されたBeanUtils.get ProptyDescripter()の方法を使用しています.中には同じキャッシュがありますが、この方法は本体類の親類の属性情報も取得します.PropertyDescriptorの中では判断できません.これは直接接続によってスティッチングsqlのエラーを引き起こします.どのフィールドが現在の表を操作するために必要なのか分かりません.仕方がないです.jdk自身のIntropector類を調べたら、中には次のような方法があります.
publicstaticBeanInfo getBeanInfo(Class<?> beanClass,Class<?> stopClass)throwsIntrospectionException
つまり、どのカテゴリーで属性の取得を停止するかを指定することができます.これはまさに私たちが必要としています.残念なことに、springはパッケージ化されていません.springの実現を参考にして、WeakhashMapを使ってメモリのオーバーフローを防ぐために、Introptor自身のキャッシュをタイムリーにクリアします.
/**
*
*
* User: liyd
* Date: 2/12/14
* Time: 10:08 PM
*/publicclassClassUtils{/** */privatestaticfinalLogger LOG =LoggerFactory.getLogger(ClassUtils.class);/**
* Map keyed by class containing CachedIntrospectionResults.
* Needs to be a WeakHashMap with WeakReferences as values to allow
* for proper garbage collection in case of multiple class loaders.
*/privatestaticfinalMap<Class,BeanInfo> classCache =Collections.synchronizedMap(newWeakHashMap<Class,BeanInfo>());/**
* BeanInfo,
*
* @param clazz
* @return
*/publicstaticBeanInfo getSelfBeanInfo(Class<?> clazz){try{BeanInfo beanInfo;if(classCache.get(clazz)==null){
beanInfo =Introspector.getBeanInfo(clazz, clazz.getSuperclass());
classCache.put(clazz, beanInfo);// Immediately remove class from Introspector cache, to allow for proper// garbage collection on class loader shutdown - we cache it here anyway,// in a GC-friendly manner. In contrast to CachedIntrospectionResults,// Introspector does not use WeakReferences as values of its WeakHashMap!Class classToFlush = clazz;do{Introspector.flushFromCaches(classToFlush);
classToFlush = classToFlush.getSuperclass();}while(classToFlush !=null);}else{
beanInfo = classCache.get(clazz);}return beanInfo;}catch(IntrospectionException e){
LOG.error(" BeanInfo ", e);thrownewMincoderException(e);}}/**
*
*
* @param clazz
* @return
*/publicstaticObject newInstance(Class<?> clazz){try{return clazz.newInstance();}catch(Exception e){
LOG.error(" class ", e);thrownewMincoderException(e);}}}
また、構築後のsqlとパラメータ情報を保存するためにオブジェクトSql Contextを作成しました.定義は以下の通りです./**
* sql
*
* User: liyd
* Date: 2/13/14
* Time: 10:40 AM
*/publicclassSqlContext{/** sql */privateStringBuilder sql;/** */privateString primaryKey;/** , sql ? */privateList<Object>params;publicSqlContext(StringBuilder sql,String primaryKey,List<Object>params){this.sql = sql;this.primaryKey = primaryKey;this.params=params;}//getter setter }