Servlet&JSP的那些事儿(十一)

时间:2021-06-02 21:03:19

作为web开发的一部分,数据库访问也是必不可少的。我们先了解一下JDBC吧。

JDBC

JDBC(java database connectivity,java数据库连接)是应用程序编程接口(API),它描述了一套访问关系数据库的标准java类库。使用这些API,可以连接数据库,然后执行sql语句对数据库进行操作。JDBC也为数据库厂商提供了一个标准的体系结构,厂商可以为自己的产品提供JDBC驱动程序,这些驱动程序就能让java应用程序直接访问他们的数据库产品,从而提高java程序访问数据库的效率。

JDBC驱动程序可以分为四种:JDBC-ODBC桥、部分本地API,部分java驱动程序、JDBC网络纯java驱动程序以及本地协议纯java驱动程序。

1)JDBC-ODBC桥顾名思义,就是用JDBC API调用ODBC去访问数据库,因为ODBC出现的比JDBC早,这适用于数据库产品只提供了ODBC驱动程序的情况,因为它的执行效率比较低。
2)部分本地API,部分java驱动程序即通过java程序调用本地API来实现数据库操作。JDBC API先调用本地API执行操作,执行结果通过本地API返回给JDBC驱动程序,再由JDBC驱动程序将结果转化为JDBC标准形式返回给用户。
3)JDBC网络纯java驱动程序利用作为中间件的应用服务器来访问数据库。
4)本地协议纯java驱动程序通过与数据库建立直接的套接字连接,采用具体于缠上的网络协议把JDBC API调用转化为直接的网络调用。这种驱动程序效率是最高的。

如何安装数据库在这里就不再赘述了。本文采用的是MySql数据库。下载地址为:点击打开链接

windows环境下有直接的安装器,还需要下载连接器。下载后安装与配置即可。(不会的话谷歌之~)

JDBC API

JDBC API包含在JDK中,被分为两个包:java.sql和javax.sql。java.sql包定义了访问数据库的接口和类。我们先看看访问数据库的过程 :

1)加载并注册数据库驱动
2)建立到数据库的连接
3)访问数据库

代码示例为:

Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManger.getConnection("jdbc:mysql://localhost:3306/book","root","shan");
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select * form books");
加载并注册数据库驱动

java.sql.Driver接口是所有JDBC驱动程序需要实现的接口,它是给数据库厂商使用的,不同厂商实现该接口的类名是不同的。mysql实现Driver接口的类名为:com.mysql.jdbc.Driver。加载JDBC驱动是调用Class类的静态方法forName(),向其传递要加载的JDBC驱动的类名。在运行时,类加载器从CLASSPATH环境变量中定位和加载JDBC驱动类。加载驱动类后,会注册一个驱动类的实例。

建立到数据库的连接

我们在程序中不需要直接去访问实现了Driver接口的驱动类,而是由驱动管理程序来管理这些驱动。Driver接口中提供了一个Connect()方法,用来建立到数据库的连接。在建立连接时,我们使用DriverManager类(驱动管理程序)的getConnection()方法建立到数据库的连接,它返回一个Connection对象。DriverManager类提供了三个重载的getConnection()方法。如下所示:

public static Conection getConnection(String url) throws SQLException;
public static Conection getConnection(String url, String user, String passwd) throws SQLException;
public static Conection getConnection(String url, Properties info) throws SQLException;
url为数据库的url。整个url用冒号:分成三部分:协议、子协议和子名称。语法为:jdbc:subprotocol:subname。jdbc标识协议,子协议用于标识一个数据库驱动程序,子名称的语法与具体驱动程序有关。mysql的数据库url为:jdbc:mysql://localhost:3306/databasename。

user为用户名,passwd为密码。Properties包含了用于特定数据库所需要的参数,以键-值对的形式给定连接参数。

访问数据库

建立连接以后,我们就可以访问数据库了。java.sql包中给定了3个接口:Statement、PreparedStatement、CallableStatement。这三个接口分别定义了对数据库访问的不同方式。

1)Statement

Connection中定义了createStatement()方法,用于创建一个Statement对象。Statement对象用于执行静态的sql语句,返回执行的结果。Statement接口中定义了executeQuery(String sql)来执行sql语句,并返回一个ResultSet类型的结果。executeUpdate(String sql)用于执行insert,update或delete语句。execute(String sql)方法执行返回多个结果集的sql语句。

