JDBC学习笔记(1)

141 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

****什么是JDBC

​编辑

JDBC架构

分为两层

JDBC应用程序层:负责管理数据库连接,提供标准的数据库访问接口

JDBC驱动程序层:

驱动程序的类型

JDBC-ODBC桥驱动程序

本机API驱动程序

网络协议驱动程序

本机协议驱动程序

使用JDBC的API

DriverManager类:为数据库加载驱动程序

Driver接口:表示数据库驱动程序,被所有JDBC驱动程序类实现

Connection接口:表示Java应用程序和数据库之间的连接

Statement接口:表示SQL语句

PreparedStatement接口:

ResultSet接口:表示从数据库检索到的数据

SQLException类:表示数据库抛出的异常

使用JDBC的步骤

加载驱动程序

使用驱动程序管理器加载和注册所需的驱动程序,使用到了DriverManager类Driver接口

 DriverManager类中的registerDriver方法或直接Class.forName()

        //方法1:
        Class.forName("com.mysql.cj.jdbc.Driver");
        /*
        将类的字节码文件加载到内存
        有一些代码会随着类的加载而执行,这些代码就是静态代码块中的
        */
        //方法2:
        Driver d = new com.mysql.cj.jdbc.Driver();
        DriverManager.registerDriver(d);
        /*
        先创建Driver对象,用registerDriver()方法注册驱动程序
         */

连接到数据库 

可以在Java应用程序中创建多个Connection对象来访问不同的数据库,使用Connection接口

DriverManger类中的getConnection()方法

该方法有三个重载

    public static Connection getConnection(String url);
    //这种方式的url与下面两种的不同
    String url = "jdbc:mysql://localhost:3306/company;user = root;password = niit";
    public static Connection getConnection(String url, Properties info);
    public static Connection getConnection(String url,String user,String password);
    //静态方法的目的是能够通过类名直接调用
   

String url = "jdbc:mysql://localhost:3306/company"; 
Connection conn = DriverManager.getConnection(url,"root","niit");

创建和执行SQL语句

创建了连接之后,肯定是用来连接的对象来执行SQL语句,所以可以使用Connection对象提供的createStatement()方法来创建Statement对象

创建时用到了Statement接口

Statement sta = conn.createStatement();

创建时还用到了PreparedStatement接口,PreparedStatement接口继承自Statement接口

从名字看它不是直接创建语句,而是在准备SQL语句

步骤

1.先准备一个SQL模板,需要参数的位置用?代替

2.将?补充

3.执行语句,因为sql字符串中有?所以不能将sql字符串传入executeQuery方法中,而是补充好?的模板对象直接调用相应的方法

String sql = "select * from login where username =? and password = ?";
psta = conn.prepareStatement(sql); 
psta.setString(1,username);
psta.setString(2,password);
rs = psta.executeQuery();

执行时用到了Statement接口中的excute(sql)executeUpdate(sql)executeQuery(sql) 方法

excute可以去执行create,alter,drop这些语句

其实excute可以执行任意的sql语句,并返回Boolean值,如果执行结果是ResultSet的对象,该方法返回true,否则返回false

String sql = "create table student(id int,name varchar(20))"
int count = sta.executeUpdate(sql);
if(count > 0)
    System.out.println("添加成功");
else
    System.out.println("添加失败");

//count接收的是sql语句影响到的数据库中受影响的行数

excuteUpdate可以去执行insert,update,delete这些语句

String sql = "insert into player values (1,123)";
int count = sta.executeUpdate(sql);
if(count > 0)
    System.out.println("添加成功");
else
    System.out.println("添加失败");

String sql = "update player set ID = 2 where ID=1";
int count = sta.executeUpdate(sql);
//执行sql语句后有返回值,该返回值用来判断执行的情况
if(count > 0)
    System.out.println("添加成功");
else
    System.out.println("添加失败");

excuteQuery可以去执行select语句

当使用excuteQuery时返回的结果就不用int类型的变量来接收了,这里用到了结果集ResultSet 来接收.

ResultSet rs = null;
String sql = "select * from player";
rs = sta.executeQuery(sql);
//游标默认情况下在第一行数据上面,所以先让游标向下移动一行,才能去获取第一行数据
rs.next();
int id = rs.getInt(1);//取数据,取第一行的第一列数据
System.out.println(id);

/*
这种情况不能确定游标所指的那行有没有数据
所以要改进
*/


ResultSet rs = null;
String sql = "select * from player";
rs = sta.executeQuery(sql);
while(rs.next()) {  //判断是否有数据
    int id = rs.getInt(1);
    String name = rs.getString(2);
    System.out.print(id+"\t");
    System.out.println(name);
} 

结果集有不同的类型,通过创建语句对象Statement sta = conn.createStatement();时确定

各种类型以常量字段形式定义在ResultSet接口中

Statement createStatement();
/*
不接受任何参数,它获取到的ResultSet默认只读,且只允许向前滚动
*/


Statement createStatement(int resultSetType,int resultSetConcurrency);


Statement createStatement(int resultSetType,int resultSetConcurrency,int resultSetHoldability);


