核心技术Ⅱ:数据库编程
关于JDBC
Java数据库连接(JDBC)API:
- 遗循了微软公司非常成功的ODBC模式(ODBC:微软提供为C语言访问数据库的一套编程接口)。JDBC和ODBC都基千同一个思想:根据API编写的程序都可以与驱动管理器进行通信,而驱动管理器则通过驱动程序与实际的数据库进行通信。
- 我们将JDBC包看作是一个用于“将SQL语句传递给数据库”的应用编程接口;
- 【参见:入门:Mybatis—关于JDBC】
JDBC的目标:
- 通过使用标准的SQL语句,甚至是专门的SQL扩展,程序员就可以利用Java语言开发访问数据库的应用,同时还依旧遵守Java语言的相关约定。
- 数据库供应商和数据库工具开发商可以提供底层的驱动程序。因此,他们可以优化各自数据库产品的驱动程序。
JDBC 驱动程序类型:
- 笫1类驱动程序:将JDBC翻译成ODBC, 然后使用一个ODBC驱动程序与数据库进行通信。
- 较早版本的Java包含一个这样的驱动程序:JDBC/ODBC桥,不过在使用这个桥接器之前需要对ODBC进行相应的部署和正确的设置。(Java 8已经不再提供JDBC/ODBC桥)
- 笫2类驱动程序:由部分Java程序和部分本地代码组成的,用于与数据库的客户端API进行通信。
- 在使用这种驱动程序之前,客户端不仅斋要安装Java类库,还需要安装一些与平台相关的代码。
- 第3类驱动程序:纯Java客户端类库,它使用一种与具体数据库无关的协议将数据库请求发送给服务器构件,然后该构件再将数据库请求翻译成数据库相关的协议。这简化了部署,因为平台相关的代码只位于服务器端。
- 第4类驱动程序:纯Java类库,它将JDBC请求直接翻译成数据库相关的协议。
JDBC 的典型用法:
- 传统的客户端/服务器模型:通常是在服务器端部署数据库,而在客户端安装富GUI程序。(在此模型中,JDBC驱动程序应该部署在客户端)
- 三层模型:客户端不直接调用数据库,而是调用服务器上的中间件层,由中间件层完成数据库查询操作。
结构化查询语言:即SQL【SQL,读作“ [ˈsiːkwəl] ”】
JDBC配置
- (驱动程序JAR文件):
- 需要准备对应的数据库驱动包:在运行访问数据库的程序时,需要将驱动程序的 JAR 文件包括到类路径中(编译时并不需要这个 JAR 文件)。
// 在从命令行启动程序时,只需要使用下面的命令: java -classpath driverPath:. ProgramName
- 注册驱动器类:
- 自动注册:许多JDBC的JAR文件会自动注册驱动器类,则可以跳过手动注册步骤。
- (包含“META-INF/services/java.sql.Driver”文件的 JAR 文件可以自动注册驱动器类)
- 自动注册对于遵循 JDBC4 的驱动程序是必须具备的特性。
- 手动注册:通过“DriverManager”来注册驱动器。
- 在 Java 程序中加载驱动器类:(注册驱动器的静态初始化器)
Class.forName("org.postgresql.Driver"); // force loading of driver class
- 设置“jdbc.drivers”属性:
- 命令行参数指定这个属性:
java -Djdbc.drivers=org.postgresql.Driver ProgramName
- 或,应用中通过调用设置系统属性:
System.setProperty("jdbc.drivers", "org.postgresql.Driver");
- 在这种方式中可以提供多个驱动器,用冒号将它们分隔开:
org.postgresq1.Driver:org.apache.derby.jdbc.ClientDriver
- 命令行参数指定这个属性:
- 在 Java 程序中加载驱动器类:(注册驱动器的静态初始化器)
- 自动注册:许多JDBC的JAR文件会自动注册驱动器类,则可以跳过手动注册步骤。
- 连接到数据库:
- 在代码中打开数据库连接:
String url = "jdbc:postgresql :COREJAVA"; String username = "dbuser"; String password = "secret"; Connection conn = DriverManager.getConnection(url, username, password);
- 驱动管理器遍历所有注册过的驱动程序,以便找到一个能够使用数据库 URL 中指定的子协议的驱动程序。
- 使用数据库配置文件(如“database.properties”)
jdbc.drivers=org.postgresql.Oriver jdbc.url=jdbc:postgresql:COREJAVA jdbc.username=dbuser jdbc.password=secret
- 在代码中打开数据库连接:
- 数据库驱动器名称:如:
org.apache.derby.jdbc.ClientDriver org.postgresql.Driver com.mysql.jbdc.driver
- 数据库URL:JDBCURL 的一般语法为:“jdbc:subprotocol:other_stuff”,其中subprotocol用于选择连接到数据库的具体驱动程序。
- URL包含各种与数据库类型相关的参数,例如“主机名”、“端口号”和“数据库名”。如:
jdbc:derby://1ocalhost:1527/COREJAVA;create=true jdbc:postgresq1:COREJAVA
示例:
try{
Class.forName("com.mysql.jbdc.driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///spring_day01","root","admin");
String sql = "select * from users where username = ?";
PrepareStatement pre = conn.prepareStatement(sql);
pre.setString(1,"小陈");
ResultSet rs = pre.executeQuery();
while(rs.next()){
String username = rs.getString("username");
String password = rs.getString("password");
User user = new User();
user.setUsername(username);
user.setPassword(password);
System.out.println(user);
}
}catch(Exception ex){
ex.printStackTrace();
}finally{
rs.close();
pre.close();
conn.close();
}
使用JDBC语句
执行SQL语句
执行语句:
- “executeUpdate”:返回受SQL语句影响的行数,或者对不返同行数的语句返回0。
- 既可以执行诸如“INSERT”、“UPDATE”和“DELETE”之类的操作,也可以执行诸如“CREATETABLE”和“DROPTABLE”之类的数据定义语句。
- “executeQuery”:返回一个“ResultSet”类型的对象,可以通过它来每次一行地迭代遍历所有查询结果。
- 执行“SELECT”查询时必须使用executeQuery方法。
- “execute”:可能会产生多个结果集和更新计数。
- 如果第一个执行结果是结果集,则返回 true;反之,返回 false。调用“getResultSet”或“getUpdateCount”方法可以得到第一个执行结果。
- 可以执行任意的SQL语句。(通常只用于由用户提供的交互式查询)
结果处理:分析结果集:
while (rs.next()) { String username = rs.getString("username"); String password = rs.getString("password"); int age = rs.getInt("age"); User user = new User(); user.setUsername(username); user.setPassword(password); user.setAge(age); System.out.println(user); }
- ResultSet接口的迭代协议与“java.util.Iterator”接口稍有不同:
- 对于ResultSet接口,迭代器初始化时被设定在第一行之前的位置,必须调用“next”方法将它移动到第一行。另外,它没有“hasNext”方法,我们需要不断地调用“next”,直至该方法返回 false 。
- 不同的数据类型有不同的访问器,比如“getString”和“getDouble”。
- 当 get 方法的类型和列的数据类型不一致时,每个 get 方法都会进行合理的类型转换。例如,调用“rs.getString("Price")”时,该方法会将 Price 列的浮点值转换成字符串。
- 每个访问器都有两种形式:
- 一种接受数字型参数。(列序号从1开始)如,“rs.getString(l)”返回的是当前行中第一列的值;
- 另一种接受字符串参数。如上例;
相关方法:
java.sql.DriverManager 1.1 | |
---|---|
static Connection getConnection(String url, String user, String password) | 建立一个到指定数据库的连接,并返回一个 Connection 对象。 |
java.sql.Connection 1.1 | |
Statement createStatement() | 创建一个 Statement 对象,用以执行不带参数的 SQL 查询和更新。 |
void close() | 立即关闭当前的连接,并释放由它所创建的JDBC资源。 |
java.sql.Statement 1.1 | |
ResultSet executeQuery(String sqlQuery) | 执行给定字符串中的 SQL 语句,并返回一个用于查看查询结果的 ResultSet 对象。 |
int executeUpdate(String sqlStatement) | 执行字符串中指定的“INSERT”、“UPDATE”或“DELETE”等 SQL 语句。还可以执行数据定义语言 (Data Definition Language, DDL) 的语句,如“CREATE TABLE”。返回受影响的行数,如果是没有更新计数的语句,则返回 0。 |
long executeLargeUpdate(String sqlStatement) 8 | |
boolean execute(String sql Statement) | 执行字符串中指定的 SQL 语句。可能会产生多个结果集和更新计数。如果第一个执行结果是结果集,则返回 true;反之,返回 false。调用“getResultSet”或“getUpdateCount”方法可以得到第一个执行结果。【见“多结果集”一节】 |
ResultSet getResultSet() | 返回前一条查询语句的结果集。如果前一条语句未产生结果媒,则返回 null 值。对于每一条执行过的语句,该方法只能被调用一次。 |
int getUpdateCount() | 返回受前一条更新语句影响的行数。如果前一条语句未更新数据库,则返回-1。对于每一条执行过的语句,该方法只能被调用一次。 |
1ong getLargeUpdateCount() 8 | |
void close() | 关闭 Statement 对象以及它所对应的结果集。 |
boolean isClosed() 6 | 如果语句被关闭,则返回true。 |
void closeOnCompletion() 7 | 使得一旦该语句的所有结果集都被关闭,则关闭该语句。 |
java.sql.ResultSet 1.1 | |
boolean next() | 将结果集中的当前行向前移动一行。如果已经到达最后一行的后面,则返同false。注意,初始请况下必须调用该方法才能转到第一行。 |
Xxx getXxx(int columnNumber) | 用给定的列序号或列标签返回或更新该列的值,并将值转换成指定的类型。列标签是SQL的AS子句中指定的标签,在没有使用AS时,它就是列名。 |
Xxx getXxx(String columnLabel)
(Xxx指数据类型, 例如“int”、“double”、“String”和“Date”等) | |
<T> T getObject(int columnIndex, Class<T> type) 7 | |
<T> T getObject(String columnLabel, Class<T> type) 7 | |
void updateObject(int columnIndex, Object x, SQLType targetSqlType) 8 | |
void updateObject(String columnLabel, Object x, SQLType targetSqlType) 8 | |
int findColumn(String columnName) | 根据给定的列名,返回该列的序号。 |
void close() | 立即关闭当前的结果集。 |
boolean isClosed() 6 | 如果该语句被关闭,则返回true。 |
管理连接、语句和结果集
分析SQL异常
组装数据库
执行查询操作
预备语句 读写LOB SQL 转义 多结果集 获取自动生成的键
可滚动和可更新的结果集
可滚动的结果集 可更新的结果集
行集
构建行集 被缓存的行集
元数据
事务
用JDBC对事务编程 保存点 批量更新