方法文档:通过 ODP.NET 使用结果集锁定更新 LOB
方法文档:通过 ODP.NET 使用结果集锁定更新 LOB

日期:2004 年 10 月 11 日

目标

在阅读此方法文档后,您应该能够:

  • 选择和更新 Oracle 数据库中的 LOB (大对象)

  • 使用 ODP.NET 的结果集锁定功能

先决条件

假设读者熟悉 MS Visual Studio.NET,并了解 ODP.NET 和数据库的基础知识。

简介

ODP.NET 提供了一种简单但最佳的方式来访问和处理 Lob。ODP.NET 提供了三种用于操作 LOB 数据的 LOB 对象,即 OracleBlob、OracleClobOracleBfile。要使用这些对象更新 LOB,需满足两个要求。首先,在选取 LOB 列之前,必须先启动一个事务。其次,列驻留的行必须以逐行方式或作为整个结果集的一部分被锁定。

此文档演示如何使用结果集锁定(即锁定整个结果集)更新 LOB 数据。更新通过 OracleCommand 对象来完成。LOB 数据作为参数绑定到 SQL 语句。成功建立数据库连接之后,即创建了一个带有 CLOB 列的数据库表。该表是由初始 CLOB 数据填充。系统将启动一个 OracleTransaction,并从数据库中检索出要更新的行。使用 SELECT ..FOR UPDATE 语句锁定整个结果集。可在使用 OracleDataReader 进行更新的 OracleClob 类型对象中获得检索出的 CLOB 对象。使用 OracleClob.append 方法修改现有的 CLOB 数据。对 OracleClob 对象进行更改之后,系统将提交此事务。使用 read 方法和 OracleDataReader 在控制台上显示数据库中已经更新的数据。使用 OracleClob.erase 清除已经修改的数据。然后使用 OracleClob.write 将旧数据重新写到 clob 对象中。

价值定位

一旦启动了事务,应用程序就可以使用以下三种级别锁定中的任意一种 — 可以相应地设置这些锁以在更新 LOB 时避免任何“脏”的写操作:

  • 不锁定:不锁定使得数据争用最少,不过,它也最危险,这是因为它不能避免“脏”的写操作。

  • 行级锁定:行级锁定允许锁定结果集的特定行。虽然这比“不锁定”机制要安全得多,但它不能完全防止“脏”的写操作。另外要注意的是,如果结果集包含了多行,那么行级锁定将比结果集锁定产生更少的数据争用。

  • 结果集锁定:结果集锁定在锁定生命期内防止“脏”的写操作。不过,如果在大量行上长期设置锁,则可能产生数据争用问题。

需求

创建数据库对象

此方法文档使用 multimedia_tab 表。使用 SQL*Plus 以任意用户身份连接到数据库(如 scott/tiger),然后运行如下命令:

DROP TABLE multimedia_tab;

CREATE TABLE multimedia_tab(thekey NUMBER(4) PRIMARY KEY, story CLOB, sound BLOB);


INSERT INTO multimedia_tab values(1,'This is a long story.Once upon a time ...',
                                    '656667686970717273747576777879808182838485');

commit;

代码预演

包括所需命名空间:.cs.vb 文件中的‘一般声明’部分中添加对命名空间的引用非常值得,这样可避免以后在脚本中限定其使用:

using System;
using System.Text;
using Oracle.DataAccess.Types;
using Oracle.DataAccess.Client;
Imports System
Imports System.Text
Imports Oracle.DataAccess.Types
Imports Oracle.DataAccess.Client

1. 建立一个到数据库的连接:

// 第 1 步
// 使用 ODP.NET 建立连接
// 注意:按照您数据库的设置
// 修改用户 Id、口令、数据源
string connectStr = "User Id=Scott;Password=tiger;Data Source=orcl9i";

OracleConnection connection = new OracleConnection(connectStr);
connection.Open();
Console.WriteLine("connected to database");
Console.WriteLine(" ");
' 第 1 步
' 使用 ODP.NET 建立连接
' 注意:按照您数据库的设置
' 修改用户 Id、口令、数据源
Dim connectStr As String = "User Id=Scott;Password=tiger;Data Source=orcl9i"

' 初始化连接
Dim connection As OracleConnection = New OracleConnection(connectStr)
connection.Open()
Console.WriteLine("connected to database")
Console.WriteLine(" ")

2. 声明所需的 Oracle 对象:

// 第 2 步
// 声明 Oracle 对象
OracleTransaction txn;
OracleCommand cmd = new OracleCommand("",connection);
OracleDataReader reader;
OracleClob clob;
' 第 2 步
' 声明 Oracle 对象
Dim txn As OracleTransaction
Dim cmd As OracleCommand = New OracleCommand("", connection)
Dim reader As OracleDataReader
Dim clob As OracleClob

3. 任何 LOB 更新都需要一个 Oracle 事务。所以,下面开始事务处理:

// 第 3 步
// 启动事务处理

txn = connection.BeginTransaction();	
' 第 3 步
' 启动事务处理
txn = connection.BeginTransaction()
			

4. 使用 FOR UPDATE 语句以锁定用于更新的整个结果集。然后执行如下语句:

