??xml version="1.0" encoding="utf-8" standalone="yes"?>国产精品视频,久久91视频,亚洲www.http://www.aygfsteel.com/nighty/archive/2011/04/26/349050.html寒武U?/dc:creator>寒武U?/author>Tue, 26 Apr 2011 08:41:00 GMThttp://www.aygfsteel.com/nighty/archive/2011/04/26/349050.htmlhttp://www.aygfsteel.com/nighty/comments/349050.htmlhttp://www.aygfsteel.com/nighty/archive/2011/04/26/349050.html#Feedback0http://www.aygfsteel.com/nighty/comments/commentRss/349050.htmlhttp://www.aygfsteel.com/nighty/services/trackbacks/349050.html        引言Q最q又用到dbutilsQ之前一直用Map映射的方式取出select的结果再手工做{换。有写过一文章说MapHandler方式的一个缺P关于commons dbutilslg的一个小~陷分析 Q用q种方式Q在目不大的情况下Q写一些Map到JavaBean的{换代码工作量不大Q但是在数据库表q多q且表中的字D过多的情况下,q种重复的setter感觉有点烦。于是又重新思考了BeanHandler和BeanListHandler的情况,dbutils底层映射用的反射Q性能上肯定有损失Q不q在大多数项目规模不是很大的情况下,q点损失可以忽略Q带来的代码减少却是比较可观?br />         问题在哪里?先看一D官方的CZ代码Q?br />

QueryRunner run = new QueryRunner(dataSource);

// Use the BeanHandler implementation to convert the first
// ResultSet row into a Person JavaBean.
ResultSetHandler<Person> h = new BeanHandler<Person>(Person.class);