2)ResultSet

Statement接口中的executeQuery(String sql)方法返回一个ResultSet类型的结果。ResultSet对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可通过ResultSet对象的next()方法移动游标到下一行。ResultSet接口中还定义了如getInt()、getString()等方法。可获取当前行中列的数据。

3)PreparedStatement

我们在程序中传递的sql语句在执行前必须被预编译,然后才能被数据库引擎执行。如果重复执行只有参数不同的sql语句,比较低效。而如果你要用不同的参数来多次执行同一个sql语句,可以使用PreparedStatement语句。用法如下:

PreparedStatement pstmt = conn.prepareStatement("insert student values (?,?)");

pstmt.setInt(1,1);
pstmt.setString(2,"shan");
pstmt.executeUpdate();

pstmt.setInt(1,2);
pstmt.setString(2,"dong");
pstmt.executeUpdate();
4)CallableStatement

CallableStatement用于执行sql存储过程。CallableStatement从PreparedStatement继承而来。在执行存储过程之前,凡是存储过程中类型为out的参数都必须被注册。可通过registerOutParameter()方法来完成。用法如下:

CallableStatement cstmt = conn.prepareCall("call p_changesal(?,?)");
cstmt.registerOutParameter(2,java.sql.Types.INTEGER);
cstmt.setInt(1,1234);
cstmt.execute();
int price = cstmt.getInt(2);
5)元数据

我们可能需要获取数据库表本身的信息。可以使用ResultSet对象的getMetaData()方法来得到ResultSetMetaData对象。ResultSetMetaData对象中定义了一些常用的方法,如getColumnCount(),getColumnDisplaySize(),getColunmName()等。

事务处理

如果网上购物的支付功能,用户进入结算中心,确认订单后,程序会获取单价和数目,然后计算总价,然后计算用户余额是否足够支付,之后更新货物数据。不过就在此时,服务器崩溃了,重新启动后,发现货物数目减少了,但收入却没有增加。因为更新用户余额的操作因为故障没有操作。要解决这种问题,就需要事务处理机制。

事务是指构成单个逻辑单元的操作集合。事务处理保证所有事务都作为一个工作单元来执行,即使出现硬件故障或系统失灵,也不能改变这种执行方式。为了将多个sql语句作为一个事务处理,需要调用Connection对象的setAutoCommit()方法,传入false来取消自动提交事务。在所有sql语句执行成功后,调用commit()方法提交,或者在出错时,调用rollback()方法来回滚(就是回到初始状态)。关于事务处理的具体概念,请参考数据库书籍理解。

JDBC数据源和连接池

前面我们讲到了连接数据库的一种方式。现在我们继续讲另外一种方式。在javax.sql包中,定义了DataSource接口,它为我们提供了另外一种连接方式。利用DataSource来建立数据库连接,不需要加载驱动,不需要使用管理类。在程序中,会通过向一个JNDI(java name and directory)服务器查询来得到DataSource对象,然后调用DataSource对象的getConnection()方法来建立数据库连接。使用方法如下:

javax.nameing.Context context = new javax.naming.InitialContext();
//lookup用来查询一个命名对象
javax.sql.DataSource ds = (javax.sql.DataSource)context.lookup("java:comp/env/jdbc/book");
java.sql.Connection conn = ds.getConnection();

conn.close();

java:comp/env是环境命名上下文(Environment Naming Context,ENC),引入它是为了解决JNDI命名冲突的问题。ENC将资源引用名与实际的JNDI名分开,从而提高了J2EE应用的移植性。

什么是连接池?

由于建立数据库连接相当耗时和耗费资源,而且一个数据库服务器能够同时建立的连接数目也是有限的,在大型web应用中,可能同时有上千个访问数据库的请求。如果数据库为每个用户建立连接,那性能会急剧下降。为了能够重复利用数据库连接,提高请求的性能,所以采用连接池技术。它预先建立多个数据库连接对象,然后将连接对象保存到连接池中,当用户请求到来,从池中取出一个连接对象为用户服务,请求完成后,用户程序调用close()方法,将连接对象放回池内。

tomcat提供了数据源和连接池的实现。在tomcat中,可以在<context>元素的内容中使用<Resource>元素来配置JDBC数据源。

转载请注明出处:http://blog.csdn.net/iAm333