多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > JDBC的進化3

JDBC的進化3

來源:程序員人生   發布時間:2015-03-12 08:46:05 閱讀次數:2491次

這次進化完成后,JDBC的進化就需要設置1個savepoint了,然后提交1下,提交到我們的腦袋硬盤中。
上1次說到了利用Statement對象來發送sql語句到數據庫。但是這樣的話,會暴露出兩個問題。
那末問題來了!!!
問題1:
在履行executeUpdate(String sql)和executeQuery(String sql)方法時,我們需要拼寫sql字符串,就像下面這樣:

String sql = "insert into customers values(21, 'yushen1', 'yushem@123.com', '1998⑶⑵', null)";

String sql = "SELECT FlowId flowId, type, IDCard idCard, ExamCard examCard, StudentName studentName, location, Grade grade FROM examstudent WHERE ExamCard = '" + examCard + "'";
感遭到點甚么了沒有???麻煩!!是否是,假設說我要修改20個字段,我是否是得拼好長1個字符串?這就是問題1。

問題2:
看下面的代碼:

String user = "' OR 1 = 1--'"; SELECT * FROM user_table WHERE user = '"+user+"';

大家知道產生了甚么?我把整張表的信息都獲得了,包括密碼(你的銀行賬戶密碼被我知道了),太可怕了! 這就是SQL注入問題,也是我要說的第2個問題。
告知你個好消息,有1個1勞永逸的辦法可以同時解決這兩個問題,同時對批量處理效力會大大的提升,這個辦法就是PreparedStatement接口。簡直是好處多多啊。來我們來學習這個辦法。還是老模樣,從具體到通用。

Solution:
PreparedStatement接口:它是Statement接口的子接口。
看看API中對它的描寫:

“An object that represents a precompiled SQL statement.”

“A SQL statement is precompiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times. “

先看第1句:代表1個預編譯的SQL命令對象
再看第2句:1個SQL命令是預編譯的和存儲在1個PreparedStatement對象中。這個對象隨后能高效的履行這個命令屢次。
觸及到1個詞:預編譯,我在下面結合代碼來講
先來1個具體的例子:

