1. 程式人生 > >面試題 --- 資料庫部分

面試題 --- 資料庫部分

1、常用的關係型資料庫, 非關係型資料庫

關係型:mysql 、 oracle 、 sqlserver
非關係型:redis、memcache、 mongodb、hadoop 等

2、簡單介紹下關係型資料庫三正規化?

正規化:正規化就是規範,就是資料庫在設計表時,要遵循的三個正規化
要想滿足第二正規化必須滿足第一正規化、要滿足第三正規化必須先滿足第二正規化

第一正規化(1NF):是指資料庫表的每一列都是不可分割的基本資料項,同一個列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重複的屬性,列資料的不可分割。
第二正規化(2NF):要求資料庫表中的每個例項或行必須被唯一地區分,為實現區分通常要為表加一個列,以儲存各個例項的唯一標識。(主鍵)
第三正規化(3NF):必須先滿足第二正規化(2NF),簡而言之,第三正規化(3NF)要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字資訊(外來鍵)。


反三正規化:有的時候為了效率,可以設定重複或可以推導的欄位,訂單(總價)和訂單項(單價)

3、事務四個基本特徵 ACID 特性

    事務是併發控制單位,是使用者定義得一個操作序列,這些操作要麼都做,要麼都不做,是一個不可分割的工作單位。
    一個轉賬必須 A 帳號扣錢成功,B 帳號加錢成功,才算真正的轉賬成功。
事務必須滿足四大特徵:原子性、一致性、隔離性、永續性/持續性
    原子性:表示事務內操作不可分割,要麼都成功、要麼都是失敗。
    一致性:要麼都成功、要麼都是失敗,後面的失敗了要對前面的操作進行回滾。
    隔離性:一個事務開始後,不能被其他事務干擾。
    永續性/永續性:表示事務開始了,就不能終止。
    

4、mysql 資料庫預設的最大連線數?

    為什麼需要最大連線數?特定伺服器上面的資料庫只能支援一定數目同時連線,這時候需要我們設定最大連線數(最多同時伺服器連線)。在資料庫安裝時都會有一個預設的最大連線數。

5、mysql 的分頁?Oracle 的分頁?

為什麼需要分頁?在很多資料時,不能完全顯示資料。進行分段顯示。

Mysql 是使用關鍵字 limit 來進行分頁的  limit offset, size 表示從多少索引去多少位。
Oracle 的分頁:使用三層巢狀查詢

Mysql:
    String sql = "select * from students order by id limit " + pageSize*(pageNumber - 1) + "," + pageSize;
Oracle:
    String sql = "select * from (select *, rownum rid from (select * from students order by postime desc) where rid <= " + pagesize*pagenumber +") as t where t > " + pagesize*(pageNumber-1); 

6、簡單講一下資料庫的觸發器的使用場景?

觸發器,需要有觸發條件,當條件滿足以後做什麼操作。

    觸發器用處還是很多的,比如校內網、開心網、facebook、你發一個日誌,自動通知好友。其實就是在增加日誌是做一個觸發器,再向通知表中寫入條目,因為觸發器效率高,而UCH 沒有用觸發器,效率和資料處理能力都很低。
    每插入一個帖子,都希望將版面表中的最後發帖時間,帖子總字數進行同步更新,用觸發器做效率很高。

create table board1(id int primary key auto_increment, name varchar(50), articleCount int);

create table article(id primary key auto_increment, title varchar(50), bid int references board1(id));

delimiter |  #把分隔符,改成|

create trigger inserArticle Trigger after insert on article for each row begin
    -> update board1 set articleCount=arcticleCount + 1 where id = NEW.bid;
    -> end;
    ->|

delimiter ;

insert into board1 value(null, 'test', 0);
insert into article1 value(null, 'test', 1);


7、簡單講一下資料庫的儲存過程的使用場景?

資料庫儲存過程具有如下優點:
    1、儲存過程只有建立時進行編譯,以後每次執行儲存過程都不需要再重新編譯,而一般SQL語句每執行一次就編譯一次,因此使用儲存過程可以大大提高資料庫執行速度。
    2、通常,複雜的業務邏輯需要多條SQL 語句,這些語句要分別地從客戶機發送到伺服器,當客戶機和伺服器之間的操作很多時,將產生大量的網路傳輸,如果將這些操作放在一個儲存過程中,那麼客戶機和伺服器之間的網路傳輸就會大大減少,降低了網路負載。
    3、儲存過程建立一次可以重複使用,從而可以減少資料庫開發人員的工作量。
    4、安全性高,儲存過程可以遮蔽對底層資料庫物件的直接訪問,使用EXECUTE許可權呼叫儲存過程,無序擁有訪問底層資料庫物件的顯式許可權。

正式由於儲存過程的上述優點,目前常用的資料庫都支援儲存過程,例如 IBM DB2, Microsoft SQL Server,Oracle, Access 等,開源資料庫系統 Mysql 也在 5.0 的時候實現了對儲存過程的支援。

定義儲存過程:

create procedure insert_Student(_name varchar(50), age int, out _id int)
begin
    insert into student value(null, _name, _age);
    select max(studld) into_id from student;
end;

call insert_Student("wfz", 23, @id);
select @id;

8、用 jdbc 怎麼呼叫儲存過程?

package csdn;
 
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
 
