JDBC不僅可執行查詢,也可以執行DDL,DML等SQL語句,從而允許通過JDBC最大限度地控制數據庫。
使用executeUpdate或者使用executeLargeUpdate方法來執行DDL和DML語句:
編寫程序,通過executeUpdate方法在mysql當前數據庫下創建一個數據庫表 示范:
public class JDBC { String driver; String url; String user; String password; //查詢該數據庫是否有對應的表,有則返回ture,沒有返回false public boolean tableIsExists(String tableName){ try{ Connection conn =DriverManager.getConnection(url,user,password); Statement statement =conn.createStatement(); String sql = "select table_name from information_schema.tables where table_schema='test'"; ResultSet resultSet = statement.executeQuery(sql); while(resultSet.next()){ String queryTableName = resultSet.getString(1); System.out.println(queryTableName); if(queryTableName.equals("tb_test")){ return true; } } }catch(Exception e){} return false; } public void createTableJDBC(String tableName){ try{ Connection conn =DriverManager.getConnection(url,user,password); Statement statement =conn.createStatement(); if(!tableIsExists(tableName)){ System.out.println("當前數據庫沒有"+tableName+"表格,將創建"+tableName+"數據庫表"); String sql = "create table "+tableName+"(" + "test_id int auto_increment primary key," + "test_name varchar(255)," + "test_desc text)"; int result = statement.executeUpdate(sql); }else{ System.out.println("當前數據庫有"+tableName+"表格,不創建"+tableName+"數據庫表"); } }catch(Exception e){} } public static void main(String[] args) { // TODO Auto-generated method stub JDBC jdbc = new JDBC(); jdbc.initParam("mysql.properties"); jdbc.createTableJDBC("tb_test"); } }
第一次運行結果如下:
tb_adminuser
tb_user
當前數據庫沒有tb_test表格,將創建tb_test數據庫表
第二此運行結果如下(假如沒有操作mysql數據的話):
tb_adminuser
tb_test
當前數據庫有tb_test表格,不創建tb_test數據庫表
編寫程序,對上述新增表添加數據:
public class JDBC { String driver; String url; String user; String password; public void initParam(String paramFile){ try{ Properties props = new Properties(); props.load(new FileInputStream(paramFile)); driver = props.getProperty("driver"); url = props.getProperty("Url"); user = props.getProperty("user"); password = props.getProperty("password"); }catch(Exception e){} } public void addData(String table,String sql){ try{ Connection conn =DriverManager.getConnection(url,user,password); Statement statement =conn.createStatement(); int resultRow = statement.executeUpdate(sql); System.out.println("對"+table+"表添加了1條數據,該表受影響行數為"+resultRow); }catch(Exception e){} } public static void main(String[] args) { // TODO Auto-generated method stub JDBC jdbc = new JDBC(); jdbc.initParam("mysql.properties"); String table = "tb_test"; String sql = "insert into "+table+"(test_name,test_desc) values('hjl','0');"; jdbc.addData(table, sql); } }
運行的效果為:
對tb_test表添加了1條數據,該表受影響行數為1
通過兩個代碼進行測試可以得知,使用executeUpdate(String sql) 是可以對數據庫進行DML語句與DDL語句操作的,不同的是,DDL語句因為不是對表中內容進行操作,因此返回的值為0;而DML語句是對表格內容進行操作的,因此返回影響表格內容的行數。
使用execute方法執行SQL語句:
Statement的execute()方法幾乎可以執行任何SQL語句,但它執行SQL語句時比較麻煩,通常都是使用executeQuery()方法或者executeUpdate()方法來執行SQL語句;只有不清楚SQL語句的類型,為了保證不出錯,最好是用execute()方法來執行該SQL語句。
使用execute()的返回值是boolean,那么如何來獲取執行查詢語句獲得的ResultSet對象,以及如何獲取執行DDL或者DML語句獲得的int數值呢?針對這種情況,Statement提供了如下兩個方法:
1.getResultSet(): 該方法返回Statement執行查詢語句所返回的ResultSet對象。
2. getUpdateCount():該方法返回statementDDL,DML語句所影響的記錄行數。
下面程序示范了使用Statment的execute()方法來執行任意的SQL語句。
public class JDBC { //使用execute方法進行對表查詢 public void queryByExecuteMethod(String table){ try{ String sql = "select * from "+table; boolean b = statement.execute(sql); if(b){ System.out.println("execute方法返回"+b); ResultSet result = statement.getResultSet(); int count = 0; while(result.next()){ count++; } System.out.println("一共查詢了"+count+"條記錄"); }else{System.out.println("execute方法返回"+b);} }catch(Exception e){} } //使用execute方法進行DML刪除該表的內容 public void deleteDataByExecuteMethod(String table){ try{ String sql = "delete from "+table; boolean b = statement.execute(sql); if(!b){ System.out.println("execute方法返回"+b); System.out.println(table+"受影響行數為:"+statement.getUpdateCount()); }else{System.out.println("execute方法返回"+b);} }catch(Exception e){} } //使用execute方法進行DDL刪除該表 public void dropTableByExecuteMethod(String table){ try{ String sql = "drop table "+table; boolean b = statement.execute(sql); if(!b){ System.out.println("execute方法返回"+b); System.out.println(table+"受影響行數為:"+statement.getUpdateCount()); }else{System.out.println("execute方法返回"+b);} }catch(Exception e){} } Connection conn = null; Statement statement = null; public JDBC(String paramFile){ try{ Properties props = new Properties(); props.load(new FileInputStream(paramFile)); String driver = props.getProperty("driver"); String url = props.getProperty("Url"); String user = props.getProperty("user"); String password = props.getProperty("password"); conn =DriverManager.getConnection(url,user,password); statement =conn.createStatement(); }catch(Exception e){} } public static void main(String[] args) { // TODO Auto-generated method stub String table = "tb_test"; JDBC jdbc_2 = new JDBC("mysql.properties"); jdbc_2.queryByExecuteMethod(table); jdbc_2.deleteDataByExecuteMethod(table); jdbc_2.dropTableByExecuteMethod(table); } }
上述程序中,使用了execute()方法執行了三種SQL語句,分別是查詢語句,DML語句與DDL語句,其中查詢語句返回的是True值,根據true值從Statement對象中獲取ResultSet對象,而根據false值,從Statement對象中獲取getUpdateCount()方法的值,其運行效果為:
execute方法返回true 一共查詢了2條記錄 execute方法返回false tb_test受影響行數為:2 execute方法返回false tb_test受影響行數為:0
使用PreparedStatement執行SQL語句:
如果在程序中有經常反復執行一條結構相似的SQL語句,例如下面兩句:
insert into tb_test values(null,'張三',1); insert into tb_test values(null,'李四',2);
對於上述兩句,它們的結構基本相似,值時執行插入時的值不同而已。對於這種情況,可以使用帶占位符(?)參數的SQL語句來代替它們,即:
insert into tb_test values(null,?,?)
但Statement執行的SQL語句是不允許使用問號占位符參數,而且這個問號占位符參數必須獲得值后才可以執行。為了滿足這種情況,JDBC提供了PreparedStatement接口,該接口是Statement接口的子接口,它可以預編譯SQL語句,預編譯后的SQL語句被存儲到PreparedStatement對象中,然后可以使用該對象對此高效地執行該語句。
PreparedStatement接口也實現了Statement接口的execute,executeQuery,executeUpdate方法,不過都沒有帶參數,因為SQL語句早已經在PreparedStatement對象里。若要執行PreParedStatement對象里預編譯的SQL語句,需要為問號占位符參數傳入參數值,PrepatedStatement提供了一系列的setXxx(int index,Xxx value)方法傳入參數值。(若不清楚傳入值的數據類型,可以使用Object來代替)。
下面使用Statement以及PrepareStatement分別對tb_test表插入10條數據,並作對比:
public class JDBC {
String driver;
String url;
String user;
String password;
public void addDatas(String table,boolean insertType){ try{ String sql =null;int result = 0; System.out.println("開始對"+table+"表插入數據"); if(insertType){ sql = "insert into "+table+" values(null,?,?)"; System.out.println(sql); PreparedStatement prepareStatement = conn.prepareStatement(sql); for(int i=0;i<5;i++){ prepareStatement.setString(1, "name_HJL"+i); prepareStatement.setString(2,"desc_"+i); result = prepareStatement.executeUpdate(); System.out.println(table+"受影響行數為:"+result); } }else{ for(int i=0;i<5;i++){ sql = "insert into "+table+" values(null,'HJL"+i+"','"+i+"')"; System.out.println(sql); result = statement.executeUpdate(sql); System.out.println(table+"受影響行數為:"+result); } } System.out.println("插入數據完畢!"); }catch(Exception e){} } Connection conn = null; Statement statement = null; public JDBC(String paramFile){ try{ Properties props = new Properties(); props.load(new FileInputStream(paramFile)); driver = props.getProperty("driver"); url = props.getProperty("Url"); user = props.getProperty("user"); password = props.getProperty("password"); conn =DriverManager.getConnection(url,user,password); statement =conn.createStatement(); }catch(Exception e){} } public static void main(String[] args) { JDBC jdbc_2 = new JDBC("mysql.properties"); String table = "tb_test"; jdbc_2.addDatas(table,true); jdbc_2.addDatas(table,false); } }
根據上述的代碼,我們可以看到使用Statement來編寫SQL語句是比較麻煩的,不僅僅要區分雙引號還有單引號,有時候是因為這個錯誤才導致程序執行不下去,同時編程時是沒有提示說該sql是錯誤的,只有等到運行為止才知道。
運行結果如下:

開始對tb_test表插入數據 insert into tb_test values(null,?,?) tb_test受影響行數為:1 tb_test受影響行數為:1 tb_test受影響行數為:1 tb_test受影響行數為:1 tb_test受影響行數為:1 插入數據完畢! 開始對tb_test表插入數據 insert into tb_test values(null,'HJL0','0') tb_test受影響行數為:1 insert into tb_test values(null,'HJL1','1') tb_test受影響行數為:1 insert into tb_test values(null,'HJL2','2') tb_test受影響行數為:1 insert into tb_test values(null,'HJL3','3') tb_test受影響行數為:1 insert into tb_test values(null,'HJL4','4') tb_test受影響行數為:1 插入數據完畢!
總體來看,PreparedStatement比使用Statement有以下的優勢:
1.PreparedStatement預編譯SQL語句,性能更好
2.PreparedStatement無須“拼接”SQL語句,編程更簡單
3.PreparedStatement可以放置SQL注入,安全性更好
使用CallableStatement調用存儲過程:
在JDBC中,若想編寫存儲過程,是使用CallableStatement對象,該對象是由Connection的perpareCall(String sql)方法來創建,調用存儲過程的SQL語句總是這種格式:{call 存儲過程名稱(?,?,?.....)},其中的問號作為存儲過程參數的占位符。例如:
delimiter // create procedure add_pro(a int, b int,out sum int) begin set sum = a+b; end; //
上述代碼是數據庫存儲過程的SQL語句,下面是將上述的SQL語句,變成perpareCall()方法使用對應格式的存儲過程SQL格式:
Connection.prepareCall("call add_pro(?,?,?)");
存儲過程的參數既有傳入參數,也有傳出參數。所謂傳入參數就是Java程序必須為這些參數傳入值,可以通過CallableStatement的setXxx()方法為傳入參數設置值;所謂傳出參數就是Java可以通過該參數獲取存儲過程里的值,CallableStatement需要調用registerOutParameter(int index,int SQLTypes)方法來注冊該參數,第二個參數是直接調用Types的類屬性便可。
當設置完傳入參數以及傳出參數后,便可以調用CallableStatement的execute()方法來執行存儲過程了,執行結束后,通過CallableStatement對象的getXxx(int index)方法來獲取指定傳出參數值。
下面根據上述的存儲過程SQL來進調用存儲過程:
public class JDBC {
String driver;
String url;
String user;
String password;
public void callableStatementTest(){ try{ String sql = "call add_pro(?,?,?)"; CallableStatement callableStatement = conn.prepareCall(sql); //設置存儲過程的傳入參數與傳出參數 callableStatement.setInt(1, 4); callableStatement.setInt(2, 5); callableStatement.registerOutParameter(3,Types.INTEGER); callableStatement.execute(); //獲取並輸出存儲過程傳出參數的值: System.out.println("執行結果是:"+callableStatement.getInt(3)); }catch(Exception e){} } Connection conn = null; Statement statement = null; public JDBC(String paramFile){ try{ Properties props = new Properties(); props.load(new FileInputStream(paramFile)); driver = props.getProperty("driver"); url = props.getProperty("Url"); user = props.getProperty("user"); password = props.getProperty("password"); conn =DriverManager.getConnection(url,user,password); statement =conn.createStatement(); }catch(Exception e){} } public static void main(String[] args) { JDBC jdbc_2 = new JDBC("mysql.properties"); jdbc_2.callableStatementTest(); } }
其運行結果為:
執行結果是:9