@Test public void testPrepareSelect(){ String sql = "SELECT * FROM users WHERE id = ?;"; // get connection Connection conn = null; // get PreparedStatement's object PreparedStatement ps = null; // execute the sql ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); // set the ? ps.setInt(1, 1); // execute the sql rs = ps.executeQuery(); // get the rs if(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String address = rs.getString("address"); String phone = rs.getString("phone"); User user = new User(id, name, address, phone); System.out.println(user); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(rs, ps, conn); } }

是否是發現個問號,然后給這個問號設置值?問:這個問號是甚么東東啊?答:這個問號相當于1個占位符,我就把這個位置占住了。要不為何叫預編譯。
再來1個通用的:

/** * PreparedStatement: through the reflect and generic and PreparedStatement * @param sql * @param clazz * @param args * @return */ public <T> T getPrepareSelect(String sql,Class<T> clazz, Object ... args){ T t = null; // get the connection Connection conn = null; // get the PreparedStatement's object PreparedStatement ps = null; // execute the ps ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); // set values for ps for(int i = 0; i < args.length; i++){ ps.setObject(i+1, args[i]); } rs = ps.executeQuery(); // get the ResultSetMetaData's object ResultSetMetaData rsmd = rs.getMetaData(); // get the columnNum int columnNum = rsmd.getColumnCount(); // read the data of rs, and packaging an object if(rs.next()){ t = clazz.newInstance(); for(int i = 1; i <= columnNum; i++){ // get the columnName and columnValue of the special row special column String columnName = rsmd.getColumnLabel(i); Object columnValue = rs.getObject(columnName); // through the generic put the columnValue to the Class' field Field userField = clazz.getDeclaredField(columnName); userField.setAccessible(true); userField.set(t, columnValue); } } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(rs, ps, conn); } return t; }

我靠,你這寫的甚么東西啊? 我就問你你還記得反射和泛型嗎?
反射:
我們在編譯時不能肯定創建甚么對象,只能在運行的時候創建,而運行時怎樣創建呢?昨天還是前天的博客,我提到過1個思惟分散:描寫數據的數據叫元數據,描寫注解的注解叫元注解,描寫類的類叫??? 汗,我也不知道該叫甚么了,但是的確存在1個類來描寫1個已編譯(已加載?我不肯定,回頭看看)的類。而通過這個類我們可以取得它描寫類的任何信息,包括創建對象和給屬性設置值。我后面會總結1篇反射。現在該知道了吧?

由于要寫成通用的,
1.我們不能肯定返回值是甚么類型的對象,我們使用了泛型。
2.對象的屬性個數,甚么類型你一樣不知道,我們使用反射,和多態參數來解決這個問題。

這里出現了個這東西:ResultSetMetaData 它是用來描寫ResultSet的,我們知道ResultSet存的是1張數據表,而ResultSetMetaData就是用來描寫這張表的,包括他有幾列,每列是甚么。

現在讀我這個程序是否是感覺好多了? 也不過如此么!!!

從具體到1般,我們上面寫的僅僅是查詢1條記錄的。
來,再來1個查詢多條記錄的通用的方法:

/** * PreparedStatement : getAll * @param sql * @param clazz * @param args * @return */ public <T> List<T> getAll(String sql, Class<T> clazz, Object ... args){ List<T> list = new ArrayList<T>(); // get connection Connection conn = null; // get PreparedStatement PreparedStatement ps = null; // execute the sql ResultSet rs = null; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); // set the ps for(int i = 0; i < args.length; i++){ ps.setObject(i+1, args[i]); } rs = ps.executeQuery(); // get the columnNum ResultSetMetaData rsmd = rs.getMetaData(); int columnNum = rsmd.getColumnCount(); // read the rs and write to an object while(rs.next()){ T t = clazz.newInstance(); for(int i = 1; i <= columnNum; i++){ // read String columnName = rsmd.getColumnLabel(i); Object columnVal = rs.getObject(columnName); // write // through the field(reflect) //Field field = clazz.getDeclaredField(columnName); //field.setAccessible(true); //field.set(t, columnVal); // through the method(reflect) PropertyUtils.setProperty(t, columnName, columnVal); } list.add(t); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(rs, ps, conn); } return list; }

來了,相比于上1個來講,這個其實很簡單了,只不過是增加了1個List<T>集合來寄存對象,獲得連接和關閉的話,你看看我的進化1就明白了。還有就是使用了Apache提供的工具類,但是我個人還是希望你能自己寫寫,以后實際項目使用的時候再用工具類會好1點。

這里來講預編譯
預編譯指令唆使了在程序正式編譯前就由編譯器進行的操作,我認為這個編譯固然不是Java中的編譯了,而是將它放到了數據庫中,在數據庫中進行預編譯,你仔細想一想是否是這樣?這個該說說內存了,數據庫在內存中會有庫池,->數據緩沖區,->日志緩沖區,1條簡單的Select語句發送到數據庫要經歷1個硬解析的進程,硬解析->檢查->履行計劃,然后到庫池,再到數據庫緩沖池。對普通的Statement語句發送的Sql語句,它每次都要履行這個進程。而PreparedStatement則不同,它被編譯過的語句會被緩存下來,下次調用有相同的預編譯語句就不會重新進行編譯(即上面那個進程),將參數傳入就會履行。

通過上面1段話:有產生了1個新的東西:
批量處理:
3個方法:addBatch()1個裝載的進程,executeBatch()履行的進程,clearBatch()清空緩沖的數據。
具體的履行進程和上面的類似,我會在效力的比較中給出具體的例子。

這些說完了,我們來測試測試他和Statement的效力,不然你們還以為我騙你們,說PreparedStatement效力高。
我同時向數據庫中插入100000條記錄為例
statement:

@Test public void testStatement() {// 260111 long start = System.currentTimeMillis(); Connection conn = null; Statement statm = null; try { conn = JDBCUtils.getConnection(); statm = conn.createStatement(); for (int i = 0; i < 100000; i++) { String sql = "insert into emp1 values(" + i + ", 'emp" + i + "')"; statm.executeUpdate(sql); } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(statm, conn); } long end = System.currentTimeMillis(); System.out.println("the time is :" + (end - start)); }

履行時間:
260111ms
PreparedStatement:

@Test public void testPreparedStatment() {// 141991 long start = System.currentTimeMillis(); // get connection Connection conn = null; // get PreparedStatement's object PreparedStatement ps = null; try { conn = JDBCUtils.getConnection(); String sql = "insert into emp1 values(?, ?)"; ps = conn.prepareStatement(sql); for (int i = 0; i < 100000; i++) { ps.setInt(1, i + 1); ps.setString(2, "emp" + i); ps.executeUpdate(); } } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(null, ps, conn); } long end = System.currentTimeMillis(); System.out.println("the time is :" + (end - start)); }

141991ms 快了接近1倍
再看看批量處理:
Statement:

@Test public void testStatement2() {// 271924 long start = System.currentTimeMillis(); Connection conn = null; Statement statm = null; try { conn = JDBCUtils.getConnection(); statm = conn.createStatement(); for (int i = 0; i < 100000; i++) { String sql = "insert into emp1 values(" + i + ", 'emp" + i + "')"; statm.addBatch(sql); if ((i % 250) == 0) { statm.executeBatch(); statm.clearBatch(); } } } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(statm, conn); } long end = System.currentTimeMillis(); System.out.println("the time is :" + (end - start)); }

271924ms 好慢

PreparedStatement:
接下來就是見證奇跡的時刻!!!

@Test public void testPreparedStatement2() {// 3230 long start = System.currentTimeMillis(); // get connection Connection conn = null; // get PreparedStatement's object PreparedStatement ps = null; try { conn = JDBCUtils.getConnection(); String sql = "insert into emp1 values(?, ?)"; ps = conn.prepareStatement(sql); for (int i = 0; i < 100000; i++) { ps.setInt(1, i + 1); ps.setString(2, "emp" + i); ps.addBatch(); if ((i % 250) == 0) { ps.executeBatch(); ps.clearBatch(); } } } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(null, ps, conn); } long end = System.currentTimeMillis(); System.out.println("the time is :" + (end - start)); }

3230ms 甚么???這么快!!!
我就甚么也不多說了,繼續吧!!

我們接下來講事務,我還是分開寫吧,這個太長了,不好瀏覽。沒耐心的觀眾已坐不住了!!

補充1點:大數據處理,這里只提供代碼示例,可以參考著去研究研究
大數據的讀取:

@Test public void get(){ String sql = "select * from customers where id = ?"; Connection conn = null; PreparedStatement ps = null; InputStream is = null; ResultSet rs = null; OutputStream os = null; try { // get connection conn = JDBCUtils.getConnection(); // get PreparedStatement's object ps = conn.prepareStatement(sql); ps.setInt(1, 22); // execute the ps rs = ps.executeQuery(); while(rs.next()){ int id = rs.getInt(1); String name = rs.getString(2); String email = rs.getString(3); Date birth = rs.getDate(4); Customer customer = new Customer(id, name, email, birth); System.out.println(customer); Blob blob = rs.getBlob(5); is = blob.getBinaryStream(); os = new FileOutputStream("1.jpg"); byte[] b = new byte[1024]; int len = 0; while((len = is.read(b)) != -1){ os.write(b, 0, len); } } } catch (Exception e) { e.printStackTrace(); } finally { if(os != null){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if(is != null){ try { is.close(); } catch (IOException e) { e.printStackTrace(); } } JDBCUtils.close(rs, ps, conn); } }

大數據的寫入:

public int insertBlob() { String sql = "insert into customers values(?, ?, ?, ?, ?)"; // get connection Connection conn = null; // get PreparedStatement's object PreparedStatement ps = null; // execute ps int rows = 0; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); ps.setInt(1, 22); ps.setString(2, "lisi"); ps.setString(3, "lisi@abc.com"); ps.setDate(4,new Date(new java.util.Date().getTime())); ps.setBlob(5, new FileInputStream("089.jpg")); rows = ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.close(ps, conn); } return rows; }
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 日韩精品久久一区二区三区 | 日本在线无 | 日韩18| 国产一区二区三区精品视频 | 香港黄页精品视频在线 | 日本高清www午夜视频 | 亚洲第一国产 | 欧美视频一区 | 中文字幕激情 | 插久久 | 岛国福利视频 | 欧美日韩国产另类一区二区三区 | 国产精品视频播放 | 最近的最新的中文字幕在线 | 亚洲 日本 欧美 日韩精品 | 毛片久久| 92看片淫黄大片看国产片 | 国产人成精品免费视频 | 亚洲欧美日韩成人 | 在线a人片免费观看不卡 | 在线亚洲欧国产精品专区 | 久久综合一区二区三区 | 亚洲欧美精品天堂久久综合一区 | 波多野结衣精品一区二区三区 | 国产免费一级片 | 好大好湿好硬顶到了好爽在 | 日本成人一区 | 国产91一区二区在线播放不卡 | 精品久久久久久中文字幕欧美 | 麻豆毛片 | 成年人在线视频免费观看 | 暴力欧美娇小 videos | 欧美性猛交xxxx乱大交be | 欧美一区二区三区综合色视频 | 亚洲精品网址 | 欧美最猛黑人xxxx黑人猛交69 | 欧美性性性性性色大片免费的 | 午夜在线视频国产极品片 | 亚洲免费在线播放 | 欧美亚洲桃花综合 | 黄色录像大片毛片aa |