jdbc获取一行字符串_JDBC基础
什么是JDBC?JDBC就是Java程序訪問數據庫的規范,是一個規范定義接口,各種數據庫廠家實現了JDBC這個接口,這些實現類就是數據庫驅動,使用時只需要調用接口中的方法即可,不用關注類是如何實現的。
JDBC的核心API有以下幾種:
DriverManager類:管理和注冊數據庫驅動,獲取數據庫連接對象Connection接口:一個數據庫連接對象,用于創建Statement和PreparedStatement對象Statement接口:一個數據庫操作對象,用于執行sql語句PreparedStatement:一個數據庫操作對象,用于執行sql語句,Statement的子接口ResultSet:用于封裝數據庫查詢的結果集,返回給客戶端Java程序這些API怎么用后面會逐個介紹到。
JDBC經典6步:
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException, SQLException {????????//1.加載注冊驅動,省略了注冊????????Class.forName("com.mysql.jdbc.Driver"); //2.獲取數據庫連接對象 String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false"; String username="root";????????String?password="root"; Connection connection = DriverManager.getConnection(url, username, password);????????//3.獲取數據庫操作對象????????Statement?statement?=?connection.createStatement();????????//4.執行sql語句,返回結果或者行數 String sql="SELECT * FROM users"; ResultSet resultSet = statement.executeQuery(sql); //5.處理結果 while(resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); System.out.println("NAME="+resultSet.getObject("NAME")); System.out.println("PASSWORD="+resultSet.getObject("PASSWORD")); System.out.println("email="+resultSet.getObject("email")); System.out.println("birthday="+resultSet.getObject("birthday")); } //6.釋放連接 resultSet.close(); statement.close();????????connection.close(); }}id=1NAME=zhansanPASSWORD=123456email=zs@sina.combirthday=1980-12-04id=2NAME=lisiPASSWORD=123456email=lisi@sina.combirthday=1981-12-04id=3NAME=wangwuPASSWORD=111111email=wangwu@qq.combirthday=1996-05-22第一步:注冊、加載驅動
實際上應該是這樣的:
Driver driver=new com.mysql.jdbc.Driver();DriverManager.registerDriver(driver);為什么這樣只加載不注冊也可以呢(mysql5之后)?
//1.加載注冊驅動,省略了注冊Class.forName("com.mysql.jdbc.Driver");點開Driver類的源碼發現:
類Driver實現了java.sql.Driver接口,在靜態代碼塊中,DriverManager類的registerDriver方法注冊了驅動,這樣我們使用注解Class.forName加全類名就會自動執行靜態代碼塊的內容,即自動注冊了驅動,只需要加載即可。
第二步:獲取數據庫連接對象connection
DriverManager類:管理和注冊數據庫驅動,獲取數據庫連接對象DriverManager類的getConnection方法返回一個數據庫連接對象//2.獲取數據庫連接對象String url="jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false";String username="root";String?password="root";????????Connection?connection?=?DriverManager.getConnection(url,?username,?password);第三步:獲取數據庫操作對象statement
Connection接口:一個數據庫連接對象,用于創建Statement和PreparedStatement對象數據庫連接對象connection的createStatement方法可以創建數據庫操作對象Statementconnection還可以管理事務:connection.setAutoCommit(false);//開啟事connection.commit();//提交事務connection.rollback();//回滾事務Statement statement = connection.createStatement();第四步:執行sql語句,返回結果或者行數
boolean?execute(String?sql):可以執行任意sqlint?executeUpdate(String?sql):執行DML語句(insert、delete、update),返回影響的行數ResultSet executeQuery(String sql):執行DQL(select)語句,返回結果集//4.執行sql語句,返回結果或者行數String sql="SELECT * FROM users";ResultSet resultSet = statement.executeQuery(sql);第五步:處理結果
如果執行的是DML語句則返回行數大于0表示執行成功,如果執行的是DQL語句,則返回結果集。
ResultSet:用于封裝數據庫查詢的結果集,返回給客戶端Java程序boolean?next():游標向下移動一行,判斷當前行是否有數據getXxx():獲取數據,Xxx表示不同數據類型while(resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); System.out.println("NAME="+resultSet.getObject("NAME")); System.out.println("PASSWORD="+resultSet.getObject("PASSWORD")); System.out.println("email="+resultSet.getObject("email")); System.out.println("birthday="+resultSet.getObject("birthday"));}第六步:釋放連接
從小到大釋放連接。
//6.釋放連接resultSet.close();statement.close();connection.close();以上六步只是最基本的,為了避免空指針異常,改進如下:
public?class?Demo02?{ public static void main(String[] args) { Connection conn=null; Statement st=null;????????ResultSet?rs=null; try { //1.加載驅動 Class.forName("com.mysql.jdbc.Driver"); //2.獲取數據庫連接對象 conn= DriverManager.getConnection(); //3.獲取數據庫操作對象 st= conn.createStatement(); //4.執行sql語句,返回結果或者行數 String sql="SELECT * FROM users"; ResultSet resultSet = st.executeQuery(sql); //5.處理結果 while(resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); System.out.println("NAME="+resultSet.getObject("NAME")); System.out.println("PASSWORD="+resultSet.getObject("PASSWORD")); System.out.println("email="+resultSet.getObject("email")); System.out.println("birthday="+resultSet.getObject("birthday")); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { if(rs!=null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } if(st!=null) { try { st.close(); } catch (Exception e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } } } }}上面的代碼重復的太多,因此進行封裝。
首先是數據庫的注冊與連接寫入db.properties文件。
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=falseusername=rootpassword=root接著是獲取連接對象和釋放資源的代碼抽取在jdbcutils中。
public?class?jdbcutils?{ private static String driver=null; private static String url=null; private static String username=null; private static String password=null; static{ try { InputStream in = jdbcutils.class.getClassLoader().getResourceAsStream("db.properties"); Properties properties = new Properties(); properties.load(in); driver=properties.getProperty("driver"); url=properties.getProperty("url"); username=properties.getProperty("username"); password=properties.getProperty("password"); Class.forName(driver); }catch (Exception e) { e.printStackTrace(); } }????//獲取連接 public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,password); } //釋放連接資源 public static void release(Connection conn, Statement st, ResultSet rs){ if(rs!=null) { try { rs.close(); } catch (Exception e) { e.printStackTrace(); } } if(st!=null) { try { st.close(); } catch (Exception e) { e.printStackTrace(); } } if(conn!=null) { try { conn.close(); } catch (Exception e) { e.printStackTrace(); } }????}}將注冊驅動、獲取連接對象和釋放連接的代碼抽取后,以上代碼就可以寫成如下,以后只需修改db.properties配置文件即可。
public class Demo02 { public static void main(String[] args) { Connection conn=null; Statement st=null; ResultSet rs=null; try { conn= jdbcutils.getConnection(); st= conn.createStatement(); String sql="SELECT * FROM users"; ResultSet resultSet = st.executeQuery(sql); while(resultSet.next()){ System.out.println("id="+resultSet.getObject("id")); System.out.println("NAME="+resultSet.getObject("NAME")); System.out.println("PASSWORD="+resultSet.getObject("PASSWORD")); System.out.println("email="+resultSet.getObject("email")); System.out.println("birthday="+resultSet.getObject("birthday"));????????????} } catch (SQLException throwables) { throwables.printStackTrace(); }finally { jdbcutils.release(conn,st,rs); } }}工具齊全之后,開始看JDBC中存在的問題了:sql注入問題。
看一個sql語句:
select * from user where name="zhulin" and password='a' or '1'=1name="zhulin"?and?password='a'為假,'1'=1為真,or拼接之后,相當于select * from user where true;這就是sql注入問題:用戶輸入的內容作為了SQL語句中的一部分,改變了原SQL的真正意義。
如何解決呢?還記得:
Connection接口:一個數據庫連接對象,用于創建Statement和PreparedStatement對象PreparedStatement對象正是用于解決這一問題。
public?class?Demo03?{ public static void main(String[] args) { Connection conn=null; PreparedStatement pstm=null; try { conn=jdbcutils.getConnection(); String sql="delete from users where id=?"; pstm=conn.prepareStatement(sql);//預編譯 pstm.setInt(1,3); int i=pstm.executeUpdate(); if(i>0){ System.out.println("刪除成功"); } } catch (SQLException throwables) { throwables.printStackTrace(); }finally { jdbcutils.release(conn,pstm,null); } }}mysql數據庫產商在實現PreparedStatement接口的實現類中的setString(int parameterIndex, String x)函數中做了一些處理,把單引號做了轉義(只要用戶輸入的字符串中有單引號,那mysql數據庫產商的setString()這個函數,就會把單引號做轉義)。
PreparedStatement會將SQL先發給數據庫預編譯,引用預編譯后的結果,可以多次傳入不同的參數給PreparedStatement對象并執行,減少SQL編譯次數,提高效率,雖然多了幾行代碼,但安全性更高,解決了sql注入的隱患,提高了程序的可讀性。
在前面提到Connection還可以管理事務,接著就簡單介紹一下JDBC控制事務。
void setAutoCommit(false);//開啟事void commit();//提交事務void rollback();//回滾事務以一個轉賬的例子介紹:Navicat中建account表
public class DemoTrasaction { public static void main(String[] args) { Connection conn = null; PreparedStatement pstmt1 = null; PreparedStatement pstmt2 = null; try { //1.獲取連接 conn = jdbcutils.getConnection(); //開啟事務 conn.setAutoCommit(false); //2.定義sql //2.1 張三 - 500 String sql1 = "update account set balance = balance - ? where id = ?"; //2.2 李四 + 500 String sql2 = "update account set balance = balance + ? where id = ?"; //3.獲取執行sql對象 pstmt1 = conn.prepareStatement(sql1); pstmt2 = conn.prepareStatement(sql2); //4. 設置參數 pstmt1.setDouble(1,500); pstmt1.setInt(2,1); pstmt2.setDouble(1,500); pstmt2.setInt(2,2); //5.執行sql pstmt1.executeUpdate(); // 手動制造異常 //int i = 3/0; pstmt2.executeUpdate(); //提交事務 conn.commit(); } catch (Exception e) { //事務回滾 try { if(conn != null) { conn.rollback(); } } catch (SQLException e1) { e1.printStackTrace(); } e.printStackTrace(); }finally { jdbcutils.release(conn,pstmt1,null); jdbcutils.release(null,pstmt2,null); } }}正常結果如下:
如果手動制造異常,則事務回滾,轉賬失敗。
最后,介紹一下數據庫連接池JDBC Template。數據庫連接池就是一個容器,存放數據庫連接對象,用戶訪問數據庫時直接從連接池中獲取數據庫連接對象,訪問完再歸還給容器。使用數據庫連接池可以解決資源,提高訪問效率。
連接池常用的有C3P0和Druid。兩者的使用都要導入jar包。
C3P0:先導入兩個jar包,然后在src目錄下定義配置文件:
c3p0.properties 或者 c3p0-config.xml。
//1.創建數據庫連接池對象DataSource ds = new ComboPooledDataSource();//2. 獲取連接對象Connection conn = ds.getConnection();Druid:先導入jar包 ,在任意目錄下定義druid.properties配置文件。
#驅動加載driverClassName=com.mysql.jdbc.Driver#注冊驅動url=jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false#連接數據庫的用戶名username=root#連接數據庫的密碼password=root#屬性類型的字符串,通過別名的方式配置擴展插件, 監控統計用的stat 日志用log4j 防御sql注入:wallfilters=stat#初始化時池中建立的物理連接個數。initialSize=2#最大的可活躍的連接池數量maxActive=300#獲取連接時最大等待時間,單位毫秒,超過連接就會失效。配置了maxWait之后,缺省啟用公平鎖,并發效率會有所下降, 如果需要可以通過配置useUnfairLock屬性為true使用非公平鎖。maxWait=60000#連接回收器的運行周期時間,時間到了清理池中空閑的連接,testWhileIdle根據這個判斷timeBetweenEvictionRunsMillis=60000minEvictableIdleTimeMillis=300000#用來檢測連接是否有效的sql,要求是一個查詢語句。validationQuery=SELECT 1#建議配置為true,不影響性能,并且保證安全性。 申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis, 執行validationQuery檢測連接是否有效。testWhileIdle=true#申請連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能。設置為falsetestOnBorrow=false#歸還連接時執行validationQuery檢測連接是否有效,做了這個配置會降低性能,設置為flasetestOnReturn=false#是否緩存preparedStatement,也就是PSCache。poolPreparedStatements=false#池中能夠緩沖的preparedStatements語句數量maxPoolPreparedStatementPerConnectionSize=200//1.加載配置文件Properties pro = new Properties();InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");pro.load(is);//2.獲取連接池對象DataSource ds = DruidDataSourceFactory.createDataSource(pro);//3.獲取連接Connection conn = ds.getConnection();同樣的,為了簡化書寫,編寫JDBCUtils來加載配置文件,初始化連接對象,釋放資源。
public class JDBCUtils { //1.定義成員變量 DataSource????private?static?DataSource?ds?; static{ try { //1.加載配置文件 Properties pro = new Properties(); pro.load(JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties")); //2.獲取DataSource ds = DruidDataSourceFactory.createDataSource(pro); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } //獲取連接 public static Connection getConnection() throws SQLException { return ds.getConnection(); } //釋放資源 public static void close(ResultSet rs , Statement stmt, Connection conn){ if(rs != null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if(stmt != null){ try { stmt.close(); } catch (SQLException e) { e.printStackTrace(); } } if(conn != null){ try { conn.close();//歸還連接 } catch (SQLException e) { e.printStackTrace(); } } } //獲取連接池方法 public static DataSource getDataSource(){ return ds;????}}這樣,我們就可以方便高效的使用JDBC了。
最后,還有一個關于JDBC的知識點,前面說過Spring可以集成Mybatis,同樣,Spring也可以集成JDBC!會在后面單獨寫一章。
總結
以上是生活随笔為你收集整理的jdbc获取一行字符串_JDBC基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国信通院公布首批软件产品开源代码安全试
- 下一篇: linux的协议栈是什么东西