JDBC 知识整理
数据持久化:
- 持久化(persistence):把数据保存到可掉电式存储设备中以供之后使用。大多数情况下,特别是企业级应用,数据持久化意味着将内存中的数据保存到硬盘加以“固化”,而持久化的实现过程大多通过各种关系数据库来完成。
- 持久化的主要应用是将内存中的数据存储在关系型数据库中,当然也可以存储在磁盘文件、XML数据文件中。
Java中的数据存储技术:
-JDBC直接访问数据库
-JDO技术
-第三方O/R工具,如Hibernate,ibatis等
- JDBC是java访问数据库的基石,JDO,Hibernate等只是更好的封装了JDBC。
JDBC基础:
- JDBC(Java Data Base Connectivity,java数据库连接)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,使用这个类库可以以一种标准的方法,方便地访问数据库资源。
- JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。
- JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
- JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。
JDBC体系结构:
-面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
-面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。
数据库驱动:
- 我们安装好数据库之后,我们的应用程序也是不能直接使用数据库的,必须要通过相应的数据库驱动程序,通过驱动程序去和数据库打交道。其实也就是数据库厂商的JDBC接口实现,即对Connection等接口的实现类的jar文件。
|---->MySQL驱动---->MySQL
应用程序---->JDBC---->|
|---->Oracle驱动---->Oracle
JDBC驱动程序分类:
- JDBC驱动程序:各个数据库厂商根据JDBC的规范制作的JDBC实现类的类库
- JDBC驱动程序总共有四种类型:
-第一类:JDBC-ODBC桥。
-第二类:部分本地API部分Java的驱动程序。
-第三类:JDBC网络纯Java驱动程序。
-第四类:本地协议的纯Java驱动程序。
-第三、第四类都是纯Java的驱动程序,因此,对于Java开发者来说,他们在性能、可移植性、功能等方面都有优势。
ODBC:
- 早期对数据库的访问,都是调用数据库厂商提供的专有的API。为了在Windows平台下提供统一的访问方式,微软推出了ODBC(Open Data Base Connectivity,开放式数据库连接),并提供了ODBC API,使用者在程序中只需要调用ODBC API,由ODBC驱动程序将调用转换为对特定的数据库的调用请求。
- 一个基于ODBC的应用程序对数据库的操作不依赖任何DBMS(Data Base Manager System,数据库管理系统),不直接与DBMS打交道,所有的数据库操作由对应的DBMS的ODBC驱动程序完成。也就是说,不论是FoxPro、Access,MySql还是Oracle数据库,均可用ODBC API进行访问。由此可见,ODBC的最大优点是能以统一的方式处理所有的数据。
JDBC-ODBC桥:
Java应用程序 ---> JDBC API ---> JDBC-ODBC桥 ---> ODBC API ---> ODBC层 ---> 数据库
- JDBC-ODBC桥本身也是一个驱动,利用这个驱动,可以使用JDBC-API通过ODBC去访问数据库。这种机制实际上是把标准的JDBC调用转换成相应的ODBC调用,并通过ODBC访问数据库
- 因为需要通过多层调用,所以利用JDBC-ODBC桥访问数据库的效率较低。
- 在JDK中,提供了JDBC-ODBC桥的实现类(sun.jdbc.odbc.JdbcOdbcDriver)
部分本地API部分Java的驱动程序:
Java应用程序 ---> JDBC API ---> JDBC驱动程序 ---> 厂商提供的本地API ---> 数据库
- 这种类型的JDBC驱动程序使用Java编写,它调用数据库厂商提供的本地API。
- 通过这种类型的JDBC驱动程序访问数据库减少了ODBC的调用环节,提高了数据库访问的效率。
- 在这种方式下需要在客户的机器上安装本地JDBC驱动程序和特定厂商的本地API。
JDBC网络纯Java驱动程序:
Java应用程序 ---> JDBC API ---> JDBC驱动程序 ---> 应用服务器 ---> 厂商提供的本地API ---> 数据库
- 这种驱动利用中间件的应用服务器来访问数据库。应用服务器作为一个到多个数据库的网关客户端通过它可以连接到不同的数据库服务器
- 应用服务器通常有自己的网络协议,Java用户程序通过JDBC驱动程序将JDBC调用发送给应用服务器,应用服务器使用本地程序驱动访问数据库,从而完成请求
本地协议的纯Java驱动程序
Java应用程序 ---> JDBC API ---> JDBC驱动程序 ---> 数据库
- 多数数据库厂商已经支持允许客户程序通过网络直接与数据库通信的网络协议。
- 这种类型的驱动程序完全使用Java编写,通过与数据库建立的Socket连接,采用具体与厂商的网络协议把JDBC调用转换为直接连接的网络调用。
JDBC API:
- JDBC API是一系列的接口,它使得应用程序能够进行数据库连接,执行SQL语句,并且得到返回结果。
常用接口:
Java.sql.Driver接口是所有JDBC驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。
在程序中不需要直接去访问实现了Driver接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。
由数据库厂家提供,作为java开发人员,只需要使用Driver接口就可以了。在编程中要连接数据库,必须先装载特定厂商的数据库驱动程序,不同的数据库有不同的装载方法。如:
-装载MySql驱动:Class.forName("com.mysql.jdbc.Driver");
-装载Oracle驱动:Class.forName("oracle.jdbc.driver.OracleDriver");
Connection与特定数据库的连接(会话),在连接上下文中执行sql语句并返回结果。DriverManager.getConnection(url,user,password)方法建立在JDBC URL中定义的数据库Connection连接上。
- JDBC URL的写法各个数据库不一样。它的标准由三部分组成,各部分用冒号分隔。如:
jdbc:mysql://localhost:3306/test
<协议>:<子协议>:<子名称>/<目标数据库名称>
-协议:JDBC URL中的协议总是jdbc
-子协议:子协议用于标识一个数据库驱动程序,如mysql,Oracle等
-子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用字名称的目的是为了定位数据库提供足够的信息。
-连接MySql数据库:
Connection conn = DriverManager.getConnection("jdbc:mysql://host:port/database","user","password");
-连接Oracle数据库:
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@host:port:database","user","password");
-连接SQLServer数据库:
Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://host:port;DatabaseName=database","user","password");
·Statement接口:
·用于执行静态SQL语句并返回它所生成结果的对象。
·ResultSet接口:
·ResultSet提供检索不同类型字段的方法
·ResultSet还提供了对结果进行滚动的方法
·使用后依次关闭对象及连接:ResultSet --> Statement --> Connection
使用JDBC的步骤:
加载JDBC驱动程序 --> 建立数据库连接Connection --> 创建执行SQL的语句Statement --> 处理执行结果ResultSet --> 释放资源
1.注册驱动(static代码块,只执行一次)
·方式一:Class.forName("com.MySQL.jdbc.Driver");推荐这种方式,不会对具体的驱动类产生依赖。
·方式二:DriverManager.registerDriver(com.mysql.jdbc.Driver);会造成DriverManager中产生两个一样的驱动,并会对具体的驱动类产生依赖。
·方式三:System.getProperty("jdbc.drivers","driver1:driver2");虽然不会对具体的驱动类产生依赖,但是注册较麻烦,所以很少使用。
2.建立连接:
Connection conn = DriverManager.getConnection(url,user,password);
JDBC URL用于标识一个被注册的驱动程序,驱动程序管理器通过这个URL选择正确的驱动程序,从而建立到数据库的连接。
其它参数如:useUnicode=true&characterEncoding=utf-8
3.创建执行SQL语句的statement
Statement state = conn.createStatement();
String id="5";
String sql="delete from table where id=" + id;
Statement st = conn.createStatement();
st.executeQuery(sql);
//存在sql注入的危险,如果用户传入的id为“5 or 1=1”,那么将删除表中的所有记录
·SQL注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的SQL语句段或命令,从而利用系统的SQL引擎完成恶意行为的做法。
·对于Java而言,要防范SQL注入,只要用PreparedStatement取代Statement就可以了。
PreparedStatement:
·可以通过调用Connection对象的preparedStatrement()方法获取PreparedStatement对象。
·PreparedStatement接口是Statement的子接口,它表示一条预编译过的SQL语句。
·PreparedStatement对象所代表的SQL语句中的参数用问号(?)来表示,调用PreparedStatement对象的setXXX()方法来设置这些参数,
setXXX()方法有两个参数,第一个参数是要设置的SQL语句中的参数的索引(从1开始),第二个是设置的SQL语句中的参数的值。
PreparedStatement有效地防止sql注入(SQL语句在程序运行前已经进行了预编译,当运行时动态地把参数传给PrepareStatement时,即使参数里
有敏感字符如 or '1=1',数据库也会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令。
String sql = "insert into user(name,pwd) value(?,?)";
PreparedStatement ps = conn.preparedStatement(sql);
ps.setString(1,"col_value");//占位符顺序从1开始
ps.setString(2,"123456");//也可以使用setObject
ps.executeQuery();
PreparedStatement VS Statement:
·代码的可读性和可维护性
·PreparedStatement能最大可能提高性能:
-DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,
那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
-在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义,事实是没有数据库会对普通
语句编译后的执行代码缓存,这样每执行一次都要对传入的语句编译一次。
-(语法检查,语义检查,翻译成二进制命令,缓存)
·PreparedStatement可以防止SQL注入
4.处理执行结果(ResultSet):
ResultSet rs = ps.executeQuery();
while(rs.next()){
rs.getString("col_name");
rs.getInt(1);
}
5.释放资源
//数据库连接(Connection)非常耗资源,尽量晚创建,早释放;都要加try catch 以防前面关闭出错,后面的就不执行了
try{
if(rs != null){
rs.close();
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try{
if(st != null){
st.close();
}
}catch(SQLException e){
e.printStackTrace();
}finally{
try{
if(conn != null){
conn.close();
}
}catch(SQLException e){
e.printStackTrace();
}
}
}
事务(ACID特点、隔离级别、提交commit、回滚rollback):
·事务基本概念:
-在数据库中,所谓事务是指一组逻辑操作单元,使数据从一种状态变换到另一种状态。
-为确保数据库中数据的一致性,数据的操作应当是离散的成组的逻辑单元:当它全部完成时,数据的一致性可以保持,而当这个单元中的一部分操作失败,
整个事务应全部视为错误,所有从起始点以后的操作应全部回退到开始状态。
-事务的操作:先定义开始一个事务,然后对数据作修改操作,这时如果提交(commit),这些修改就永久地保存下来,如果回退(rollback),数据库
管理系统将放弃所作的所有修改而回到开始事务时的状态。
-事务开始于:
·连接到数据库上,并执行一条DML语句(INSERT、UPDATE或DELETE)。
·前一个事务结束后,又输入了另外一条DML语句
-事务结束于:
·执行COMMIT或ROLLBACK语句。
·执行一条DDL语句,例如CREATE TABLE语句;在这种情况下,会自动执行COMMIT语句。
·执行一条DCL语句,例如GRANT语句;在这种情况下,会自动执行COMMIT语句。
·断开与数据库的连接
·执行了一条DML语句,该语句却失败了;在这种情况中,会为这个无效的DML语句执行ROLLBACK语句。
-事务处理:保证所有事务都作为一个工作单元来执行,即使出现了故障,都不能改变这种执行方式。当在一个事务中执行多个操作时,要么所有的事务都被
提交(commit),要么整个事务回滚(rollback)到最初状态。
-当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
-为了让多个SQL语句作为一个事务执行:
·调用Connection对象的setAutoCommit(false);以取消自动提交事务;
·在所有的SQL语句都成功执行后,调用commit();方法提交事务;
·在出现异常时,调用rollback();方法回滚事务;
·若此时Connection没有被关闭,则需要恢复其自动提交状态。
·事务的四大特点(ACID):
-atomicity(原子性):
·事务是一个不可分割的工作单位,一个事务内的所有操作是一个整体,要么全部成功,要么全部失败;
-consistency(一致性):
·事务必须使数据库从一个一致性变换到另外一个一致性状态,当一个事务内有一个操作失败时,所有的更改过的数据都必须回滚到修改前的状态;
-isolation(隔离性):
·事务的隔离性是指一个事务的执行不能被其它事务所干扰,即一个事务内部的操作及使用的数据对并发的其它事务是隔离的,并发执行的各个事务之间
不能互相干扰;也可以认为事务查看数据时数据所处的状态,要么是另一并发事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看
中间状态的数据;
-durability(持久性):
·持久性是指一个事务一旦被提交,它对数据库中数据的改变是永久性的,接下来的其他操作和数据库故障不应该对其有任何影响。
数据库的隔离级别:
·对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:
-脏读:对于两个事务 T1、T2,T1 读取了已经被 T2 更新但还没有被提交的字段,之后,若 T2 回滚, T1 读取的内容就是临时且无效的。
-不可重复读:对于两个事务 T1、T2,T1 读取了一个字段,然后 T2 更新了该字段。之后,T1 再次读取同一个字段,值就不同了。
-幻读:对于两个事务 T1、T2,T1 从一个表中读取了一个字段,然后 T2 在该表中插入了一些新的行。之后,如果 T1 再次读取同一个表,就会多出几行。
·数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题。事务隔离级别从低到高如下:
-读取未提交(Read Uncommitted):允许事务读取未被其它事务提交的变更,脏读、不可重复读和幻读的问题都会出现;
-读取已提交(Read Committed):只允许事务读取已经被其它事务提交的变更,可以避免脏读,但不可重复读和幻读问题仍然可能出现;
-可重复读(Repeatable Read):确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其他事务对这个字段进行更新,可以避免脏读
和不可重复读,但幻读的问题仍然存在;
-序列化(serializable):确保事务可以从一个表中读取相同的行,在这个事务持续期间,禁止其他事务对该表执行植入,更新和删除操作,所有并发问题
都可以避免,但性能十分低下。
·一个事务与其它事务隔离的程度称为隔离级别。数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。
-Oracle支持2种事务隔离级别:read commited(读取已提交)、serializable(序列化)。oracle默认的事务隔离级别为:read commited。
-Mysql支持4种事务隔离级别。MySQL默认的事务隔离级别为:repeatable read(可重复读)。
·在MySql中设置隔离级别:
·每启动一个MySQL程序,就会获得一个单独的数据库连接,每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。
·查看当前的隔离级别:select @@tx_isolation
·设置当前MySQL连接的隔离级别:set transaction isolation level read committed;
·设置数据库系统的全局的隔离级别:set global trasaction isolation level read committed;
使用JDBC驱动程序处理元数据:
·Java通过JDBC获得连接以后,得到一个Connection对象,可以从这个对象获得有关数据库管理系统的各种信息,包括数据库中的各个表,表中的各个列,数据类型,
触发器,存储过程等各方面的信息。根据这些信息,JDBC可以访问一个实现事先并不了解的数据库。
·获取这些信息的方法都是在DatabasMetaData类的对象上实现的,而DatabaseMetaData对象是在Connection对象上获得的。
DatabaseMetaData类:
·DatabaseMetaData类中提供了许多方法用于获得数据源的各种信息,通过这些方法可以非常详细地了解数据库的信息:
-getURL():返回一个String类对象,代表数据库的URL;
-getUserName():返回连接当前数据库管理系统的用户名;
-isReadOnly():返回一个boolean值,指示数据库是否只允许读操作;
-getDatabaseProductName():返回数据库的产品名称;
-getDatabaseProductVersion():返回数据库的版本号;
-getDriverName():返回驱动程序的名称;
-getDriverVersion():返回驱动程序的版本号。
ResultSetMetaData类:
·可用于获取关于ResultSet对象中列的类型和属性信息的对象:
-getColumnName(int column):获取指定列的名称
-getColumnCount():返回当前ResultSet对象中的列数。
-getColumnTypeName(int column):检索指定列的数据库特定的类型名称
-getColumnDisplaySize(int column):指示指定列的最大标准宽度,以字符为单位。
-isNullable(int column):指示指定列中的值是否可以为null。
-isAutoIncrement(int column):指示是否自动为指定列进行编号,这样这些列仍然是可读的。
Oracle LOB:
·LOB,即Large Objects(大对象),是用来存储大量的二进制和文本数据的一种数据类型(一个LOB字段可存储多达4GB的数据)。
·LOB分为两种类型:内部LOB和外部LOB。
-内部LOB将数据以字节流的形式存储在数据库的内部。因而,内部LOB的许多操作都可以参与事务,也可以像处理普通数据一样对其进行备份和恢复操作。
Oracle支持三种类型的内部LOB:
·BLOB(二进制数据)
·CLOB(单字节字符数据)
·NCLOB(多字节字符数据)
-CLOB和NCLOB类型适用于存储超长的文本数据,BLOB字段适用于存储大量的二进制数据,如图像、视频、音频,文件等。
-目前只支持一种外部LOB类型,即BFILE类型。在数据库内,该类型仅存储数据在操作系统中的位置信息,而数据的实体以外部文件的形式存在于操作系统的
文件系统中。因而,该类型所表示的数据是只读的,不参与事务。该类型可帮助用户管理大量的由外部程序访问的文件。
MySQL BLOB类型介绍:
·MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。
·MySQL的四种BLOB类型(除了在存储的最大信息量上不同外,他们是等同的)
类型 大小(单位:字节)
TinyBlob 最大 255
Blob 最大 65 K 或 65535
MediumBlob 最大 16 M 或 16777215
LongBlob 最大 4 G 或 4294967295
·实际使用中根据需要存入的数据大小定义不同的BLOB类型。
·需要注意的是:如果存储的文件过大,数据库的性能会下降。
使用JDBC来写入BLOB类型数据到Oracle中:
·oracle的blob字段比long字段的性能要好,可以用来保存如图片之类的二进制数据。
·oracle的blob字段由两部分组成:数据(值)和指向数据的指针(定位器)。
尽管值与表自身一起存储,但是一个Blob列并不包含值,仅有它的定位指针。为了使用大对象,程序必须声明定位器类型的本地变量。
·当Oracle内部LOB被创建时,定位器被存放在列中,值被存放在LOB段中,LOB端是在数据库内部表的一部分。
·因为Blob自身有一个cursor,当写入Blob字段必须使用指针(定位器)对Blob进行操作,因而在写入Blob之前,必须获得指针(定位器)才能进行写入
·如何获得Blob的指针(定位器):需要先插入一个empty的blob,这将创建一个blob的指针,然后再把这个empty的blob的指针查询出来,这样通过两步操作,
就获得了blob的指针,可以真正的写入blob数据了。
使用BLOB的步骤:
1.插入空blob:
insert into javatest(name,content) values (?,empty_blob());
2.获得blob的cursor
select content from javatest where name = ? for update;
·注意:必须加 for update,锁定该行,直至该行被修改完毕,保证不产生并发冲突。
3.利用 io ,和获取到的 cursor 往数据库写数据流。
批量处理JDBC语句提高处理速度:
·当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率;
·JDBC的批量处理语句包括下面两个方法:
-addBatch(String):添加需要批量处理的SQL语句或是参数;
-executeBatch():执行批量处理语句;
·通常我们会遇到两种批量执行SQL语句的情况:
-多条SQL语句的批量处理;
-一个SQL语句的批量传参;
JDBC数据库连接池的必要性:
·在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤:
-在主程序(servlet、beans)中建立数据库连接。
-进行sql操作
-断开数据库连接
·这种模式开发,存在的问题:
-普通的JDBC数据库连接使用 DriverManager 来获取,每次向数据库建立连接的时候都要将 Connection加载到内存中,再验证用户名和密码
(得花费0.05s ~ 1s 的时间)。需要数据库连接的时候,就向数据库要求一个,执行完成后再断开连接。这样的方式将消耗大量的资源和时间。
数据库的连接资源并没有得到很好的重复利用。若同时有几百人甚至几千人在线,频繁地进行数据库连接操作将占用很多的系统资源,严重的甚至会造成
服务器的崩溃。
-对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄露,最终将导致重启数据库。
-这种开发不能控制被创建的连接对象数,系统资源会被毫无顾忌地分配出去,如连接过多,也可能导致内存泄露,服务器崩溃。
数据库连接池(connection pool):
·为解决传统开发中的数据库连接问题,可以采用数据库连接池技术。
·数据库连接池的基本思想就是为数据库建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,
使用完毕之后再放回去
·数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
·数据库连接池在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数据库是否被使用,
连接池都将一直保证至少拥有那么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池请求的连接数超过
最大连接数量时,这些请求将被加入到等待队列中。
数据库连接池技术的优点:
·资源重用:由于数据库连接得以重用,避免了频繁创建,释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增加了系统运行环境的平稳性。
·更快的系统反应速度:数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于连接池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,
直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统的响应时间。
·新的资源分配手段:对于多应用共享同一数据库的系统而言,可在应用层通用数据库连接池的配置,实现某一应用最大可用数据库连接数的限制,避免某一应用
独占所有的数据库资源。
·统一的连接管理,避免数据库连接泄露:在较为完善的数据库连接池实现中,可根据预先的占用超时设定,强制回收被占用连接,从而避免了常规数据连接操作中
可能出现的资源泄露。
两种开源的数据库连接池:
·JDBC的数据库连接池使用javax.sql.DataSource来表示,DataSource只是一个接口,该接口通常由服务器(Weblogic,WebSphere,Tomcat)
提供实现,也有一些开源组织提供实现:
-DBCP 数据库连接池
-C3P0 数据库连接池
·DataSource通常被称为数据源,它包含连接池和连接池管理两个部分,习惯上也经常把DataSource称为连接池。
DBCP数据源:
·DBCP 是Apache软件基金组织下的开源连接池实现,该连接池依赖该组织下的另一个开源系统:Common-pool。如需使用该连接池实现,应在系统中
增加如下两个jar文件:
-Commons-dbcp.jar:连接池的实现
-Commons-pool.jar:连接池实现的依赖库
·Tomcat的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可以由应用程序独立使用。
DBCP数据源使用范例:
·数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。
·当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close();但上面的代码并没有关闭数据库的物理连接,它仅仅把数据库连接释放,
归还给了数据库连接池。
DBCP数据源和C3P0数据源对比:
DBCP数据源 C3P0数据源
创建数据源对象
BasicDataSource bds = new BasicDataSource(); CombopooledDataSource cds = new CombopooledDataSource();
设置连接数据库的驱动
bds.setDriverClassName("com.mysql.jdbc.Driver"); cds.setDriverClass("com.mysql.jdbc.Driver");
设置连接数据库的url
bds.setUrl("jdbc:mysql://localhost:3306/test"); cds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
设置连接数据库的用户名
bds.setUsername("root"); cds.setUser("root");
设置连接数据库的密码
bds.setPassword("123456"); cds.setPassword("123456");
设置数据库连接池的初始连接数
bds.setInitialSize(5); cds.setInitialPoolSize(10);
设置连接池最多可有多少个活动连接数
bds.setMaxActive(20); cds.setMaxPoolSize(40);
设置连接池中最少有2个空闲连接
bds.setMinIdle(2);
取得连接池连接
bds.getConnection(); cds.getConnection();
Apache-DBUtils简介:
·commons-dbutils是Apache组织提供的一个开源JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的
工作量,完成也不影响程序的性能。
·API介绍:
-org.apache.commons.dbutils.QueryRunner
-org.apache.commons.dbutils.ResultSetHandler
-工具类
·org.apache.commons.dbutils.DbUtils。
DbUtils类:
·DbUtils:提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:
-public static void close(...) throws java.sql.SQLException:DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的
参数是不是NULL,如果不是的话,他们就关闭Connection、Statement和ResultSet。
-public static void closeQuietly(...):这一类方法不仅能在Connection、Statement和ResultSet为Null情况下避免关闭,还能
隐藏一些在程序中抛出SQLException。
-public static void commitAndCloseQuietly(Connection conn):用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。
-public static boolean loadDriver(java.lang.String.driverClassName):这一方法装载并注册JDBC驱动程序,如果成功就返回true。
使用该方法,你不需要捕捉这个异常ClassNotFoundException。
QueryRunner类:
·该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
·QueryRunner类提供了两个构造方法:
-默认的构造方法。
-需要一个javax.sql.DataSource来作参数的构造方法
·QueryRunner类的主要方法:
-public Object query(Connection conn,String sql,Object[]params,ResultSetHandler rsh) throws SQLException:
执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为语句的置换参数。该方法会自行处理PreparedStatement和ResultSet的创建和关闭。
-public Object query(String sql,Object[] params,ResultSetHandler rsh) throws SQLException:
几乎与第一种方法一样;唯一的不同在于它不将数据库连接提供给方法,并且它是从提供给构造方法的数据源(DataSource)或使用的setDataSource方法中重新获得Connection。
-public Object query(Connection conn,String sql,ResultSetHandler rsh) throws SQLException:
执行一个不需要置换参数的查询操作。
-public int update(Connection conn,String sql,Object[] params) throws SQLException:
用来执行一个更新(插入、修改或删除)操作。
-public int update(Connection conn,String sql) throws SQLException:
用来执行一个不需要置换参数的更新操作。
ResultSetHandler接口:
·该接口用于处理java.sql.ResultSet,将数据按要求转换为另一种形式。
·ResultSetHandler接口提供了一个单独的方法:ObjectHandle(java.sql.ResultSet.rs)。
·ResultSetHandler接口的实现类:
-ArrayHandler:把结果集中的第一行数据转换成对象数组
-ArrayListHandler:把结果集中的每一行数据都转成一个数组,再放到List中。
-BeanHandler:把结果集中的第一行数据封装到一个对应的JavaBean实例中。
-BeanListHandler:将结果集中的每一行数据都封装到一个对应的JavaBean实例中,存放到List里。
-ColumnListHandler:将结果集中某一列的数据存放到List中。
-KeyedHandler(name):将结果集中的每一行数据都封装到一个Map里,再把这些map再存放到一个map里,其key为指定的key。
-MapHandler:将结果集中的第一行数据封装到一个Map里,key是列名,value就是对应的值。
-MapListHandler:将结果集中的每一行数据都封装到一个Map里,然后再存放到List里。
数据库的分页语句:
·在编写Web应用程序等系统时,会涉及到与数据库的交互,如果数据库中数据量很大的话,一次检索所有的记录,会占用系统很大的资源,因此常常采用分页语句:
需要多少数据就只从数据库中取多少条记录。
·SQL Server、Oracle和MySQL的分页语句(从数据库中的第M条数据开始取N条记录):top,rownum,limit
·SQL Server数据库分页语句:
-从数据库表中的第M条记录开始取N条记录,利用Top关键字(如果Select语句中既有Top,又有order by,则是从排序好的结果集中选择):
select * from ( select Top N * from (select Top(M+N-1) * from 表名称 order by 主键 desc)t1)t2 order by 主键 asc
-例如从表Sys_option(主键为sys_id)中从第10条记录开始检索20条记录:
select * from ( select Top 20 * from (select Top 29 * from Sys_option order by sys_id desc)t1)t2 order by sys_id asc
·Oracle数据库分页语句:
-从数据库表中的第M条记录开始取N条记录,利用rownum关键字(如果Select语句中既有rownum,又有order by,则是从排序好的结果集中选择):
select * from ( select rownum rownum_,t1. * from (select * from table order by table.id desc)rownum_ where rownum <=M)where rownum_ > N
-例如从表employees(主键为employee_id)中从第10条记录开始检索20条记录:
select * from ( select rownum r_,row. * from (select * from employees order by employee_id desc)row_ where rownum <=20)where r_ >= 10
·MySql数据库分页语句:
-Mysql数据库最简单,是利用MySQL的limit函数,limit[offset]rows从数据库表中M条记录开始检索N条记录的语句为:
select [列名列表] from 表名称 limit M , N;
-例如从表Sys_option(主键为sys_id)中从第10条记录开始检索20条记录:
select * from sys_option limit 10,20;