public class JDBCtest {
    public static void main(String[] args) {
        //test();
        //test2();
        test3();
    }
   /*
    * 命令列建立的儲存過程函式為: create procedure all_user() select * from user;
    *    建立一個查詢所有內容的儲存過程
    * 呼叫無參儲存過程
    */
    static void test() {
        Connection conn = Dbutil.open();
        try {
            //儲存過程函式固定格式:{call xxx}
            CallableStatement cs = conn.prepareCall("{call all_user()}");
            ResultSet rs = cs.executeQuery();
            while (rs.next()) {
                int id = rs.getInt(1);
                String name = rs.getString(2);
                int age = rs.getInt(3);
                System.out.println(id + "," + name + "," + age);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Dbutil.close(conn);
        }
    }
       /*
        * 命令列建立的儲存過程函式為:
        * create procedure insert_user(in myname varchar(20),
        * in myage tinyint(20)) insert user(username,age) values(myname,myemail);
*  表示建立一個插入myname,資料型別為varchar(20); myage,資料型別為tinyint(20)的儲存過程
        * 呼叫輸入帶參儲存過程
        */
    static void test2() {
        Connection conn = Dbutil.open();
        try {
            CallableStatement cs = conn.prepareCall("{call insert_user(?,?)}");
            cs.setString(1, "jack");
            cs.setInt(2, 10);
            cs.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Dbutil.close(conn);
        }
    }
       /*
        * 命令列建立的儲存過程函式為:
        *  create procedure getnamebyid(in cid int,
        * out return_name varchar(20)) select username into return_name
        * from user where id =cid;
        * 表示建立一個如果id為cid,那麼就輸出返回一個return_name
        * 呼叫輸入、輸出帶參儲存過程
        */
    static void test3() {
        Connection conn = Dbutil.open();
        try {
            CallableStatement cs = conn.prepareCall("{call getnamebyid(?,?)}");
            cs.setInt(1, 3);  //索引1,第3個id
            //輸出引數的話要註冊
            cs.registerOutParameter(2, Types.CHAR);
            //註冊後要更新
            cs.execute();
            String name =cs.getString(2);  //這個是索引的意思
            cs.executeQuery();
            System.out.println(name);
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            Dbutil.close(conn);
        }
    }
}

9、簡單說一下你對jdbc 的理解?

    java database connection java 資料庫連線,資料庫管理系統(mysql,oracle)是很多,每個資料庫管理系統支援的命令是不一樣的。

Java 只定義介面,讓資料庫廠商自己實現介面,對於我們而言,只需要匯入對應廠商開發的實現即可,然後以介面方式進行呼叫(mysql + mysql驅動(實現) +jdbc )

1、對應普通開發人員我們不知道mysql 和oracle 等資料庫廠商的所有語言。
2、就算你知道,沒有使用所有得資料庫,需要定製多套程式碼。

10、寫一個簡單的jdbc 的程式,寫一個訪問oracle 資料庫的jdbc程式?

1、載入驅動(com.mysql.jdbc.Driver,oracle.jdbc.driver.OracleDriver)
2、獲取連線(DriverManager.getConnection(url,username, password))
3、設定引數(Statement  PreparedStatement    cstmt.setXXX(index,value);)
4、執行(executeQuery,executeUpdate)
5、釋放連線(釋放連線要從小到大,必須放到finnaly 裡)

11、JDBC 中的PreparedStatement 相比 Statement 的好處?

大多數我們使用 PreparedStatement 代替 statement
1、PreparedStatement 是預編譯的,比Statement 速度快
2、程式碼的可讀性和維護性
雖然用PreparedStatement 來代替 Statement 會使程式碼多出幾行,但這樣的程式碼無論從可讀性還是可維護性來說,都比直接使用Statement 的程式碼離得很多檔次
stmt.executeUpdate(" insert into tb_name (col1, col2, col3, col4) values (" + var1 +", "+ var2 + ", " + var3 + "," + var4 + ")");

perstmt = con.prepareStatement(" insert into tb_name (col1, col2, col3, col4) values (?, ?, ?, ?)");
perstmt.setString(1, var1);
perstmt.setString(2, var2);
perstmt.setString(3, var3);
perstmt.setString(4, var4);

3、安全性
PreparedStatement 可以防止SQL 注入攻擊,而Statement 卻不能, 比如說:
String sql = " select * from tb_name where name = '" + varname + "' and passwd = '" + varpasswd + "' ";
如果我們把['or' 1' = '1]作為varpasswd 傳入進來,使用者名稱隨意,看看會成為市民?
select * from tb_name = '隨意' and passwd = "or '1' = '1';
把[';drop table tb_name;'] 作為varpasswd 傳入進來,則:
select * from tb_name ='隨意' and passwd = ";drop table tb_name;
有些資料庫是不會讓你成功的,但也有很多資料庫就可以使這些語句執行、
而如果你使用預編譯語句你傳入的任何內容就不會和原來的語句發生任何匹配的關係,只要全使用預編譯語句你就用不著對傳入的資料做任何過濾,而如果使用普通的 statement, 有可能要對drop 等做費盡心機的判斷和過濾

12、資料庫連線池作用

1、限定資料庫連線個數,不會導致由於資料庫連線過多導致系統執行緩慢或崩潰
2、資料庫不需要每次都去建立或銷燬,節約資源
3、資料庫不需要每次都去建立,響應時間更快