JDBC数据库编程详解

1.安装驱动程序

到对应的数据库厂商那里获取对应的驱动程序并安装。

2.数据库配置

String url = "jdbc:mysql://127.0.0.1:3306/test";
String username = "dbuser";
String password = "secret";

3.连接到数据库

Connection conn = DriverManager.getConnection(url, username, password);

4.使用JDBC语句

Statement stat = conn.createStatement();
String command = "UPDATE Books" + " SET Price = Price - 5.00" + " WHERE Title NOT LIKE '%Introduction'";
stat.executeUpdate(command);

4.1execute

execute执行给定的SQL语句,该语句可能返回多个结果。
executeBatch提交一批命令到数据库执行,如果所有命令都成功执行,则返回一个更新计数数组。
executeLargeBatch提交一批命令到数据库执行,如果所有命令都成功执行,则返回一个更新计数数组。

4.2executeQuery

executeQuery:执行给定的SQL语句,返回一个ResultSet对象。

一个ResultSet对象维护一个指向其当前数据行的游标。最初,游标位于第一行之前,next方法会将游标移动到下一行,当在ResultSet对象中没有更多行next方法会返回false,一般更方便的是可以在while循环中使用它来遍历结果集。

ResultSet rs = stat.executeQuery("SELECT * FROM Books");

while(rs.next())
{
   //...
}

4.3executeUpdate

executeUpdate执行给定的SQL语句,可以是INSERTUPDATEDELETE语句,也可以是不返回任何内容的SQL语句,比如SQL DDL语句。
executeLargeUpdate执行给定的SQL语句,可以是INSERT、UPDATE或DELETE语句,也可以是不返回任何内容的SQL语句,比如SQL DDL语句。

5.预备语句(PreparedStatement)

SElECT Books.Price, Books
FROM Books, Publishers
WHERE Books.Publisher_Id = Publishers.Publisher_Id
AND Publishers.Name = the name from the list box

我们没有必要在每次触发一个这样的查询时都建立新的查询语句,而是可以准备一个带有宿主变量的查询语句,每次查询时只需要为该变量天如不同的字符串就可以反复多次地使用该语句。这一技术改进了查询性能。

在预备查询语句中,每个查询变量都用”?“来表示。如果存在一个以上的变量,那么在设置变量值时必须注意”?“的位置。

String publisherQuery
  = "SElECT Books.Price, Books"
  + " FROM Books, Publishers"
  + " WHERE Books.Publisher_Id = Publishers.Publisher_Id AND Publishers.Name = ?";

PreparedStatement stat = conn.prepareStatement(publisherQuery)
//第一个参数指的是需要设置的宿主变量的位置,位置1表示第一个"?"
//第二个参数指的是赋予宿主变量的值
stat.setString(1, publisher);

6.可滚动(Scrollable)结果集

默认ResultSet对象是不可滚动和不可更新的,并且有一个只能向前移动的指向当前位置的游标(Cursor)。因此,您只能遍历它一次,并且只能从第一行到最后一行。

但是如果我们需要在结果集中向前或向后移动,甚至可以跳到任意位置,那就需要使用可滚动结果集。

可使用以下方法得到一个不同的Statement对象。

//正常语句
Statement stat = conn.createStatement(int resultSetType, int resultSetConcurrency);
//预备语句
PreparedStatement stat = conn.prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
resultSetType解释
ResultSet.TYPE_FORWARD_ONLY结果集不能滚动(默认值)
ResultSet.TYPE_SCROLL_INSENSITIVE结果集可以滚动,但对数据库变化不敏感
ResultSet.TYPE_SCROLL_SENSITIVE结果集可以滚动,且对数据库变化敏感
方法解释
rs.next()将游标从当前位置向前(forword)移动一行。
rs.previous()将游标移动到ResultSet对象的前一行。
rs.relative(n)将游标移动相对数量的行(正数或负数)。
rs.absolute(int row)将游标移动到这个ResultSet对象中的给定行号。
rs.getRow检索当前行号。
rs.first()将游标移到ResultSet对象的第一行。
rs.beforeFirst()将游标移动到ResultSet对象的前面,就在第一行之前。
rs.last()将游标移动到ResultSet对象的最后一行。
rs.afterLast()将游标移到ResultSet对象的末尾,就在最后一行之后。

7.可更新(Updatable)结果集

如果可能希望编辑结果集中的内容,那就需要使用可更新结果集,可以以编程方式来更新其中的项,使得数据库可以自动更新数据。

可更新结果集并非必须时可滚动结果集,但如果将数据提供给用户去编辑,那么通常也会希望结果集时滚动的。

