(十四)JDBC入门


目录


什么是JDBC

JDBC 是一套规范,由许多接口组成,相当于提供了一套协议,大家要怎么怎么做;

JDBC 下层是各家数据的驱动;我们只需要调用 JDBC 提供的接口就好了,至于 JDBC 自己去调用具体的数据库驱动,都经历了什么,这一项不需要我们去关心 ;

需要使用到两个包:java.sql 、javax.sql ;

同时也需要导入具体的数据库驱动 ;(如 mysqloracle 的数据库驱动,这里我给出一个 mysql 的数据库驱动)


操作JDBC的步骤

第一步,加载驱动 ;

第二步:获取数据库连接;

第三步:获取statement对象,以便向数据库发送语句 ;

第四步:向数据库发送语句,并得到 结果集

第五步:从 结果集 中,获得数据 ;

第六步:关闭连接,释放资源 ;


DriverManager对象

JDBC 程序中的 DriverManager 用于加载驱动,并创建与数据库的链接;

这个 API 的常用方法

// 注册驱动
DrverManager regsterDriver(new Driver())
//获取连接
DriverManager getConnect on(url,user,password)

注意:

在实际开发中并不推荐采用 registerDriver 方法注册驱动。

原因有二:

  1. 查看 Driver 的源代码可看到,如果采用此种方式,会导致驱动程序注册两次,在內存中会有2个Driver象。

    public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }
    
    static {
        try {
            // mysql 自己在实现驱动的时候,在加载类的时候,已经把自己注册进去了
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
    }
  2. 程序 importmysql 的驱动。导致程序依赖于 mysqlapi; 脱离 mysqljar 包。

    程序将无法编译,将来程序切换底层数据库将会非常麻烦,要改动许多代码。

推荐方式:

      Class.forName("完整类名") ;

其实在查看了源代码以后, 我们就知道了,就应该这样来加载驱动,驱动类自己在实现的时候,就用了static代码块,让加载自己的时候,就注册自己,厂商也是为了解耦的考虑,才那么写的;

同样在导入 Connection 包的时候,不要带入具体的数据库的包,比如 java.mysql.connection ;

这样程序就牢牢的和mysql绑定在一起了 ;我们直接导入它的父类,java.sql ;这样,无论我们用什么数据库,它的驱动的 Connetion 都是要遵循 java.sql 包下面的 Connection 接口规范 ;

——————————–备注———————————

这个 DriveManger 类,就是服务提供者框架里面的,那个对外提供服务的类 ;

Java.sql.Driver 则是 JDBC 框架对外提供的服务者接口

Driver类 则是 mysql厂商 自己根据 Java.sql.Driver 接口实现的类,就是服务实现者


数据库URL

URL用于标识数据库的位置,程序员通过URL地址告诉JDBC程序连接哪个数据库;

URL的写法为:

jdbc : mysql: [] // localhost : 3306 / 项目名 ? 参数名:参数值

对应关系:

协议 : 子协议 // 主机: 端口 / 数据库

Mysqlurl 地址的简写形式: **jdbc : mysql: /// 数据库名字
**


Connection对象

JDBC 程序中的 Connection,它于代表数据库的链接;

Collection 是数据库编程中最重要的一个对象,客户端与数据库所有交互都是通过 Collection 对象完成的;

这个对象的常用方法:

  • createStatement()

    创建向数据库发送 sqIstatement 对象。

  • prepareStatement("sql语句")

    创建向数据库发送 预编译 sqIPrepareSatement 对象。

  • prepareCall(sql)

    创建执行存储过程的 CallableStatement 对 象。

  • setAutoCommit(boolean autoCommit)

    设置事务是否自动提交。

  • commit()

    在链接上提交事务。

  • rollback():

    在此链接上回滚事务。


Statement对象

Jdbc程序中的 Statement 对象用于向数据库发送 SQL 语句 ;

Statement 对象常用方法:

  • executeQuery(String sql)

    用于向数据发送查询语句。

  • executeUpdate(String sql)

    用于向数据浑发送 insert.update或delete 语句

  • execute(String sql)

    用于向数据库发送任意sq语句

  • addBatch(String sql)

    把多条sql语句放到一个批处理中。

  • executeBatch()

    向数据库发送一批 sql 语句执行。

虽然 execute(); 可以向数据库发送任意SQL语句,但是我们一般不用它,因为它的返回值是 boolean,需要我们去判断,然后再做处理;得不偿失;

executeUpdate(),返回的 int 值,代表影响表中的行数 ;


ResultSet对象

Jdbc 程序中的 ResultSet 用于代表 Sql语句 的执行结果。

ResultSet 封装执行结果时,采用的类似于表格的方式 ResultSet 对象维护了一个指向表格数据行的游标,初始的时候,游标 在第一行之前;

调用 ResutSet.next()方法,可以使游标指向具体的数据行,进行调用方法获取该行的数据。跟集合的迭代器操作是一样的

ResultSet 既然用于封装执行结果,那么该对象提供的都是用于获取数据的 get 方法:


获取任意类型的数据

// 根据游标
getObject(int index)
// 根据字段名 
getObject(String columnName)

获取指定类型的数据

// 根据游标
getString(int index)
getInt(int index)
getDate(int index)
...

// 根据字段名 
getString(String columnName)
getInt(String columnName)
getDate(String columnName)
...

其中 ResultSetgetDate() 方法,返回的是 sql 包下面的 date;但是由于sql.dateutil.date 的子类,因此前者可以直接赋值给后者 ;


常用数据类型转换表

SQL类型 JDBC对应的方法 返回类型
BIT(1) 、 bit(10) getBoolean() 、getBytes() Boolean、Byte[ ]
TINYINT getByte() Byte
SMALLINT getShort() Short
Int getInt() Int
BIGINT getLong() Long
CHAR、VARCHAR、LONGVARCHAR getString() String
Text(clob)、Blob getClob、getBlob() Clob、Blob
DATE getDate() java.sql.Date
TIME getTime() java.sql.Time
TIMESTAMP getTimestamp() java.sql.Timestamp

释放资源

Jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象,这些对象通常是 ResultSet,Statement和Connection 对象。、

特别是 Connection 对象,它是非常稀有的资源,用完后必须马上释放,如果Connection 不能及时、正确的关闭,极易导致系统宅机。

Connection的使用原则:尽量晚创建,尽最早的释放。

为确保资源释放代码能运行,资源释放代码也- 一定要放在finally语句中。


SQL注入

产生的原因:使用 Statement 对象,对 sql 语句不进行任何操作,直接查询;因而,我们可以拼接出一条 where 条件为永真的语句,这样,就可以取到用户;

预防 SQL注入,使用 PreparedStatement 对象 ,它会对sql语句,进行转义,只要发现接受的参数中有sql的符号,就进行转义。然后,再发送给数据库;这样就拼接不出来想要的 sql 语句了;


statementpreparedStatement 对象的区别

  1. preparedStatementStatement 的子类(说是实现类更贴切);
  2. preparedStatement 可以防止 sql注入 的问题 ;
  3. preparedStatement 是编写 sql 语句变得更容易,使用占位符;
  4. preparedStatement 是对 sql 语句进行 预编译 的,可以减轻数据库的压力 ;

关于 预编译 :

我们利用 Statement 发送给数据库的语句,数据库并不是拿到以后,就立马执行的;数据库要先编译以后,再执行; 这样当业务比较大的时候,向数据库发送的语句很多的时候,数据库对每一条语句都要进行编译,这样数据库很难受的,压力很大 ;

而我们使用 preparedStatement 对象,在写代码的时候,就对 sql 语句进行了预编译;这样数据库那边就不再需要进行编译操作,以减轻服务器的压力 ;


关于数据库中时间的问题;

我们需要进行一个 String ——> date 的转换 ;

因为,我们前台页面中接受到的数据,都是字符串,我们要将它们存进数据库的时候,需要将字符串转换成数据库的时间接受的格式 ;

转换代码:

//                如果是日期,则进行日期转换
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    return (T) dateFormat.parse(date);
                } catch (ParseException e) {
//                    打印日志,便于查找错误
                    e.printStackTrace();
//                    发生转换异常了,则报错;
                    throw new RuntimeException(e);
                }

转换完以后的是日期是 java.utils.date 类型的,我们数据库中的 datejava.sql.date 类型的;因此在存进去之前,还需要再转换一下 ;

//            存进去的时候,需要将 java.utils.date 转成 java.sql.date 类型
            statement.setDate(4,new Date(user.getBirthday().getTime()));

从数据库获取时间的时候,是不需要进行转换的,因为 java.utils.datejava.sql.date 的父类。取出的 java.sql.date 类型可以直接赋值给 java.utils.date

//                这里取出的是 java.sql.date 但是由于它是 java.utils.date 因此不用进行转换
                user.setBirthday(resultSet.getDate("birthday"));
原文地址:https://www.cnblogs.com/young-youth/p/11665711.html