第二部分 JDBC練習

前提下載:mysql-connector-java,工程下建立lib文件夾將壓縮包放入,右鍵壓縮包build path 把jar包導入

這個壓縮包用于java和mysql的連接(mysql的JDBC)

建立簡單JDBC的連接

1.數據庫的driver向java的DriverManager注冊
2.java的DriverManager連接數據庫(上一步的意義就是讓這步知道應該連接哪一個數據庫)
3.這時候數據庫和java連接上了,但是如果想要傳輸數據你必須要還要在連接上獲得傳輸器

       String driver="com.mysql.jdbc.Driver";//驅動路徑(Driver類的全類名)
       String url="jdbc:mysql://localhost:3306/數據庫名";//數據庫地址
       String user="root";//訪問數據庫的用戶名
       String password="123456";//用戶密碼        
         try {
             //1、加載驅動
             Class.forName(driver);  //實例化Driver類
 //對于系統說并不確定用的是哪一個數據庫,java提供一個大管家,用于管理當前使用的是哪個數據庫的連接,這個大管家就是DriverManager。想要和某個數據庫相連,就要向這個數據庫注冊一下,告訴它想要和那個數據庫相連。實例化過程自動向DriverManager注冊使用哪個driver,不需要顯示調用DriverManager.registerDriver方法(將數據庫的Driver向java的DriverManager注冊,注冊后java和mysql就處于準備連接階段)
             //2、連接數據庫
           Connection con = DriverManager.getConnection(url, user, password);
             if(!con.isClosed()){//判斷數據庫是否鏈接成功
                 System.out.println("已成功鏈接數據庫!");
                 //3、建立傳輸器(Statement對象)
                 Statement st = con.createStatement();
                //4、執行sql語句
                 String sql="select *from user";//查詢user表的所有信息
                 ResultSet rs = st.executeQuery(sql);//查詢之后返回結果集
           //ResultSet用來存儲從數據庫中查詢的結果
                 //5、打印出結果
                 while(rs.next()){
        //next()方法,類似一個游標,從0數據開始,每調用一次就指向rs的下一個數據,也就是表里的下一行   System.out.println(rs.getString("Id")+"\t"+rs.getString("name")+"\t"+rs.getString("password"));
 //rs.getString("Id")表示將rs里的id字段的數據當做字符串取出,與實際字段數據類型無關
也可以使用rs.getString(1)表示獲取第一個字段值
           }
               }
                 rs.close();//關閉資源
                 con.close();//關閉數據庫
             }
                 
             } catch (Exception e) {
                 // TODO Auto-generated catch block
               e.printStackTrace();
           }

executeQuery(sql) 用于執行select語句
executeUpdate(sql)用于執行select以外語句 (返回值>0修改成功 <0插入失敗)
解決中文亂碼問題
若想往數據庫里插入漢字首先保證數據庫和eclipse的編碼一致 然后 在url尾部加上 ?characterEncoding=utf8 并且設置編輯器的編碼為utf-8(有時候需要專門更改某個字段的編碼)
注:實際開發過程應該先檢查能否插入漢字(必須統一開發工具版本!!)

以上是一個初級的JDBC程序,若完善,需要改成以下


image.png

2.獲取JDBC的連接和關閉連接的工具類(通過配置文件進行連接)
配置文件存在src目錄下,因為ecplise會把src下目錄的文件當做是當前目錄

public class JDBCTools {   
    private static String driver;    
    private static String url;
    private static String username;
    private static String password;
    private static Properties prop=new Properties(); //類似Map集合
    
