一, JDBC 的几个对象
DriverManager 对象
为什么在实际开发中一般不使用 DriverManager.registerDriver(new Driver()); 而用 Class.forName("com.mysql.jdbc.Driver") 来注册驱动 原因: 使用前者会让驱动注册两次, 因为在 Driver 类里面有一个静态代码块, 静态代码块会在类加载时候执行
- static {
- try {
- java.sql.DriverManager.registerDriver(new Driver());
- } catch (SQLException E) {
- throw new RuntimeException("Can't register driver!");
- }
- }
在 Driver 类加载时候执行 registerDriver(new Driver()) 加载一次; 在 jdbc 代码里面也写了一个 DriverManager.registerDriver(new Driver()); 又加载了一次, 会注册两次驱动 而使用反射, 直接加载 Driver 类, 来加载驱动
Connection 对象
在 java.sql 包里面, 表示对数据库的连接, 用于创建执行 sql 的对象 ** Statement createStatement() : 创建一个 Statement 对象 ** PreparedStatement prepareStatement(String sql) :(常用) 创建一个 PreparedStatement 对象, 预编译的对象, 防止 sql 注入 ** CallableStatement prepareCall(String sql) : 创建一个 CallableStatement 对象, 可以执行存储过程
在实际开发中, 一般使用的 PreparedStatement 因为可以防止 sql 注入
Statement 对象
作用: 用来执行 sql 语句 ** ResultSet executeQuery(String sql) : 执行查询语句, 返回的是 ResultSet 结果集 ** int executeUpdate(String sql) : 执行修改, 删除, 更新的语句, 返回的是 int 类型, 返回的是成功操作的记录数 * 比如增加一条记录, 返回 int 值, int 值是成功添加的记录的数量 boolean execute(String sql) : 执行 sql 语句 crud 语句都可以执行, 返回的是 boolean 类型 * 如果查询出的结果是 ResultSet, 返回 true * 不是查询的操作, 返回是 false
用来执行批处理的操作 (了解) ** 有很多的 sql 语句, 批量执行很多的 sql 语句 ** addBatch(String sql) : 把多个 sql 语句放到批处理里面 ** clearBatch(): 清除批处理里面的语句 ** int[] executeBatch() : 执行批处理的语句
二, JDBC 中的事务
事务: 是数据库操作的最小工作单元, 是作为单个逻辑工作单元执行的一系列操作; 这些操作作为一个整体一起向系统提交, 要么都执行, 要么都不执行; 事务是一组不可再分割的操作集合 (工作逻辑单元); 简单来说就是: 表示一组操作要么都成功, 如果其中有一个失败了, 所有的操作都失败, 比如 首先执行添加操作, 之后再执行一个修改操作, 只有添加和修改操作都成功, 这两个操作才能真正生效, 但是如果有一个操作失败了或者之中出现了异常, 这两个操作都不会成功. 事务有四大特性:
原子性 事务是数据库的逻辑工作单位, 事务中包含的各操作要么都做, 要么都不做
一致性 事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态. 因此当数据库只包含成功事务提交的结果时, 就说数据库处于一致性状态. 如果数据库系统 运行中发生故障, 有些事务尚未完成就被迫中断, 这些未完成事务对数据库所做的修改有一部分已写入物理数据库, 这时数据库就处于一种不正确的状态, 或者说是 不一致的状态.
隔离性 一个事务的执行不能其它事务干扰. 即一个事务内部的操作及使用的数据对其它并发事务是隔离的, 并发执行的各个事务之间不能互相干扰.
持续性 也称永久性, 指一个事务一旦提交, 它对数据库中的数据的改变就应该是永久性的. 接下来的其它操作或故障不应该对其执行结果有任何影响.
JDBC 操作事务, 在 Connection 里面 setAutoCommit(boolean autoCommit): 设置事务的提交方式, 默认情况下, 会自动提交, 把值设置成 false 不会自动提交, 相当于开始一个事务 ** 提交事务 commit() ** 回滚事务 rollback() ** 设置回滚点 setSavepoint() 设置了回滚点之后就可以往 rollback 里面加参数, 参数为回滚点, 然后就会会滚到回滚点的操作
回滚事务和回滚点案例
- public class TestTran1 {
- public static void main(String[] args) {
- Connection connection = null;
- PreparedStatement preparedStatement = null;
- try{
- connection = JDBCUtils.getConnections();
- // 将事务设置为不自动提交, 相当于开始一个事务, 要设置在 sql 语句执行之前
- connection.setAutoCommit(false);
- String sql = "UPDATE account SET salary=salary+? WHERE name=?";
- preparedStatement = connection.prepareStatement(sql);
- preparedStatement.setInt(1,-1000);
- preparedStatement.setString(2,"张三");
- preparedStatement.executeUpdate();
- // 这里人为设置一个异常
- int m = 10/0;
- preparedStatement.setInt(1,1000);
- preparedStatement.setString(2,"李四");
- preparedStatement.executeUpdate();
- // 提交事务
- connection.commit();
- }catch(Exception e){
- try {
- // 出现了异常就回滚事务, 然后上面的一些转账操作都会失效.
- connection.rollback();
- } catch (SQLException e1) {
- e1.printStackTrace();
- }
- }finally {
- JDBCUtils.closeResouce(preparedStatement,connection);
- }
- }
- }
- public class TestTran2 {
- public static void main(String[] args) {
- Connection connection = null;
- PreparedStatement preparedStatement = null;
- try{
- connection = JDBCUtils.getConnections();
- // 将事务设置为不自动提交, 相当于开始一个事务, 要设置在 sql 语句执行之前
- connection.setAutoCommit(false);
- String sql = "UPDATE account SET salary=salary+? WHERE name=?";
- preparedStatement = connection.prepareStatement(sql);
- preparedStatement.setInt(1,-1000);
- preparedStatement.setString(2,"张三");
- preparedStatement.executeUpdate();
- preparedStatement.setInt(1,1000);
- preparedStatement.setString(2,"李四");
- preparedStatement.executeUpdate();
- // 设置回滚点
- Savepoint savepoint = connection.setSavepoint();
- // 还钱的过程
- preparedStatement.setInt(1,-100000);
- preparedStatement.setString(2,"李四");
- preparedStatement.executeUpdate();
- // 查询李四是否有这么多钱
- String sql2 = "SELECT * FROM account WHERE name='李四'";
- ResultSet resultSet = preparedStatement.executeQuery(sql2);
- while (resultSet.next()){
- int salary = resultSet.getInt("salary");
- // 如果还完钱之后账户为负, 则说明李四没有那么多钱, 要回滚到他还 10w 之前的过程
- if (salary < 0){
- connection.rollback(savepoint);
- }
- else {
- // 不为负数就还钱
- String sql3 = "UPDATE account SET salary=salary+? WHERE name=?";
- preparedStatement = connection.prepareStatement(sql3);
- preparedStatement.setInt(1,100000);
- preparedStatement.setString(2,"张三");
- preparedStatement.executeUpdate();
- }
- }
- // 提交事务
- connection.commit();
- }catch(Exception e){
- try {
- // 出现了异常就回滚事务, 然后上面的一些转账操作都会失效.
- connection.rollback();
- } catch (SQLException e1) {
- e1.printStackTrace();
- }
- }finally {
- JDBCUtils.closeResouce(preparedStatement,connection);
- }
- }
三, 元数据
元数据: 元数据代表的是数据库, 数据表, 表中的字段, 的一些信息, 比如说, 数据库的名称, 驱动, 表中的主键名称, 字段的类型, 字段的条数等等... 一些信息
对应的上面的三个, 可以把元数据可以分为三类,
数据库元数据
参数元数据
结果集元数据
第一类: 数据库元数据
数据库元数据可以通过 Connection 的 getMateData() 方法来获取一个数据库元数据, 返回 DatabaseMetaData 就代表一个数据库的元数据, 在 DatabaseMetaData 里面的方法:
第二类: 参数元数据
通过 PraparedSatatment 里面的 getParameterMetaData() 方法得到参数元数据 , 返回值 ParameterMetaData 代表一个参数元数据 在 ParameterMetaData 里面的方法
getParameterCount() : 中得到? 数量)
getParameterTypeName(int param) : 得到指定位置参数的类型
第三类: 结果集元数据
通过 PraparedSatatment 里面的 getMetaData() 方法得到结果集元数据, 返回值 ResultSetMetaData 代表一个结果集元数据
ResultSetMetaData 里面的方法:
getColumnCount() :
getColumnName(int column) : 获得指定列的名称 (位置从 1 开始的) -getColumnTypeName(int column): 获得指定列的类型 (位置从 1 开始的)
来源: http://www.bubuko.com/infodetail-3345365.html