// 第 4 步
// 使用 FOR UPDATE 子句锁定结果集
cmd.CommandText = "SELECT story FROM multimedia_tab FOR UPDATE";

reader = cmd.ExecuteReader();
' 第 4 步
' 使用 FOR UPDATE 子句锁定结果集
cmd.CommandText = "SELECT story FROM multimedia_tab FOR UPDATE"

reader = cmd.ExecuteReader()

5. 将数据读入 Oracle LOB 对象:

// 第 5 步
// 使用类型正确的 Oracle LOB 对象的存取器
// 读取 OracleDataReader 中的数据
reader.Read();
clob = reader.GetOracleClob(0);
Console.WriteLine("Old Data:{0}", clob.Value);
Console.WriteLine(" ");
' 第 5 步
' 使用类型正确的 Oracle LOB 对象的存取器
' 读取 OracleDataReader 中的数据
reader.Read()
clob = reader.GetOracleClob(0)
Console.WriteLine("Old Data:{0}", clob.Value)
Console.WriteLine(" ")
		

6. 修改然后提交 OracleCLOB 当前例程中的数据。自动提交事务将释放此锁:

// 第 6 步
// 修改该行的 CLOB 列
string ending = " The end.";

// 将 CLOB 数据追加到当前 OracleCLOB 实例
clob.Append(ending.ToCharArray(), 0, ending.Length);

// 释放锁
txn.Commit();
Console.Write("Updated to new data:");
' 第 6 步
' 修改该行的 CLOB 列
Dim ending As String = " The end."

' 将 CLOB 数据追加到当前 OracleCLOB 实例
clob.Append(ending.ToCharArray(), 0, ending.Length)

' 释放锁

txn.Commit()
Console.Write("Updated to new data:")

7. 从数据库中取出修改了的数据然后将其显示在控制台上:

// 第 7 步
// 从数据库提取修改的数据
// 使用 FOR UPDATE 子句锁定整个结果集
cmd.CommandText = "SELECT story FROM multimedia_tab FOR UPDATE";

reader = cmd.ExecuteReader();
reader.Read();
clob = reader.GetOracleClob(0);
Console.WriteLine(clob.Value);
Console.WriteLine(" ");
' 第 7 步
' 从数据库提取修改的数据
' 使用 FOR UPDATE 子句锁定整个结果集
cmd.CommandText = "SELECT story FROM multimedia_tab FOR UPDATE"

reader = cmd.ExecuteReader()
reader.Read()
clob = reader.GetOracleClob(0)
Console.WriteLine(clob.Value)
Console.WriteLine(" ")

8. 将 CLOB 对象的当前实例重置为旧数据:

// 第 8 步
// 使用旧值重置数据
// 启动 Oracle 事务处理
txn = connection.BeginTransaction();

// 清空 OracleCLOB
// 当前实例
clob.Erase();

// 将字符串重写为旧值
StringBuilder blr1 = new StringBuilder();
blr1.Append("'This is a long story.Once upon a time ...',");

String oldData = blr1.ToString();
' 第 8 步
' 使用旧值重置数据
' 启动 Oracle 事务处理
txn = connection.BeginTransaction()



' 清空 OracleCLOB
' 当前实例
clob.Erase()


' 将字符串重写为旧值
Dim blr1 As StringBuilder = New StringBuilder()
blr1.Append("'This is a long story.Once upon a time ...',")

Dim oldData As String = blr1.ToString()

9. 提交事务将自动释放此锁。随后在控制台上显示旧数据:

// 第 9 步
// 将字节数组写入 OracleCLOB 对象
clob.Write(oldData.ToCharArray(),0, oldData.Length);


// 更新数据、释放锁
txn.Commit();

Console.WriteLine("Old Data again:{0}", clob.Value);
' 第 9 步
' 将字节数组写入 OracleCLOB 对象
clob.Write(oldData.ToCharArray(), 0, oldData.Length)


' 更新数据、释放锁
txn.Commit()

Console.WriteLine("Old Data again:{0}", clob.Value)

设置并运行此方法文档的项目

1. 打开 Visual Studio.NET。

2. 创建控制台应用程序项目:

用 C# 创建一个控制台应用程序项目。默认情况下系统将 Class1.cs 添加到项目中。
用 Visual Basic .NET 创建控制台应用程序项目。默认情况下系统将 Module1.vb 添加到项目中。

3. 请确保您的项目包含对 System、Oracle.DataAccessSystem.Data 命名空间的引用。如果这些引用不存在,请添加对这些命名空间的引用。

4. 复制代码:

使用 Solution Explorer 打开 Class1.cs。有关为此方法文章用 C# 编写的代码的完整清单,请单击这里。复制此代码并覆盖 Class1.cs 的内容。

使用 Solution Explorer 打开 Module1.vb。有关为此方法文章用 VB.NET 编写的代码的完整清单,请单击这里。复制此代码并覆盖 Module1.vb 的内容。

5. 按照代码的第 1 步中的数据库设置修改用户 Id、口令及数据源。

6. 要编译并运行此应用程序,请按下 Ctrl+F5。这将显示旧数据和新数据,如图 1.1 所示:


图 1.1 – 输出的屏幕截图

资源


请在 OTN 示例代码论坛中输入有关此方法文档的意见。

寄送此页面
Printer View 打印机视图