一、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开始的)