/*
resultSetType代表ResultSet类型,它决定结果集指针是可滚动还是仅向前,表格的1,2,3
resultSetConcurrency指定结果集的并发模式,它决定结果集中的数据是可更新还是只读,表格的4,5
resultSetHoldability指定事务提交后,是否继续保留指针,意味着是否可以继续读取数据,表格的6,7
*/

ResultSet字段描述
TYPE_SCROLL_SENSITIVE允许指针双向移动,如果数据发生修改,能及时同步到数据库
TYPE_SCROLL_INSENSITIVE允许指针双向移动,如果数据库发生修改,不能及时同步到数据库
TYEPE_FORWARD_ONLY只允许指针从前向后移动
CONCUR_READ_ONLY不允许更新ResultSet对象的并发模式,也就是只能读
CONCUR_UPDATABLE允许更新ResultSet对象的并发模式,也就是可读加可写
CLOSE_CURSOR_AT_COMMIT提交当前事务后关闭指针(不能再取到数据)
HOLD_CURSOR_OVER_COMMIT提交当前事务后保留指针(可以继续使用数据)

结果集ResultSet中的方法

rs.first();//指针跳转到第一行

rs.isFirst;//指针是否在第一行

rs.beforeFirst;//指针跳转到第一行之前

rs.isBeforeFirst();//指针是否在第一行之前

rs.last();//指针跳转到最后一行

rs.islast;//指针是否在最后一行

rs.afterLast;//指针跳转到最后一行之后

rs.isAfterLast();//指针是否在最后一行之后

rs.previous();//指针跳转到上一行

rs.next();//指针跳转到下一行

rs.absolute(int i);//指针跳转到指定行

rs.relative(int i);//指针向前或向后跳转的相对行数,正数向前跳,负数向后跳

XXX getXXX(String columnLabel);//根据列的名称获取该列的值,并转换为XXX类型

XXX getXXX(int columnIndex);//根据列的位置,获取该列的值,并转换为XXX类型

如
int id = rs.getInt(1);
String name = rs.getString(2);

修改结果集时用到的方法

rs.updateRow();//更新ResultSet对象,同时将数据同步到数据库中对应的表

rs.insertRow();//向ResultSet对象中插入一行数据,同时将数据同步到数据库中对应的表

rs.deleteRow();//从ResultSet对象中删除一行数据,同时在数据库中对应的表中删除该行数据

rs.updateString(int columnIndex,String x);//根据列索引找到字段,并使用指定字符串修改它

rs.updateString(String columnLabel,String x);//根据列名找到字段,并使用指定字符串更新它

rs.updateInt(int columnIndex.int x);//根据列索引找到字段,并使用指定数字修改它

rs.updateInt(String columnLabel,int x);//根据列名找到字段,并使用指定数字更新它

处理SQL异常

我们给数据库发送的SQL语句,执行时可能会出现错误,比如插入数据时主键冲突,此时JDBC会把问题包装成SQLException异常

由于不能确保SQL是否正确,数据库是否能连上,所以JDBC代码必须处理SQLException

完整的使用JDBC代码

public class JDBC_Demo2 {
    public static void main(String[] args) {
        Statement sta = null;
        Connection conn = null;
        try {
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //定义sql
            String sql = "insert into player values (1,123)";
            //获取Connection对象
            String url = "jdbc:mysql://localhost:3306/company";
            conn = DriverManager.getConnection(url,"root","niit");
            //获取执行sql的对象
            sta = conn.createStatement();
            //执行sql
            int count = sta.executeUpdate(sql);
            //处理结果
            System.out.println(count);
            if(count > 0)
                System.out.println("添加成功");
            else
                System.out.println("添加失败");

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            if(sta != null) {
                try {
                    sta.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null){
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

public class JDBC_Demo6 {
    public static void main(String[] args) {

        Connection conn = null;
        Statement sta = null;
        ResultSet rs = null;
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            String url = "jdbc:mysql://localhost:3306/company";
            conn = DriverManager.getConnection(url,"root","niit");
            sta = conn.createStatement();
            String sql = "select * from player";

            rs = sta.executeQuery(sql);

            while(rs.next()) {  //判断是否有数据
                int id = rs.getInt(1);
                String name = rs.getString(2);
                System.out.print(id+"\t");
                System.out.println(name);
            }
            rs.first();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }catch (SQLException e) {
            e.printStackTrace();
        }finally {
            if(rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(sta != null) {
                try {
                    sta.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if(conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

管理数据库事务

什么是事务

事务作为一个单元执行的一组SQL语句,只有当所有的SQL语句都执行成功,事务才完成,如果任意一个SQL语句执行失败,则整个事务回滚执行前的状态,它的目的是保证数据的一致性。

提交事务

Connection类提供了两种提交事务的方式:

隐式:当一组SQL语句执行完毕后,默认自动提交事务

显式:当一组SQL语句执行完毕后,手动调用commit()方法提交事务,这需要先将提交模式变更为手动,通过Connection类,con.setAutoCommit(false);来变更提交模式为手动

回滚事务

如果在提交之前,事务执行失败,虽然之前的所有SQL语句都没有执行效果,但此时数据库中的表被锁定,导致其他程序无法提交,为了避免这类问题,必须快速回滚,通过Connection类,con.rollback();