//正常语句
Statement stat = conn.createStatement(int resultSetType, int resultSetConcurrency);
//预备语句
PreparedStatement stat = conn.prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
String query = "SELECT * FROM Books";
ResultSet rs = stat.executeQuery(query);
while (rs.next())
{
    if(...)
    {
        double increase = ...;
        double price = rs.getDouble("Price");
        rs.updateDouble("Price", price + increase);
        rs.updateRow();
    }
}
resultSetConcurrency解释
ResultSet.CONCUR_READ_ONLY结果集不能用于更新数据库(默认值)
ResultSet.CONCUR_UPDATABLE结果集可以用于更新数据库
方法SQL语句中的等效语句解释
updateXxx————用指定的值更新指定的列。
insertRowINSERT将插入行的内容插入到ResultSet对象和数据库中。
updateRowUPDATE使用ResultSet对象当前行的新内容更新到数据库。
deleteRowDELETE从ResultSet对象和数据库中删除当前行。

8.行集(RowSet)

可滚动结果集虽然功能强大,却有一个重大的缺陷:在与用户的整个交互过程中,必须始终与数据库保持连接。用户可能会离开电脑一段时间,而在此期间却始终占用着数据库连接。这种方式存在很大的问题,因为数据库连接书有稀有资源。在这种情况下,我们可以使用行集。RowSet接口继承自ResultSet接口,但无需始终保持与数据库的连接。

行集分类解释
CachedRowSet允许在断开连接的状态下执行相关操作。
WebRowSet代表了一个被缓存的行集,该行集可以保存为XML文件。该文件可以移动到Web应用的其它层,只要在该层中使用另一个WebRowSet对象重新打开该文件即可。
FilteredRowSet和JoinRowSet支持对行集的轻量级操作,等同于SQl中的SELECT和JOIN操作。这两个接口的操作对象时存储在行集中的数据,因此运行时无需建立数据库连接。
JdbcRowSetResultSet接口的精简包装器,在RowSet接口中添加了一些有用的方法。

在此重点介绍下被缓存的行集(CachedRowSet):

一个被缓存的行集中包含了一个结果集中所有的数据。被缓存的行集有一个非常重要的优点:断开数据库连接后仍然可以使用行集。

在执行每个用户命令时,我们只需打开数据库连接,执行查询操作,将查询结果放入被缓存的行集,然后关闭数据库连接即可。

//结果集对象负责打开数据库连接、执行查询操作,然后填充行集,最后关闭连接
ResultSet rs = ...;
RowSetFactory factory = RowSetProvider.newFactory();
CachedRowSet crs = factory.createCachedRowSet();
crs.populate(rs);
conn.close();
//被缓存行集负责打开数据库连接、执行查询操作、填充行集,最后断开连接
//建立数据库连接
crs.setURL("jdbc:mysql://127.0.0.1:3306/testdb");
crs.setUsername("dbuser");
crs.setPassword("secret");
//设置查询语句和参数
crs.setCommand("SELECT * FROM Books WHERE Publisher_ID = ?");
crs.setString(1, publisherId);
//将查询结果填充到行集
crs.execute

我们甚至可以修改被缓存的行集中的数据,当然,这些修改不会立即反馈到数据库中,必须发起一个显示的请求,以便让数据库真正接受所有修改。此时CachedRowSet会重新连接到数据库,并通过执行SQL语句向数据库中写入所以修改后的数据。

如果查询结果非常大,那我们肯定不想将其全部放入行集中。毕竟,用户可能知识想浏览其中的几页而已。在这种情况下,可以指定每一页的尺寸。

CachedRowSet crs =...;
crs.setCommand(command);
//只获得20行
crs.setPageSize(20);
...
crs.execute();
//获取下一页数据
crs.nextPage();
//将修改写回到数据库中
crs.acceptChanges(conn);

9.事务(Transaction)

我们可以将一组语句构建成一个事务(transaction),当所有语句都顺利执行之后,事务可以被提交,否则,如果其中某个语句遇到错误,那么事务将被回滚,就好像没有任何语句被执行过一样。

默认情况下, 数据库连接处于 自动提交模式(autocommit mode),即每个SQL语句一旦被执行便会被提交给数据库。一旦SQL命令被提交,就无法对它执行回滚操作。在使用事务时,需要关闭这个默认值。

try {
    // 关闭自动提交
    conn.setAutoCommit(false);
    // 执行多条SQL语句
    Statement stat = conn.createStatement();
    stat.executeUpdate(command1);
    stat.executeUpdate(command2);
    stat.executeUpdate(command3);
    // 提交事务
    conn.commit();
} catch (SQLException e) {
    // 回滚事务
    conn.rollback();
} finally {
    conn.setAutoCommit(true);
    conn.close();
}

使用保存点可以更细粒度地控制回滚操作,创建保存点意味着稍后只需要返回这个点,而非放弃整个事务。

Statement stat = conn.createStatement();
stat.executeUpdate(command1);
Savepoint svpt = conn.setSavepoint();
stat.executeUpdate(command2);

if(...)
{
    conn.rollback(svpt);
}
conn.commit();

//不需要保存点时,应该释放它
conn.releaseSavepoint(svpt);

原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/experience/javae/9153.html

(0)
上一篇 2021年10月17日 14:27
下一篇 2021年10月29日 21:09

相关推荐

发表回复

登录后才能评论