<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 3  文章 - 8  trackbacks - 0
    <2009年1月>
    28293031123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(1)

    隨筆檔案(8)

    文章檔案(1)

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    JDBC針對條件個(gè)數(shù)不定的查詢,一般的做法是直接拼裝查詢字符串,但是這樣做無法抵御注入攻擊,還是要封裝才安全,但是封裝對條件個(gè)數(shù)、類型不定,是很有困難的,最近終于找到了解決辦法:
    public class queryDAOImpl implements queryDAO {
        
    /**
         * 動(dòng)態(tài)拼裝查詢
         * 
    @param mq 封裝查詢條件的類
         * 
    @return
         * 
    @throws java.sql.SQLException
         
    */
        
    public List<Map> queryAll(MnewsQ mq) throws SQLException {
            List
    <Map> v = new Vector<Map>();
            Connection con 
    = null;
            PreparedStatement pstmt 
    = null;
            ResultSet rs 
    = null;
            Vector t 
    = new Vector();   //儲(chǔ)存查詢條件
            Vector<String> t2 = new Vector<String>();   //儲(chǔ)存查詢條件類型
            String sql = "SELECT * FROM mnews WHERE mnews.sc=0";
            
    //如果提交了查詢條件gj (int型)
            if (mq.getGj() > 0) {
                sql 
    = sql + " AND gj=?";
                t.add(mq.getGj());
                t2.add(
    "int");
            }
            
    //如果提交了查詢條件gjz4 (String型)
            if (mq.getGjz4() != null && mq.getGjz4().length() > 0) {
                sql 
    = sql + " AND gjz4=?";
                t.add(mq.getGjz4());
                t2.add(
    "String");
            }
            
    try {
                con 
    = ConnectionMannagerJNDI.getCon();    //取得數(shù)據(jù)庫連接
                pstmt = con.prepareStatement(sql);
                
    int paramNum = t.size();    //查詢條件數(shù)量
                for (int i=0; i<paramNum; i++) {
                    
    if ("int".equals(t2.get(i).toString())) {
                        pstmt.setInt(i 
    + 1 + 2, Integer.parseInt(t.get(i).toString()));
                    } 
    else if ("String".equals(t2.get(i).toString())) {
                        pstmt.setString(i 
    + 1 + 2, t.get(i).toString());
                    }
    //Date、float等類型依此類推
                }
                rs 
    = pstmt.executeQuery();
                
    //以字段名為鍵,以字段值為值,將查詢結(jié)果存入Map,再裝進(jìn)Vector
                ResultSetMetaData rsmd = rs.getMetaData();
                
    int columnNum = rsmd.getColumnCount();
                
    while (rs.next()) {
                    Map map 
    = new HashMap();
                    
    for (int i=1; i<=columnNum; i++) {
                        map.put(rsmd.getColumnName(i),rs.getObject(i));
                    }
                    v.add(map);
                }
            } 
    finally {
                ConnectionMannagerJNDI.releaseConnection(rs, pstmt, 
    null, con);
            }
            
    return v;
        }
    }


    posted on 2009-01-26 18:38 cccp21 閱讀(5454) 評論(8)  編輯  收藏

    FeedBack:
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-01-26 19:00 銀河使者
    條件是動(dòng)態(tài)的也可以用查詢參數(shù),用java.sql.PreparedStatement就可以。樓主只是做了個(gè)封裝,不過個(gè)人認(rèn)為ResultSet本身也可以根據(jù)列名來定位列,而再把每行放在一個(gè)Map中,再把結(jié)果集放在Vector中,感覺有些多此一舉。  回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-01-29 11:31 cccp21
    @銀河使者
    請注意,是條件的個(gè)數(shù)是動(dòng)態(tài)的,PreparedStatement只是讓開發(fā)者設(shè)置參數(shù)值,但是參數(shù)個(gè)數(shù)還是固定的。
    把每行放在一個(gè)Map中,再把結(jié)果集放在Vector中,是為了把JDBC與應(yīng)用分離開,我開始的時(shí)候也和你一樣,后來才聽別人指出這一點(diǎn)的。  回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-01-29 19:26 銀河使者
    @ cccp21
    不討論P(yáng)reparedStatement了,要想動(dòng)態(tài),一般也是采用你的方法,即動(dòng)態(tài)生成帶SQL參數(shù)的SQL語句,以及通過循環(huán)調(diào)用setter方法來設(shè)置參數(shù)的值,這就是動(dòng)態(tài),所有的動(dòng)態(tài)基本都是這么弄的。
    我是說第二個(gè)問題,在查詢后,又使用Map和Vector再對數(shù)據(jù)進(jìn)行封裝,是不是有些耗資源。要注意哦,如果是Web程序,可不是一個(gè)用戶或幾個(gè)用戶在訪問程序啊,要是門戶類型的系統(tǒng),可能在一分鐘之內(nèi)就會(huì)有數(shù)以萬計(jì)的用戶來訪問。這時(shí)就要建立多達(dá)數(shù)萬個(gè)Map和Vector,服務(wù)器會(huì)掛的。當(dāng)然,如果用戶在可控范圍內(nèi),這么做是沒有問題的。但是可以封裝得更高級(jí)一些,如返回的這些數(shù)據(jù)直接可以被某些用于顯示的組件使用,如使用json格式的組件。這根據(jù)具體情況而定。
    是的,使用Map和Vector可以從邏輯上將JDBC和應(yīng)用進(jìn)行分離。但個(gè)人認(rèn)為要想分離,可以從數(shù)據(jù)層及應(yīng)用邏輯層進(jìn)行分離更好。也就是有數(shù)據(jù)層提供相應(yīng)的訪問數(shù)據(jù)的方法,如獲得指定用戶的保存在數(shù)據(jù)庫中的密碼。而應(yīng)用邏輯層一般不直接訪問數(shù)據(jù)庫,可以訪問數(shù)據(jù)層中的方法進(jìn)行邏輯處理。
    雖然將數(shù)據(jù)放在Map是Vector中是更抽象了,但JDBC本身就是抽象的,在業(yè)務(wù)邏輯層直接訪問ResultSet并沒有什么不妥,因?yàn)椴还芎笈_(tái)用的是什么數(shù)據(jù)庫,從ResultSet中獲得數(shù)據(jù)的方法都是一樣的。如果非想要跨數(shù)據(jù)庫,不如直接用hibernate。  回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-01-29 19:31 銀河使者
    封裝本是面象對象最值得稱道的地方,如果封裝得太多有時(shí)得不償失。個(gè)人認(rèn)為在業(yè)務(wù)邏輯層,只要不直接涉及到SQL就可以,因?yàn)镾QL本身是和數(shù)據(jù)庫相關(guān)的,而業(yè)務(wù)邏輯層應(yīng)和數(shù)據(jù)庫不相關(guān)。但對于JDBC中的對象的使用上來說,一般也是和數(shù)據(jù)庫不相關(guān)的(至少對于象SQL Server、oracle、db2、mysql這樣的數(shù)據(jù)庫來說是這樣的)。

    結(jié)論:數(shù)據(jù)訪問層直接和數(shù)據(jù)庫相關(guān),可以涉及任何的SQL語句。業(yè)務(wù)邏輯層與數(shù)據(jù)庫無關(guān),在該層直接訪問數(shù)據(jù)層,不能直接在業(yè)務(wù)邏輯層編寫SQL語句,但可以使用JDBC的相關(guān)對象。  回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-01-31 10:57 cccp21
    @銀河使者
    我覺得這個(gè)思路不錯(cuò)是因?yàn)檫@樣可以在同一個(gè)方法中建立、關(guān)閉數(shù)據(jù)庫連接。之前曾經(jīng)在關(guān)閉數(shù)據(jù)庫連接這個(gè)問題上吃過虧。
    如果在應(yīng)用中直接訪問ResultSet,關(guān)閉數(shù)據(jù)庫連接有點(diǎn)麻煩——如果之前就關(guān)閉了數(shù)據(jù)庫連接,那么應(yīng)用在ResultSet中就訪問不到數(shù)據(jù),而不關(guān)閉的話,就要在應(yīng)用完成后關(guān)閉數(shù)據(jù)庫連接,這里就會(huì)有些混亂。你有什么好主意呢?  回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-01-31 21:05 銀河使者
    @ cccp21
    在使用ResultSet時(shí)當(dāng)然不能關(guān)閉Connection,不知道你為什么會(huì)在使用ResultSet之間關(guān)閉Connection,這個(gè)Connection是共享的?還是用的什么其他方式。為了提高效率,可以使用連接池,一般每個(gè)Connection都是線程獨(dú)享的,用完了再還給連接池。以上只針對Web應(yīng)用,如果是桌面引用,建議使用Web Service方式。

    如果想關(guān)閉ResultSet方便些,可以使用jdbc+spring的方式,也就是jdbcTemplate,這個(gè)很方便。基本原理是從連接池中獲得一個(gè)Connection,執(zhí)行一條或多條SQL語句,返回結(jié)果(這個(gè)結(jié)果也是封裝的,和你的方法差不多,但考慮了異常處理),在返回結(jié)果之前,Connection就已經(jīng)關(guān)閉了,關(guān)閉的動(dòng)作是由Spring自動(dòng)完成的。 而對于用戶來說,只是調(diào)用了JdbcTemplate的一個(gè)方法來獲得查詢結(jié)果。再也不用考慮什么Connection、ResultSet,另人討厭。不過對于小程序,用什么都行,我還是喜歡直接用jdbc,對于大一點(diǎn)的程序,尤其對Web程序,個(gè)人認(rèn)為用jdbc +Spring比較好,如果想更高級(jí)一些,還跨數(shù)據(jù)庫,可以使用hibernate+spring的方式。  回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2009-02-16 21:57 cccp21
    @銀河使者
    你是說在web頁中接受并使用ResultSet然后再在該頁中關(guān)閉ResultSet和數(shù)據(jù)庫連接?
    還是說接受并用完ResultSet后關(guān)閉ResultSet并調(diào)用另一個(gè)函數(shù)關(guān)閉連接?

    一般每個(gè)Connection都是線程獨(dú)享的——那為什么我以前看到很多取數(shù)據(jù)源連接的方法要保證之生成一個(gè)數(shù)據(jù)源對象?比如:
        private static DataSource ds = null;
        private static Object Lock = new Object();
       
    /**
     * 生成DataSource
     * @return 返回一個(gè)DataSource對象
     */
        public static DataSource gainDataSource(){
            try {
                if(ds == null){
                    synchronized(Lock){
                        if(ds == null){
                            InitialContext ctx = new InitialContext();
                            ds = (DataSource)ctx.lookup("數(shù)據(jù)源名");
                        }
                    }
                }
            } catch (NamingException e) {e.printStackTrace();}
            return ds;
        }
    這有什么好處呢?
      回復(fù)  更多評論
      
    # re: JDBC查詢動(dòng)態(tài)封裝 2010-04-14 01:00 CodingMouse
    要想重復(fù)造輪子就要造得好用一些才行:

    我也造了一個(gè)輪子,下面這樣的效果。

    代碼片段:

    // 構(gòu)建DAO工廠
    AbstractDAOFactory<AccountPOJO, Long> factory = AbstractDAOFactory.newInstance();
    // 構(gòu)建DAO實(shí)例
    IGenericsDAO<AccountPOJO, Long> dao = factory.buildGenericsDAO();

    // 按條件檢索數(shù)據(jù)并自動(dòng)映射成POJO有序集合
    List<AccountPOJO> pojos = dao.find(
    AccountPOJO.class,
    Condition.valueOf("accountid", Condition.LE, 10),
    Condition.and("birthday", Condition.ISNULL),
    Condition.or("accountname", Condition.LIKE, "鄧%"));

    // 在控制臺(tái)輸出結(jié)果
    for (AccountPOJO account : pojos) {
    System.out.println(account);
    }

    在控制臺(tái)輸出的調(diào)試信息為:

    2010-04-14 00:48:58,281 main DEBUG [com.china.codingmouse.cmsdk4j.dao.sql.generator.SQLGenerator]
    [CmSdk4j Auto SQL Generator In 2010-04-14 00:48:58.281]
    SELECT accountid, accountname, onlinecount, birthday, loginname, loginpassword, email, accountstate FROM account WHERE accountid <= ? AND birthday IS NULL OR accountname LIKE ?
    ------------------------------
    2010-04-14 00:48:58,328 main DEBUG [com.china.codingmouse.cmsdk4j.dao.converter.DataTypeConverter]
    [SQL Parameter List Information In 2010-04-14 00:48:58.328]
    No:1
    Type:java.lang.Integer
    Value:10
    ------------------------------
    2010-04-14 00:48:58,343 main DEBUG [com.china.codingmouse.cmsdk4j.dao.converter.DataTypeConverter]
    [SQL Parameter List Information In 2010-04-14 00:48:58.343]
    No:2
    Type:java.lang.String
    Value:鄧%
    ------------------------------

    在控制臺(tái)輸出的程序結(jié)果為:

    [ accountid = 1, accountname = 鄧超, onlinecount = 2203, birthday = 1984-12-26, loginname = CodingMouse, loginpassword = cmsdk4j, email = CodingMouse@gmail.com, accountstate = true ]
    [ accountid = 3, accountname = 李四, onlinecount = 932, birthday = null, loginname = LiSi, loginpassword = lisi123, email = lisi123@126.com, accountstate = false ]
    [ accountid = 7, accountname = 鄧遠(yuǎn)辰, onlinecount = 429, birthday = null, loginname = ChengCheng, loginpassword = chengchengpwd, email = chengchengdream@gmail.com, accountstate = true ]

    我也非常支持重復(fù)造輪子的行為,我上面那個(gè)泛型DAO的find方法實(shí)現(xiàn)是這樣的:

    /**
    * 獲取該類型匹配的模型有序集合。<br><br>
    *
    * @param clz 注冊返回類型。
    * @param conditions SQL條件列表。
    * @return 該類型匹配的全部模型有序集合。
    * @throws DataAccessException 數(shù)據(jù)訪問異常。
    */
    public List<T> find(Class<? extends Object> clz, Condition... conditions)
    throws DataAccessException {
    return this.findAction.find(clz, conditions);
    }

    這段時(shí)間一直也在自己琢磨動(dòng)態(tài)SQL的拼裝問題,但總是顯得對復(fù)雜SQL的支持還不夠。也許還是只有單獨(dú)封裝個(gè)高內(nèi)聚的SQL查詢條件包裝器才能達(dá)到效果。

    由于我的DAO抽象基類還是采用的短事務(wù)處理方式,所以,總感覺還是不能完全滿足需求:

    /**
    * 執(zhí)行查詢SQL命令并返回模型有序集合。<br><br>
    *
    * @param clz 注冊模型類型。
    * @param sql 要執(zhí)行的帶占位符SQL命令字串。
    * @param param SQL參數(shù)列表。
    * @return 泛型模型集合。
    * @throws DataAccessException 數(shù)據(jù)訪問異常。
    */
    public List<Object> executeQuery(
    Class<? extends Object> clz,
    String sql,
    Parameter... param)
    throws DataAccessException {

    // 數(shù)據(jù)庫連接對象
    Connection conn = null;
    // SQL命令執(zhí)行對象
    PreparedStatement ps = null;
    // 結(jié)果集對象
    ResultSet rs = null;
    // JDBC事務(wù)管理對象
    DBTransaction trans = null;

    try {
    conn = DB_CONNECTION_POOL.getConnection();
    trans = DBTransaction.begin(conn);
    ps = DataTypeConverter.java2Jdbc(
    conn.prepareStatement(sql),
    param);
    rs = ps.executeQuery();
    List<Object> modelList = new Vector<Object>();
    while(rs.next()) {
    Object model = DataTypeConverter.jdbc2Java(
    clz,
    rs);
    modelList.add(model);
    }
    trans.commit();
    return modelList;
    } catch (Throwable e) {
    trans.rollback();
    logger.error(
    this.getClass().getName(),
    Logger.DIR_INTERNAL,
    null,
    Logger.getStackTrace(e));
    throw new DataAccessException(e);
    } finally {
    this.closeAll(rs, ps, conn, trans);
    }

    }  回復(fù)  更多評論
      

    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲狠狠狠一区二区三区| 久久精品熟女亚洲av麻豆| 午夜宅男在线永久免费观看网| 亚洲色少妇熟女11p| 久久亚洲精品无码播放| 亚洲五月午夜免费在线视频 | XXX2高清在线观看免费视频| 久久精品国产精品亚洲蜜月 | 久久精品国产亚洲AV高清热| 美女黄网站人色视频免费国产| 中国国语毛片免费观看视频| 久久精品国产亚洲AV忘忧草18| 亚洲精品无码久久久| 99久久综合国产精品免费| 一区二区在线免费视频| 激情内射亚洲一区二区三区爱妻| 亚洲人成网站在线观看青青 | 亚洲高清视频免费| 免费一级毛片免费播放| 免费视频爱爱太爽了| 成人a毛片免费视频观看| 亚洲mv国产精品mv日本mv| 国产午夜亚洲精品国产成人小说| 日韩毛片免费无码无毒视频观看| a级特黄毛片免费观看| 国产精品无码亚洲精品2021| 亚洲高清在线mv| 亚洲乱码无码永久不卡在线| 可以免费观看一级毛片黄a| 全免费毛片在线播放| 亚洲免费观看视频| 免费一区二区三区在线视频 | 91在线老王精品免费播放| 又硬又粗又长又爽免费看| 亚洲AV无码国产剧情| 亚洲国产精品日韩在线观看| 精品国产综合成人亚洲区| 亚洲国产精品激情在线观看 | 亚洲成人免费电影| 久热综合在线亚洲精品| 亚洲中文字幕日产乱码高清app|