数据库应用技术
1、JDBC概念
JDBC(Java Database Connectivity)是一种可用于执行SQL语句的Java API,它为访问相关数据库提供了标准的库。本质上来说就是调用者(程序员)和实现者(数据库厂商)之间的协议。JDBC 的实现由数据库厂商以驱动程序的形式提供。JDBC API 使得开发人员可以使用纯 Java 的方式来连接数据库,并进行操作。
在 JDBC中包括了两个包:java.sql 和 javax.sql。
1)java.sql 基本功能。这个包中的类和接口主要针对基本的数据库编程服务,如生成连接、执行语句以及准备语句和运行批处理查询等。同时也有一些高级的处理,比如批处理更新、事务隔离和可滚动结果集等。
2)javax.sql 扩展功能。它主要为数据库方面的高级操作提供了接口和类。如为连接管理、分布式事务和旧有的连接提供了更好的抽象,它引入了容器管理的连接池、分布式事务和行集等。
JDBC能实现以下3个方面功能:同一个数据库建立连接、向数据库发送SQL语句和处理数据库返回的结果。如图所示为编写JDBC程序的一般过程。
2、JDBC API 常用接口和方法
2.1JDBC常用接口
接口或类 | 说明 |
---|---|
java.sql.Connection | 与特定数据库的连接(会话)。在连接上下文中执行SQL语句并返回结果 |
java.sql.Driver | 每个驱动程序类必须实现的接口。Java SQL框架允许多个数据库驱动程序。每个驱动程序都应该提供一个实现Driver接口的类。 |
java.sql.DriverManager | 管理一组JDBC驱动程序的基本服务 |
java.sql.Statement | 用于执行静态SQL语句并返回它所生成结果的对象 |
java.sql.PreparedStatement | 表示预编译的SQL语句的对象。SQL语句被预编译并存储在PreparedStatement 对象中,然后可以使用此对象多次高效地执行该语句 |
java.sql.CallableStatement | 用于执行SQL存储过程的接口 |
java.sql.ResultSet | 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成 |
java.sql.ResuletSetMetaData | 可用于获取关于ResultSet对象中列的类型和属性信息的对象 |
2.2、驱动程序管理器 DriverManager
常用方法
方法 | 说明 |
---|---|
getConnection(String url) | 根据指定数据库连接URL建立与数据库的连接,参数url为数据库连接URL |
getConnection(String url, String username, String password) | 根据指定数据库连接URL、username及password建立与数据库的连接,参数url为数据库连接URL,username为数据库的用户名,password为数据库的密码 |
getConnection(String url, Properties info) | 根据指定数据库连接URL及数据库连接属性建立与数据库的连接,参数url为数据库连接URL,info为连接属性 |
setLoginTimeout(int seconds) | 设置要进行登录时驱动程序等待的超时时间。 |
deregisterDriver(Driver driver) | 从DriverManager的管理列表中删除一个驱动程序,参数driver为要删除的驱动对象 |
registerDriver(Driver driver) | 向DriverManager注册一个驱动程序,参数driver为要注册的驱动对象 |
2.3、数据库连接接口Connection
Connection是与数据库连接对象,一个应用程序可与单个数据库有一个或多个连接,或者与多个数据库有多个连接。打开连接对象与数据库建立连接的标准方法是
Connection con=DriverManager.getConnection("URI","用户名","口令");
例:
String uri = "jdbc:mysql://localhost:3306/school2";
String user = "root";
String password = "root";
Connection con = DriverManager.getConnection(uri, user, password);
使用Connection与数据库建立连接,使用完毕后必须关闭它。
代码:
con.close();
2.4、执行SQL语句接口Statement
JDBC提供了3种接口来实现SQL语句的发送执行,它们分别是Statement、PreparedStatement(继承Statement)、CallableStatement(继承PreparedStatement)。它们都用于发送特定类型的SQL语句,Statement对象用于执行不带参数的简单SQL语句;PreparedStatement对象用于执行带或不带IN参数的预编译SQL语句;CallableStatement对象用于执行对数据库中存储过程。
使用Statement类来发送执行SQL语句首先要创建Statement对象实例。建立Statement类对象可以通过Connection类中createStatement()方法创建。
方法1:Statement createStatement()throws SQLException
方法2:Statement createStatement(int resultSetType,int resultSetConcurrency) throws SQLException
其中resultSetType参数有三个取值:
1)ResultSet.TYPE_FORWARD_ONLY 当前结果集游标只能向下滚动。
2)ResultSet.TYPE_SCROLL_INSENSITIVE 游标可以上下滚动,数据库变化时,当前结果集不变。
3)ResultSet.TYPE_SCROLL_SENSITIVE 游标可以上下滚动,数据库变化时,结果集随之变动。
resultSetConcurrency用来指定是否可以使用结果集更新数据库,它有两个取值:
1)ResultSet.CONCUR_READ_ONLY:不能用结果集更新数据库中的表
2)ResultSet.CONCUR_UPDATABLE: 能用结果集更新数据库中的表
例:
Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
创建好Statement对象后,就可以利用它提供的executeQuery()方法来执行一个产生单个结果集的查询语句,它返回一个ResultSet 对象。
ResultSet executeQuery(String sql) throws SQLException
例:
ResultSet rs = stmt.executeQuery("SELECT * FROM course");
整合例子:
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/databasename", "root", "123456");
Statement statement = connection.createStatement();
String sql = "SELECT * FROM course";
ResultSet rs = statement.executeQuery(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Statement接口常用方法
方法 | 说明 |
---|---|
Boolean execute(String sql) | 执行给定的SQL语句,该语句可能返回多个结果 |
void close() | 释放此对象的数据库和JDBC资源 |
ResultSet executeQuery(String sql) | 执行给定的SQL语句,该语句返回单个ResultSet对象 |
int executeUpdate(String sql) | 执行给定的SQL语句,该语句可能为insert、update或delete语句,或者不返回任何内容的SQL语句(如SQL DDL语句) |
ResultSet getResultSet() | 以ResultSet对象的形式获取当前结果,每个结果只应调用一次此方法 |
Connection getConnection() | 获取生成此Statement对象的Connection对象。 |
使用Statement的方法时,语句可能返回或不返回ResultSet对象。
如果是查询语句,通常使用executeQuery(String sql);
如果是修改、插入或删除语句,通常使用executeUpdate(String sql);
2.5、执行动态SQL语句接口PreparedStatement
PreparedStatement继承于Statement,PreparedStatement对象包含以编译的SQL语句,执行速度比Statement。
使用PreparedStatement类,它执行的SQL语句可以包含一个或多个IN参数。所谓IN参数指那些在SQL语句创立时尚未指定值的参数,在SQL语句中IN参数的值用(“?”)代替。建立PreparedStatement类对象可以通过Connection类中prepareStatement()方法创建。
方法1:PreparedStatement prepareStatement(String sql) throws SQLException
方法2:PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
例:
PreparedStatement pstmt;
pstmt = con.prepareStatement("SELECT * FROM course where tno=?",ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
在PreparedStatement对象执行前,每一个IN参数都必须设置值,通过setXXX()方法来实现,其中XXX表示各种数据类型名。如IN参数为integer类型,则可用setInt()方法设置它。
如pstmt.setString(1,“825”);其中1表示参数位置,“825”表示参数值。
设置好IN参数后,执行查询使用executeQuery()方法。代码如下:
ResultSet rs;
rs = pstmt.executeQuery();
整合例子:
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/databasename", "root", "123456");
String sql = "insert into values(?,?,?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 6);
preparedStatement.setString(2, "l");
preparedStatement.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
executeUpdate()返回执行后所更新的数据库中记录的行数。
2.6、执行存储过程接口CallableStatement
使用CallableStatement对象用于执行对数据库中存储过程。建立CallableStatement类对象可以通过Connection类中prepareCall()方法创建。
方法1:CallableStatement prepareCall(String sql) throws SQLException
方法2:CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException
例:
CallableStatement callstmt;
ResultSet rs;
callstmt = con.prepareCall("call stud_degree()",
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
rs = callstmt.executeQuery();
例:
try {
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/databasename", "root", "123456");
String sql = "insert into values(?,?,?,?)";
CallableStatement callableStatement = connection.prepareCall(sql);
callableStatement.setString(1, "li");
callableStatement.setInt(2, 1);
callableStatement.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
2.7、访问结果集接口ResultSet
ResultSet接口常用方法
方法 | 说明 |
---|---|
Boolean absolute(int row) | 将光标移动到此ResultSet对象的给定行编号,参数row为正时从结果集第一行开始编号,为负时从结果集最后一行开始编号 |
void close() | 释放此对象的数据库和JDBC资源 |
boolean next() | 将光标从当前位置向前移一行。ResultSet光标最长位于第一行之前;第一次调用使第一行成为当前行;第二次调用使第二行成为当前行。 |
int getInt() | 以int的形式获取此ResultSet对象的当前行中指定列的值 |
Long getLong() | 以long的形式获取此ResultSet对象的当前行中指定列的值 |
float getFloat() | 以float的形式获取此ResultSet对象的当前行中指定列的值 |
String getString() | 以string的形式获取此ResultSet对象的当前行中指定列的值 |
boolean getBoolean() | 以boolean的形式获取此ResultSet对象的当前行中指定列的值 |
Date getDate() | 以Date的形式获取此ResultSet对象的当前行中指定列的值 |
Object getObject() | 以Object的形式获取此ResultSet对象的当前行中指定列的值 |
2.8、JDBC相关驱动
1、Driver接口
java.sql.Driver是所有JDBC驱动程序需要实现的接口。不同数据库产商实现该接口的类名是不同的
2、com.microsoft.sqlserver.jdbc.SQLServerDriver
SQL Server 2000 的JDBC 驱动的类名
3、oracle.jdbc.driver.OracleDriver
Oracle的JDBC驱动的类名
4、com.mysql.jdbc.Driver
MySQL的JDBC驱动的类名
2.9、加载与注册JDBC驱动
1、使用Class.forName()
Class.forName("com.mysql.jdbc.Driver");
2、常见数据库URL表示
SQL Server
jdbc:microsoft:sqlserver://localhost:1433;databasename=users
Oracle
jdbc:oracle:thin:@localhost:1521:ORCL
MySQL
jdbc:mysql://localhost:3306/databasename
3、使用不同方式连接数据库
3.1、纯驱动连接
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://localhost:3306/databasename", "root", "123456");
3.2、ODBC桥连接
4、数据库的更新操作
5、数据库的显示和查询操作
6、数据库分页显示
7、数据库连接池
数据库操作中,和数据库建立连接(Connection)是最为耗时操作之一,而且,数据库都有最大连接数目限制,如果很多用户访问是同一数据库,所进行的都是同样的操作,比如记录查询,那么,为每个用户都建立一个连接是不合理的。为解决这一问题,引入连接池概念。
所谓连接池,就是预先建立好一定数量数据库连接,将这些连接对象存放在一个称为连接池的容器中,当需要访问数据库时,只要从连接池中取出一个连接对象即可,当用户使用完连接对象后,将该连接对象放回到连接池中。如果某用户需要操作数据库时,连接池中已没有连接对象可用,那么该用户就必须等待,直到连接池中有了连接对象。
在Web工程META-INFO目录下新建context.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource
name="jdbc/TestDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/school2"
username="root"
password="root"
maxIdle="10"
maxWait="1000"
maxActive="100"
/>
</Context>
1)name:设置数据源JNDI名
2)auth: 设置数据源管理者,有两个可选值Container和Application,Container表示由容器创建和管理数据源,Application表示由Web应用创建和管理数据源
3)type: 设置数据源类型
4)driverClassName:jdbc驱动程序
5)url:连接数据库路径
6)username:用户名
7)password:口令
8)maxActive:设置连接池中处于活动状态数据库连接最大数目,0表示不受限制。
9)maxIdle: 设置连接池中处于空闲状态数据库连接最大数目,0表示不受限制
10)maxWait: 设置连接池中没有处于空闲状态连接时,请求数据库连接的请求的最长等待时间(单位ms),如果超出该时间将抛出异常,-1表示无限等待
Javax.sql.DataSource接口,负责与数据库建立连接,在应用时不需要编写连接数据库代码,可以直接从数据源中获得数据库连接,在DataSource中预先建立了多个数据库连接,这些数据库连接保存在数据库连接池中,当程序访问数据库时,只需从连接池取出空闲的连接,访问结束后,再将连接归还给连接池。DataSource对象由容器(例如Tomcat)提供,不能通过创建实例方法来获得DataSource对象,需要利用Java的JNDI(Java Naming and Directory Interface)来获得DataSource对象引用。JNDI是一种将对象和名字绑定的技术,对象工厂负责生产对象,并将其与惟一的名字绑定,在程序中可以通过名字获得对象引用。
通过JNDI获取数据源,代码如下:
Context initCtx=new InitialContext();
Context ctx=(Context) initCtx.lookup("java:comp/env");
Object obj=(Object)ctx.lookup("jdbc/TestDB");
javax.sql.DataSource ds=(javax.sql.DataSource)obj;
方法2:
1、确保Tmcat安装目录webapps\yourweb\WEB-INF\lib中包含JDBC连接数据库所必须的驱动jar文件。
2、在Tomcat中配置连接池,修改Tmcat安装目录的conf/server.xml文件,在元素中添加如下内容,用以配置连接数据库各项信息。注意配置文件中原有 <Resource … />保留。其中,Resource元素属性含义同方法一。
3、修改Tmcat安装目录的conf/context.xml文件,在元素中添加如下内容。
<ResourceLink global="jdbc/TestDB" name="jdbc/TestDB" type="javax.sql.DataSource"/>
Context元素代表一个Web应用,连接池需要读取该元素中信息完成数据库连接。