    static{    //靜態初始化塊
        InputStream in=null;  //建立一個輸入流
        
        try {
            in=JDBCTools.class.getClassLoader().getResourceAsStream("db.properties");
            /*getResourceAsStream()是用來獲取文件中資源
            JDBCTools.class.getClassLoader()代碼的意思是
            先得到JDBCtools的Class對象,然后得到這個類的加載器,
            最后用這個加載器去加載需要的資源文件
                              其實也可以使用FileInputStream讀取文件
            */
            prop.load(in); //將輸入流裝在到Properties集合類中
            //得到key對應的value
            driver=prop.getProperty("jdbc.driver");
            url=prop.getProperty("jdbc.url");
              username=prop.getProperty("jdbc.username");
            password=prop.getProperty("jdbc.password"); 
            Class.forName(driver);  //加載驅動
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    
    
    public static Connection getConnection(){  //獲取連接的方法
        Connection conn=null;    
        try {
            conn=DriverManager.getConnection(url,username,password);
            
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return conn;
    }
        
    
    public static void closeConnection(Connection conn,Statement stmt,ResultSet rs){
        try {              //關閉連接的方法
            if(rs != null)
                rs.close();
            if(stmt != null)
                stmt.close();
            if(conn != null)
                conn.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }   
}

3.PreparedStatement(實際開發用的)

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Demo1 {
public static void main(String[] args) {
    Connection conn=null;
    PreparedStatement ps=null;
    ResultSet rs=null;
    String url="jdbc:mysql://localhost:3306/sunhao?characterEncoding=utf8";
//解決中文亂碼的問題
    String username="root";
    String password="123456";
    String driver="com.mysql.jdbc.Driver";
    try {
        Class.forName(driver);
        conn=DriverManager.getConnection(url,username,password);
        
        String sql="select *from emp where empno=?";
        
        ps=conn.prepareStatement(sql);   //預編譯
        
        ps.setInt(1,7369);   //賦參數,為第一個問號位置賦值7369
        
        rs=ps.executeQuery();    //執行sql
        if(rs.next()){
            System.out.println(rs.getString("ename"));  
        }   
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
}
}

4.利用preparedStatement實現登陸注冊


public class UserDaoImpl {
    public User login(User u){   //因為一般登陸有后續操作所以如果數據庫中有這么個人,就返回他
        User u1=null;
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        conn=JDBCTools.getConnection();
        String sql="select * from t_user where username=? and password=?";
        try {
            ps=conn.prepareStatement(sql);
            ps.setString(1, u.getUsername());
            ps.setString(2, u.getPassword());
            rs=ps.executeQuery();
            if(rs.next()){
                u1=new User(rs.getString("username"),rs.getString("password"));
                return  u1;
            }
                    
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return u;   
    }
    public void register(User u) throws SQLException{
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        conn=JDBCTools.getConnection();
        String sql="insert into t_user values(?,?)";
        ps=conn.prepareStatement(sql);
        ps.setString(1, u.getPassword());
        ps.setString(2, u.getPassword());
        int falg=ps.executeUpdate();
        if(falg>0){
            System.out.println("插入成功");
        }else{
            System.out.println("插入失敗");
        }   
    }
}


注意模糊查找的時候不能在預編譯的sql語句里使用%?%而應該是 ? 在參數里為?賦值為模糊查找%張 %

模擬DButils工具包的方法

1.建立可以插入可變參數的數據增刪改方法。update(String sql,Object...obj)

public class UTl {
    public void update(String sql,Object...obj) throws SQLException{
        Connection conn=null;  //可變參數的obj的長度就是sql里占位符個數,用于替換占位符
        PreparedStatement ps=null;
        conn=JDBCTools.getConnection();
        ps=conn.prepareStatement(sql);  //sql是具有占位符的語句
        for(int i=0;i<obj.length;i++){   //將sql語句里的占位符替換為實參
            ps.setObject(i+1, obj[i]);
        }
        int flag=ps.executeUpdate();
        if(flag>0){
            System.out.println("插入成功");
        }       
    }

2.建立一個完成查詢的工具方法,

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.sql.ResultSetMetaData;
import com.qianfeng.demo1.JDBCTools;

public class DDD {
    
    /*為什么查詢不用和增刪改類似的方法?
    因為增刪改的時候,是往數據庫里操作,
    而查是將數據庫里的內容存在對象里,
       這時你不知道表和類中到底有哪些屬性,所以需要調用方法獲取數據庫的字段和值
    然后將字段值存到對象的對應屬性里
    在此過程就需要 有獲得數據庫字段的方法,
    而此時返回值應該是存完值后的類對象,但是由于是萬能查找,
    你不知道你查找的數據庫應該返回的是什么類,返回值就設置成了泛型
    傳遞一個泛型類的反射的原因是,普通類是無法給一個不確定的字段進行賦值的
        而類的反射卻可以給不確定的私有屬性進行賦值
(獲取數據庫的字段名,然后調用反射的cls.getDeclaredField(fileName);方法就可以得到類中屬性的名字,再通過field.set(obj, fileValue);就可以把值存給對應屬性了)
    
    */
    /*1.獲取鏈接
    2.獲取PreparedStatement
    3.獲取結果集
    4.獲取結果集元數據(字段)
    5.把數據存入map集合
    6.遍歷map集合存入對象(其實此時完全可以直接把字段—字段值存入對象,多次一舉,只是為了易于理解)
    */
    public <T>T find(Class<T> cls,String sql,Object...obj) throws SQLException, InstantiationException, IllegalAccessException{
            /*第一個參數是一個反射對象,泛型表示的是這個泛型對象反射的是哪一個類,反射哪個類返回值就是哪個類*/
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        
        conn=JDBCTools.getConnection();//1.獲取鏈接
        ps=conn.prepareStatement(sql);//2.獲取PreparedStatement
        for(int i=0;i<obj.length;i++){
            ps.setObject(i+1, obj[i]);
        }
        rs=ps.executeQuery();//3.獲取結果集
    
    //結果集也是一個表,得到表結構的方法使用getMetaData(),得到表結構你就可以得到表的字段了
        ResultSetMetaData rmd=rs.getMetaData(); 
//得到結果集的結構,rmd對象代表表結構
        //String 是字段名  Object是字段值
        Map<String,Object>map=new HashMap<>();
        if(rs.next()){     //4.獲取表的元數據(字段)   
            for(int i=0;i<rmd.getColumnCount();i++){  rmd表結構對象調用方法獲取字段個數
                //注意數據庫里字段是從1開始
                String columnName=rmd.getColumnLabel(i+1); 
                Object columnValue=rs.getObject(columnName);
                map.put(columnName, columnValue);//5.把數據存入map集合
            }
        }       
        T t=cls.newInstance();  //建立對象,注意類必須擁有一個無參構造器
        Iterator it=map.entrySet().iterator();
        while(it.hasNext()){   //遍歷map集合
            Entry <String,Object>entry=(Entry<String,Object>)it.next();
            String fileName=entry.getKey();
            Object fileValue=entry.getValue();
            
            set(t,fileName,fileValue);//6.遍歷map集合存入對象
        }   
        System.out.println(map);    
        return t;   
    }

    private void set(Object obj,String fileName, Object fileValue)  {
        // TODO Auto-generated method stub
        
        try {
            Class cls=obj.getClass();  
/*此時使用反射的意義在于,直接知道obj的直接類,而且用反射可以給私有指定字段進行賦值*/
            Field field=cls.getDeclaredField(fileName);
            field.setAccessible(true);//設置為true后可以直接給私有屬性賦值而不調用方法
            
            field.set(obj, fileValue);
            
            
        } catch (NoSuchFieldException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }
}

/*注意1.當數據庫字段和類屬性類型不同,統一屬性
 * 2.基本類型存在null時不可賦值,將類中屬性改為包裝類
 * */
 

7.jdbc進行批處理:批量增刪改

public class TestBatch {
    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        
        try {
            conn=JDBCTools.getConnection();
            String sql="insert into a values(?)";
            ps=conn.prepareStatement(sql);
            for(int i=0;i<102;i++){
                ps.setInt(1, i);
                ps.addBatch();   //添加到緩沖區
                if(i%10==0){
                    ps.executeBatch();  //將添加到緩沖區的數據批量更新到數據庫
                    ps.clearBatch();    //將緩沖區中更新完的數據清空
                }   
            }
         ps.executeBatch();  //將沒更新的緩沖區更新
         ps.clearBatch();       
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }
}

8.DBCP連接池

commons-dbcpxxx.jar
commons-poolxxx.jar

public class TestDBCPpool {

    //第一種鏈連接方式(無配置文件)
    @Test
    public void test1(){
         BasicDataSource dataSource = new BasicDataSource();
           //必要屬性
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://localhost:3306/sunhao");
            dataSource.setUsername("root");
            dataSource.setPassword("123456");
            
         
         //常用屬性
            dataSource.setMinIdle(5); //最小空閑連接
            dataSource.setMaxIdle(50);   //最大空閑連接
            dataSource.setInitialSize(10);  //初始化連接
            dataSource.setMaxActive(200);   //最大連接數
            dataSource.setMaxWait(5000);  //最大等待時間
        
            //獲取鏈接
        Connection conn=null;
        try {
            conn=dataSource.getConnection();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }   
    }
    
    //第二種連接方式(有配置文件)
    @Test
    public void test2() throws Exception{
        Properties prop=new Properties();
        prop.load(new FileInputStream("db.properties"));
        //配置文件必須符合特定的規則才能正確讀取
        DataSource dataSource = BasicDataSourceFactory.createDataSource(prop);
        Connection conn=null;
        conn=dataSource.getConnection();
        
//這時候常用屬性可以設置到配置文件中,當連接后就自動獲取了常用屬性
    }
}

9.c3p0連接池(常用此連接池)
//1.構造函數不寫name值就要,想dbcp一樣

public class C3P0Utils {  
    //1、提供私有化的數據源    使用默認設置  (也可以先定義用靜態代碼塊加載配置文件)
    private static ComboPooledDataSource datasource=new ComboPooledDataSource();  
    //使用命名配置 (如果配置文件中有多條配置信息,就要使用下面這種方法,確定創建的是哪個數據源) 
    //private static ComboPooledDataSource datasource =new ComboPooledDataSource("itheima");  
    //2.提供對外的數據源  
     public static DataSource getDataSource(){  
        return datasource;    
    }  
    //3.提供對外的鏈接    
    public static Connection getConnection() throws SQLException{  
        return datasource.getConnection();  
    }  
}  
  public static void closeConnection(Connection conn,Statement stmt,ResultSet rs){
        try {              
            if(rs != null)
                rs.close();
            if(stmt != null)
                stmt.close();
            if(conn != null)
                conn.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }   

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,527評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,687評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,640評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,957評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,682評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,011評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,009評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,183評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,714評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,435評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,665評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,148評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,838評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,251評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,588評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,379評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,627評論 2 380

推薦閱讀更多精彩內容

  • Spark SQL, DataFrames and Datasets Guide Overview SQL Dat...
    Joyyx閱讀 8,344評論 0 16
  • JDBC概述 在Java中,數據庫存取技術可分為如下幾類:JDBC直接訪問數據庫、JDO技術、第三方O/R工具,如...
    usopp閱讀 3,546評論 3 75
  • java類和數據庫表的關系 類對應表,字段對應屬性,一行數據對應一個對象,所以類的屬性名要和表的字段名相同才能進行...
    孫浩j閱讀 567評論 0 1
  • 一. Java基礎部分.................................................
    wy_sure閱讀 3,830評論 0 11
  • 貧困很難進入成功人士的法眼。在這些成功人士的眼中,富足和商機無處不在,他們從不懷疑自己的能力,并堅信世間財富俯拾...
    行云流水007閱讀 150評論 0 0