// Execute the SQL statement with one replacement parameter and
// return the results in a new Person object generated by the BeanHandler.
Person p = run.query(
    
"SELECT * FROM Person WHERE name=?", h, "John Doe");

        q里有个地方有约束,是要求CZ中的JavaBeancPerson中的字段定义要和数据库的字段定义一致。Java的命名习惯一般是骆峰写法Q例如userIdQ那么数据库中就必须定义为userIdQ而问题在于:有时候我们需要数据库中字D늚定义格式与JavaBean的命名不一P比如数据库定义ؓQuser_idQ而JavaBean则定义ؓuserId
        看源代码可能有点Ҏ_在官方的example面的最下面果然有一D关于自定义BeanProcessor的指引。摘录出来:

      BasicRowProcessor uses a BeanProcessor to convert ResultSet columns into JavaBean properties. You can subclass and override processing steps to handle datatype mapping specific to your application. The provided implementation delegates datatype conversion to the JDBC driver.
      BeanProcessor maps columns to bean properties as documented in the BeanProcessor.toBean() javadoc. Column names must match the bean's property names case insensitively. For example, the firstname column would be stored in the bean by calling its setFirstName() method. However, many database column names include characters that either can't be used or are not typically used in Java method names. You can do one of the following to map these columns to bean properties:
      1. Alias the column names in the SQL so they match the Java names: select social_sec# as socialSecurityNumber from person
      2. Subclass BeanProcessor and override the mapColumnsToProperties() method to strip out the offending characters.


      大概意思就是提供二U方式:一U就是最直接的,用as关键字把colName重命名,另一U方式就是承BeanProcessorc,重写mapColumnsToProperties()Ҏ?br />       那当然是W二U方式更加具有代表性。尝试了一下。代码如下:
    
 1public class CustomBeanProcessor extends BeanProcessor {
 2    
 3    @Override
 4    protected int[] mapColumnsToProperties(ResultSetMetaData rsmd,
 5            PropertyDescriptor[] props) throws SQLException {
 6        int cols = rsmd.getColumnCount();
 7        int columnToProperty[] = new int[cols + 1];
 8        Arrays.fill(columnToProperty, PROPERTY_NOT_FOUND);
 9
10        for (int col = 1; col <= cols; col++{
11            String columnName = rsmd.getColumnLabel(col); 
12            if (null == columnName || 0 == columnName.length()) {
13              columnName = rsmd.getColumnName(col);
14            }

15            columnName = colNameConvent(columnName); // 在这里进行数据库表columnName的特D处?/span>
16            for (int i = 0; i < props.length; i++{
17
18                if (columnName.equalsIgnoreCase(props[i].getName())) {
19                    columnToProperty[col] = i;
20                    break;
21                }

22            }

23        }

24        return columnToProperty;
25    }

26
27    /**
28     * 数据库列名重新约?br /> 29     * @param columnName
30     * @return
31     */

32    private String colNameConvent(String columnName) {
33        String[] strs = columnName.split("_");
34        String conventName = "";
35        for (int i = 0; i < strs.length; i++{
36            conventName += StringUtils.capitalize(strs[i]);
37        }

38        StringUtils.uncapitalize(conventName);
39        return conventName;
40    }

41}

        注意mapColumnsToPropertiesҎ的逻辑是从父类的方法中直接复制出来的,然后在第15行那里变了个戏法Q这里的columnName是从数据库中读出来的,自定义一个privateҎ用于转换命名Q这里你可以添加自q命名U束。例如上面就是把 user_id 转化为Java的骆峰写法:userId
       再深入一层思考,你可以在q里q行更多扩展Q以便让自己可以选择不同的命名{换方式。定义了q个Processor之后Q下面看看如何调用:
Connection conn = ConnectionManager.getInstance().getConnection();
QueryRunner qr 
= new QueryRunner();
CustomBeanProcessor convert 
= new CustomBeanProcessor();
RowProcessor rp 
= new BasicRowProcessor(convert);
BeanHandler
<User> bh = new BeanHandler<User>(User.class, rp);
User u 
= qr.query(conn, sql, bh, params);
DbUtils.close(conn);
      是不是非常灵z?如果是想q回Listl果的,把BeanHandler替换成BeanListHanderc,q可以再q一步封装这些操作,抽象到公共模块中去,让外部直接传入sql语句和Classp直接q回惌的结果,当然你得增加泛型的定义。同样D一个封装的例子Q?br />
 1protected <T> List<T> selectBeanList(Connection conn, String sql, Class<T> type,
 2            Object[] params) throws Exception {
 3        log.debug("select sql:[" + sql + "]");
 4        QueryRunner qr = new QueryRunner();
 5        CustomBeanProcessor convert = new CustomBeanProcessor();
 6        RowProcessor rp = new BasicRowProcessor(convert);
 7        ResultSetHandler<List<T>> bh = new BeanListHandler<T>(type, rp);
 8        List<T> list = qr.query(conn, sql, bh, params);
 9        return list;
10    }

        至于Z么扩展这个方法就可以实现q个逻辑得去跟源代码看它的内部实现Q用了一些JavaBean的处理和反映的技巧来做的。具体就不说?br />         ȝQcommonslg都设计得非常好,可扩展性和实用性都非常高。虽然上面D例实C转换逻辑的替换,但是仍然需要开发h员在设计数据库的时候和写JavaBean旉要严格做好规范,避免产生不必要的问题。这斚wRuby On Railsq接内部实玎ͼ动态语a的优点特别能体现Q同时强制你在设计时必须用这U方式,典型的约定优于配|原则。当Ӟ在dbutils里你愿意二种字段名都一样也无可厚非?br />        ~点QBeanProcessor是不支持兌查询的,所以上面的方式也只能局限于单表的{换,q点׃如myBatis和HibernateQ当然用q二个就引入了一些复杂性,如何权衡需要自p量,哪个用得好都一栗本人就不喜ƢmyBatis那种把SQL写到XML中的方式Q见q太复杂的SQL最l在XML里面变得面目全非Q如果是接手别h的代码,是很痛苦的,而且你无法避免只修改XML而不改JavaQ既然二者都要改Q那直接写Java里又有什么区别?单就是美。格式和注释写好一点同样很Ҏ理解Q?

]]>
关于commons dbutilslg的一个小~陷分析http://www.aygfsteel.com/nighty/archive/2011/02/12/344155.html寒武U?/dc:creator>寒武U?/author>Sat, 12 Feb 2011 09:33:00 GMThttp://www.aygfsteel.com/nighty/archive/2011/02/12/344155.htmlhttp://www.aygfsteel.com/nighty/comments/344155.htmlhttp://www.aygfsteel.com/nighty/archive/2011/02/12/344155.html#Feedback6http://www.aygfsteel.com/nighty/comments/commentRss/344155.htmlhttp://www.aygfsteel.com/nighty/services/trackbacks/344155.html         鉴于前面没有旉了解Q就都粗略用了上面那种_暴的map.get("")来处理,最好的情况是让dbutilslg能自动识别到ascd的列名。于是有IZ׃门看了看它的源代码,发现最主要的一D代码如下:
 1public Map<String, Object> toMap(ResultSet rs) throws SQLException {
 2        Map<String, Object> result = new CaseInsensitiveHashMap();
 3        ResultSetMetaData rsmd = rs.getMetaData();
 4        int cols = rsmd.getColumnCount();
 5
 6        for (int i = 1; i <= cols; i++{
 7            result.put(rsmd.getColumnName(i), rs.getObject(i));
 8        }

 9
10        return result;
11    }
        CaseInsensitiveHashMap是dbutils自定义的一个MapQ忽略键大小写的K-V字典Q但是key使用的是ResultSetMetaData.getColumnName()Q我想问题大概出在这里,于是认真Mjava的api文档Q开发做久了Ҏ遗忘基础Q,果然Q原?strong>getColumnName()是:获取指定列的名称Q?/span>而as关键字之后,使列名称变成用于昄的意义,q个时候应该?strong>getColumnLabel()Q?span style="color: #339966">获取用于打印输出和显C的指定列的标题。徏议标题通常?SQL AS 子句来指定。如果未指定 SQL ASQ则?getColumnLabel q回的值将?getColumnName Ҏq回的值相?/span>。自己手动试验了一下,果然如所料,问题出在这里?br />         所以呢Q如果想要dbutils在自动{换Map及MapList时能识别聚合函数的列名,那么最好的做法是重蝲q种方式Q懒一点的Q你干脆修改上面那D代码,让它判断是否使用了as关键字。个人暂时搞不清楚官方ؓ什么没有考虑q一步,有时间再思考一下!

]]>
վ֩ģ壺 | | | Դ| | | | | ʵ| Ϫ| | | | | | ͨ| ʩ| | ƽ| | ߺ| ޻| | | SHOW| ׸| | | | | ֹ| ζ| ɽ| ڻ| | | | ݳ| ϵ| ƽ| Ļ|