【001】什么是JDBC?
答:
JDBC的全称是Java DataBase Connection,也就是Java数据库连接,我们可以用它来操作关系型数据库。
JDBC接口及相关类在 java.sql 包和 javax.sql 包里。
我们可以用它来连接数据库,执行SQL查询,存储过程,并处理返回的结果。
【002】如何创建一个JDBC连接?
答:
JDBC连接是和数据库服务器建立的一个会话,可以想象成是一个和数据库的Socket连接。
创建JDBC连接需要两步:
① 注册并加载驱动:
使用Class.forName(),驱动类就会注册到DriverManager里面并加载到内存里
② 使用DriverManager获取连接对象:
调用DriverManager.getConnection()方法并传入数据库连接的URL、用户名及密码,就能获取到连接对象
【003】JDBC的核心API有哪些?
答:
JDBC的核心API都在 java.sql.* 和javax.sql.* 两个jar包中,主要有5个:
Driver、DriverManager、Connection、Statement、ResultSet
① Driver :Java驱动程序接口。所有具体的数据库厂商都要实现此接口
② DriverManager :驱动管理器类,用于管理所有注册的驱动程序
| -- registerDriver(driver):注册驱动类对象
| -- Connection getConnection(Strinig url, Strinig user, Strinig password):
通过指定URL、用户名、密码获取连接对象
Connection getConnection(String url, Properties info):
通过指定URL、属性集文件获取连接对象
③ Connection :Java程序和数据库的连接对象,
客户端和数据库所有交互都是通过connection对象完成的
| -- Statement createStatement() :创建Statement对象
| -- PreparedStatement prepareStatement(String sql) :创建PreparedStatement对象
| -- CallableStatement prepareCall(String sql) :创建CallableStatement对象
| -- setAutoCommit(boolean autoCommit) :设置事务是否自动提交
| -- commit() :在链接上提交事务
| -- rollback() :在此链接上回滚事务
④ Statement :用于执行静态的SQL语句,
(包含子接口PreparedStatement、CallableStatement)
PreparedStatement:
| -- int executeUpdate() :执行预编译的更新SQL语句(DDL、DML)
| -- ResultSet executeQuery() :执行预编译的查询SQL语句(DQL)
| -- execute(String sql) :用于向数据库发送任意SQL语句
| -- addBatch(String sql) :将多条SQL语句放到一个批处理中
| -- executeBatch() :向数据库发送一批SQL语句执行
CallableStatement:用于执行存储过程的SQL语句(call xxx)
| -- ResultSet executeQuery():调用存储过程的方法
⑤ ResultSet :用于封装查询出来的数据
| -- boolean next() :将光标移动到下一行
| -- getXX() :获取列的值
【004】使用JDBC后,需要注意什么?
答:
JDBC程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是ResultSet、Statement和Connection对象
特别是Connection对象,它是非常稀有的资源,用后必须释放,如果Connection不能及时、正确的关闭,极易导致系统宕机
为确保资源释放代码能运行,一定要放在finally语句中
Connection使用原则:尽量晚创建、尽量早释放
【005】Statement和PreparedStatement有什么区别?
答:
① 预编译
PreparedStatement 对象会将SQL语句预编译并存储,在真正执行前,才把参数传递给SQL语句,可以反复执行,因此 PreparedStatement 比 Statement 效率要高一些
- 创建时区别:
- Statement stmt = conn.createStatement();
- PreparedStatement pstmt = conn.prepareStatement();
- PreparedStatement 会先初始化SQL;
- Statement 则不会初始化SQL,并且没有预处理,每次都从0开始执行SQL
- 执行时区别:
- ResultSet rs = stmt.executeQuery(SQL);
- ResultSet rs = pstmt.executeQuery();
② 安全性
PreparedStatement 是预编译的,可以有效防止SQL注入等问题,所以安全性较高些
③ 代码可读性和可维护性
④ 缓存
PreparedStatement 是有缓存的,使用缓存提高了运行速度
【006】阐述JDBC连接的开发步骤?
答:
① 加载数据库驱动
Class.forName("com.mysql.jdbc.Driver");
② 通过DriverManager获取数据库连接Connection
DriverManager.getConnection();
③ 通过Connection获取 Statement / PreparedStatement
conn.createStatement(); / conn.prepareStatement();
④ 将SQL语句绑定到 Statement / PreparedStatement中去,准备向数据库发送SQL语句
⑤ 执行完SQL语句后,返回对象的结果
ResultSet rs = executeQuery(查询)
int i = executeUpdate(增删改)
⑥ 如果是查询的话,迭代结果集进行处理
while(rs.next()) { String name = rs.getString("name"); ... }
⑦ 如果是非查询的话,还需要事务支持
conn.setAutoCommit(false);
conn.commit(); / conn.rollback();
⑧ 依次关闭连接对象
ResultSet / Statement / Connection -> rs.close(); st.close(); conn.close();
【007】JDBC连接数据时效率如何,应如何解决?
答:
JDBC获取连接对象需要消耗较多的资源,而每次操作都要重新获取新的连接对象,然后关闭,这样连接对象的效率低;并且创建连接也需要效率较多资源,创建的时间也长
假设网站1天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库资源,极易造成数据服务器内存溢出
【008】什么是连接池,连接池有什么作用,常用的连接池有哪些?
答:
创建:指一开始就创建一定数量的连接放入内存中,这块内存称为连接池
使用:当需要使用时直接从连接池中取一个已经创建好的连接对象
关闭:连接关闭时不是真正关闭连接,而是将连接对象再次放到连接池中
作用:解决了JDBC重复创建新连接对象消耗较多资源的问题
常用:C3P0连接池、DBCP连接池
【009】阐述什么是DBUtils,其核心功能类有哪些?
答:
DBUtils是Java编程中的数据库操作工具,封装了对JDBC的操作,即简化了JDBC的开发工具包
它有3个核心功能类:
① QueryRunner :
该类简化了SQL的增删改查操作
QueryRunner() \ QueryRunner(DataSource ds) 构造函数
update(Connection conn, String sql, Object... params) \ update(...)
用来完成表数据的增加、删除、更新操作
query(Connection conn, String sql, ResultSetHandler<T> rsh, Object.. params) \ query(..)
用来完成表数据的查询操作
② ResultSetHandler :
该接口用于处理结果集,将数据按要求转换为另一种形式进行封装
该接口中的方法:Object handle(ResultSet rs);
常用的实现ResultSetHandler接口的类如下:
- 封装成数组
- ArrayHandler:
- ArrayListHandler:
- 把结果集的每1行数据都封装成对象数组,然后再存放到List
- 封装成JavaBean
- BeanHandler(Class clazz):
- 把结果集中的第1行数据封装到一个对应的JavaBean实例中
- BeanListHandler:
- 把结果集的每1行数据都封装到一个对应的JavaBean实例中,然后再存放到List
- 封装成Map
- MapHandler:
- 把结果集中的第1行数据封装到一个Map中,key是列名,value是对应的值
- MapListHandler:
- 把结果集的每1行数据都封装到一个Map中,然后再存放到List
- KeyedHandler:
- 把结果集的多行数据都封装到一个Map中,取其中1列作为键,记录本身作为值;然后再把这些map存放到另1个Map中,其中key为指定的列,格式:
Map<某列类型, Map<字段名, 字段值>>,keyedHandler指定为<某列类型>(列名)
- 封装成单行单列
- ScalarHandler:
- 获取结果集中的第1行第1列的值,常用于单行单列的聚合函数查询结果集
- 封装成多行单列:
- ColumnListHandler:
- 只封装1列时,将数据存放到List,List集合中的元素类型与列的类型相同,通常用于多行单列的查询结果集
③ DbUtils :
提供如关闭连接、事务处理、装载JDBC驱动程序等方法的工具类,所有方法都是静态的
close(...) :DbUtils提供了3个重载的关闭方法,这些方法检查所提供的参数是否为null,如果不是的话,则关闭Connection、Statement和ResultSet
closeQuietly(...) :不仅能在Connection、Statement和ResultSet为null的情况下避免关闭,还能隐藏一些在程序中抛出的SQLException
【010】在Java中,什么是事务、什么是Java事务,事务有什么用?
答:
① 事务:
通常认为,事务仅与数据库相关;事务必须服从ACID原则,即:
原子性(atomicity)、一致性(consistency)、隔离性(isolation)、持久性(durability)
事务可以理解是一组原子操作单元,从数据库角度说,就是一组SQL指令,要么全部执行成功,若因为某个原因其中一条指令执行错误,则撤销先前执行过的所有指令。即:
SQL指令组要么全部执行成功,要么全部撤销不执行
② Java事务:
实际上,一个Java应用系统要操作数据库,则通过JDBC来实现。增删改查通过方法间接实现,事务的控制也相应转移到Java程序代码中,因为数据库操作的事务习惯上也称为Java事务
③ 作用:
事务是为解决数据安全操作提出的,事务控制实际上是控制数据的安全访问
【011】写出MySQL事务、JDBC事务、DbUtils事务各自的操作语法
答:
MySQL默认每条语句都自动开启一个事务
① MySQL事务 :
set @@autocommit; 查询当前事务提交情况
set @@autocommit = 0; 关闭自动提交,启动手动提交事务(0关闭、1开启)
start transaction; 开启事务
commit; 提交事务
rollback; 回滚事务
② JDBC事务 :
setAutoCommit(false) 开启事务
commit; 提交事务
rollback; 回滚事务
③ DbUtils事务 :
conn.setAutoCommit(false) 开启事务
new QueryRunner() 创建核心类,不设置数据源(手动管理连接)
query(conn, sql, handler, params) 手动传递连接执行查询操作
update(conn, sql, params) 手动传递连接执行更新操作
DbUtils.commitAndClose(conn) 提交并关闭连接
DbUtils.rollbackAndClose(conn) 回滚并关闭连接
【012】ThreadLocal类中常用的方法有哪些
答:
ThreadLocal 工具类可以在同一个线程中共享数据
ThreadLocal 底层是一个Map,key存放当前线程对象,value存放需要共享的数据
① set(value) :向当前线程存入数据,类似 map.put(key, value)
② get() :从当前线程取出数据,类似 map.get(key)
③ remove() :从当前线程删除数据,类似 map.remove(key)
【013】简要描述事务的ACID特性
答:
① 原子性(Atomicity)
- 事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生
② 一致性(Consistency)
- 事务前后数据的完整性必须保持一致,事务执行之前和执行之后数据要保持一致
③ 隔离性(Isolation)
- 指多个用户并发访问数据库时,一个用户的事务不能被其它用户的事务干扰,多个并发事务之间的数据要相互隔离,互不影响
④ 持久性(Durability)
- 指一个事务一旦被提交,它对数据库中数据的改变是永久的,即使数据库发生故障也不应该对其有任何影响
【014】事务并发访问时常见的问题有哪些?如何解决?
答:
事务并发访问时可能会出现的问题有:脏读、不可重复读、幻读
① 脏读
② 不可重复读
- 一个事务中两次读取的数据内容不一致(这是事务update时引起的)
③ 幻读
- 一个事务中两次读取的数据数量不一致(这是事务insert或delete时引起的)
解决方案:
设置相应的隔离级别
read uncommitted < read committed < repeatable read < serializable
【015】理解事务的4种隔离级别,并写出使用隔离级别的常用命令
答:
隔离级别
| 名字
| 脏读
| 不可重复读
| 幻读
| 数据库默认
隔离级别
| read uncommitted
| 读未提交
| 是
| 是
| 是
| | read committed
| 读已提交
| 否
| 是
| 是
| Oracle
SQL Server
| repeatable read
| 可重复读
| 否
| 否
| 是
| MySQL
| serializable
| 串行化
| 否
| 否
| 否
| |
相关命令:
- 查询全局事务隔离级别:
- select @@global.tx_isolation;
- 设置全局事务隔离级别:
- set global transaction isolation level read uncommitted;
【016】隔离级别的安全性和性能有什么联系?
答:
隔离级别越高,安全性越高,但性能越低;
所以一般情况下使用第2级(read committed)或第3级(repeatable read)
安全性:read uncommitted < read committed < repeatable read < serializable
性 能:read uncommitted > read committed > repeatable read > serializable
|
|