面试题 --- 数据库部分

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、数据库不需要每次都去创建,响应时间更快

猜你喜欢

转载自blog.csdn.net/Keith003/article/details/83275282