<oracle-7> 事务

本文详细阐述了Oracle数据库中事务的概念、ACID特性、控制语句、原子性、持久性、完整性约束以及分布式事务处理。重点介绍了事务的隐式开始、自动提交习惯的不当使用以及如何在循环中合理提交事务,提供了对事务机制全面深入的理解。
[b]事务(transaction)是数据库区别于文件系统的特性之一[/b]。在文件系统中,如果你正把文件写到一半,操作系统就崩溃了,这个文件就很可能会被破坏。这正是数据库中引入事务的主要目的,[b]事务会把数据库从一种一致状态转变为另一种一致状态[/b]。在数据库中提交工作时,可以确保要么所有修改都已经保存,要么所有修改都不保存。

Oracle中的事务体现了所有必要的ACID特征。
[color=red]原子性[/color](Atomicity):事务中的所有动作要么都发生,要么都不发生。
[color=red]一致性[/color](Consistency):事务将数据库从一种一致状态变为下一种一致状态。
[color=red]隔离性[/color](Isolation):一个事务的影响在该事务提交前对其他事务都不可见。
[color=red]持久性[/color](Durability):事务一旦提交,其结果就是永久性的。

[b]7.1 事务控制语句[/b]
[b]Oracle中不需要专门的语句来“开始事务”。事务会在[color=red]修改数据的第一条语句[/color]处[color=red]隐式开始[/color](也就是得到TX锁的第一条语句)[/b]。也可以使用set transaction或DBMS_TRANSACTION包来显式地开始一个事务,但是这一步并不是必要的,[b]这与其他的许多数据库不同,因为那些数据库中都[color=red]必须[/color]显式开始事务[/b]。如果发出commit或rollback语句(注意rollback to savepoint不会结束事务),就会显式地结束一个事务。

如果正常退出sql*plus会话,而没有提交或回滚事务,[b]sql*plus会自动完成提交[/b]。不要过分依赖这些隐式行为,一定要显式提交或回滚。
Oracle中的事务是原子性的,这说明无非两种情况:构成事务的每条语句都会提交(成为永久)或者所有语句都回滚。注意这里的“所有”,也就是当成了一个整体。

[color=darkred]我们可以了解到控制事务的语句只有:commit,rollback, savepoint, rollback to <savepoint>,set transaction五种。[/color]

[b]7.2 原子性[/b]
前面对事务控制语句做了一个简要的概述后,下面可以看看语句原子性、过程原子性和事务原子性的含义。

[b]7.2.1 语句级原子性[/b]
考虑以下语句:
insert into t values(1);
如果该语句由于一个约束冲突而失败,这一行就不会插入。不过再考虑下面的例子,表T上的一个insert或delete会触发一个触发器,它将适当地调整t2表上的列:
T2: create table t2 (cnt int);
T: create table t (x int check (x > 0));

创建触发器:
create trigger t_trigger
before insert or delete on t for each row
begin
if (inserting) then
Update t2 set cnt = cnt + 1;
else
update t2 set cnt = cnt – 1;
end if;
dbms_output.put_line(‘I fired and updated’ || sql%rowcount || ‘ rows’);
end;
/

这种情况下往T表插入数据,会发生什么就不那么显而易见了。如果触发器触发之后出现了错误,触发器的影响是否还存在?也就是如果触发器被触发,并且更新了t2,但是这一行没有插入到T中,结果会怎样?期望的结果是,如果并没有真正在T中插入一行,我们就不希望T2中的cnt列增加。幸运的是,在oracle中,客户最初发出的语句(在这里就是insert into t)会完全成功或完全失败。这个语句是原子性的,同时insert into T的任何连带效果都被认为是该语句的一部分,这里就是触发器。

为了得到这种语句级原子性,oracle悄悄地在每个数据库调用外面包了一个savepoint。前面的insert 语句实际处理如下:
savepoint statement1;
Insert into t values (1);
If error then rollback to statement1;
savepoint statement2;
Insert into t values (-1);
if error then rollback to statement2;

在[b]Sybase或sqlserver[/b]中刚好相反。这些系统中的触发器会独立于触发语句执行。如果触发器遇到一个错误,它[b]必须显式[/b]地回滚自己的工作,然后产生另外一个错误来回滚触发语句。

[b]7.2.2 过程级原子性[/b]
有意思的是,oracle把pl/sql匿名块也当做是语句。比如以下存储过程:
Create or replace procedure p as
Begin
Insert into t values (1);
Insert into t values (-1);
End;
/

继续沿用上节的check约束,在这个过程中,第二个insert总会失败。这时候我们调用这个存储过程会发现表t里总是空的。也就是整体没有插入数据。但是如果我们调用p的时候自己捕获了错误,那第一句插入就会成功。因为oracle没有捕获到异常发生,当做事务成功,就会提交。

[b]7.2.3 事务级原子性[/b]
事务的总目标是把数据库从一种一致状态转变为另一种一致状态。为了实现这个目标,事务也是原子性的,事务完成的所有工作要么完全提交称为永久性的,要么回滚并撤销。

[b]7.2.4 DDL与原子性[/b]
需要指出,oracle中有一类语句具有原子性,不过只是在语句级保证原子性。DDL(数据定义语言, Data Definition Language, DDL)语句采用了一种特定的实现方式,可以完成如下工作:
(1) 提交当前所有未完成的工作,结束当前已有的所有事务。
(2) 完成DDL操作,如create table.
(3) 如果DDL操作成功则提交,否则回滚DDL操作。

[b]7.3 持久性[/b]
通常情况下,一个事务提交时,它的改变就是永久性的。即使数据库在提交完成之后随即崩溃,你也完全可以相信这些改变确实已经永久存储在数据库中。不过,下述两种情况例外:
(1) 使用commit语句新增的write扩展(这是oracle database 10g release2及以上版本中新增的特性)。
(2) 在非分布式(只访问一个数据库,而不是多个数据库连接)pl/sql代码块中执行commit.

[b]7.3.1 commit的write扩展[/b]
在oracle 10g release2及以上版本中,可以为commit语句增加一个write子句。这个write子句允许等到生成的redo写至磁盘之后再提交(wait,这是默认选项),或者不等写redo就直接提交(nowait)。
通常情况下,commit是一个同步过程,应用首先调用commit,然后等待整个commit处理完成。在oracle 10g release2之前,所有oracle版本支持的都是这种commit行为,这也是oracle 10g release2及以上版本的默认行为。
Oracle的当前版本中,并不需要等待提交完成(这需要一定的时间,因为提交涉及一个物理IO操作,要向存储在磁盘上的redo日志文件完成物理写操作),可以在后台完成提交。这会带来一个副作用:提交不能保证持久性。也就是说,应用可能会从该数据库得到一个响应,指出已经收到你的异步提交,而且其他会话能够看到你做出的改变,不过后来却发现你原以为已经提交的事务实际上并未真正提交。这种情况很少见,往往涉及严重的硬件或软件故障。要让一个异步提交不具有持久性,数据库必须异常关闭,这意味着数据库实例或运行这个数据库实例的计算机必须完全失效。
那么,既然事务要保证持久性,这种可能导致非持久性的特性又有什么用呢?答案在于性能。在应用中发出一个commit时,会请求LGWR进程得到生成的redo,并确保将生成的这些redo写至在线redo日志文件。完成物理IO操作的速度相当慢,所以,commit甚至比事务中DML语句本身耗时还要长。如果异步完成commit,就不再需要等待客户应用中的物理IO,这会让客户应用速度更快,特别是如果有大量commit,异步提交会让速度大大提高。
既然如此,为什么不总是使用commit write nowait呢?记住,[color=red]正确性永远位于首位[/color]。只有3种特殊情况才需要使用nowait:
(1) 定制的数据加载程序。
(2) 处理某种实时数据,这些数据对时间敏感,即使失败也可能会被覆盖或丢弃。
(3) 应用实现了自己的“排队”机制。
你会注意到这3种应用个都是后台的非交互式应用,他们不会与人直接交互。如果应用需要与人交互,向用户报告“提交完成”,就应当使用同步提交。对于面向客户的在线应用,不能把异步提交作为改善性能的手段。异步提交只适应于面向批处理的应用。因此除了这3类批处理应用外,其他应用中都不该使用这个新功能—commit write nowait。

[b]7.3.2 非分布式pl/sql代码块中的commit[/b]
从oracle6引入pl/sql以来,pl/sql一直都透明地使用异步提交。这种做法是可行的,因为从某种意义来说所有pl/sql都类似于批处理程序,即在pl/sql过程完全执行完之前,最终用户无法知道过程的结果。也正是因为这个原因,这种异步提交只能用于非分布式的pl/sql代码块;如果涉及到多个数据库,会有两个对象(两个数据库)依赖于提交的持久性。倘若两个数据库都依赖于提交的持久性,就必须采用同步协议,否则可能在一个数据库中改变已经提交,而在另一个数据库中未提交。

[b]7.4 完整性约束和事务[/b]
默认情况下,完整性约束会在整个sql语句得到处理之后才进行检查。也有一些可延迟的约束允许将完整性约束的验证延迟到应用请求时(发出一个set constraints all immediate命令)才完成,或者延迟到发出commit时再检查。

[b]7.4.1 immediate约束[/b]
在讨论的前一部分,我们假设约束都是immediate模式,这也是一般情况。在这种情况下,完整性约束会在整个sql语句得到处理之后立即检查。注意,这里用的是“sql语句”而不是“语句”。如果一个pl/sql存储过程中有多条sql语句,那么在每条sql语句执行之后都会立即验证其完整性约束,而不是在这个存储过程完成后才检查它。比如update语句会影响多条语句,则会在所有需要更新的语句更新完后才检查一次,而不是每变化一行数据就检查一次。

[b]7.4.2 deferrable约束和级联更新[/b]
从oracle8开始,我们还能够延迟约束检查,对于许多操作来说,这很有好处。首先能想到的是可能需要将一个主键的update级联到子键。在以前的版本中,确实也可以完成cascade udpate,但是为此需要做大量的工作,而且存在某些限制。有了可延迟约束后,这就变得易如反掌了。

[b]7.5 [color=red]不好[/color]的事务习惯[/b]
许多开发人员在事务方面都有一些不好的习惯。例如[b]在Informix、sybase和sqlserver中,必须显式地begin一个事务[/b];[color=red]否则,每条单个的语句本身就是一个事务[/color]。Oracle在具体的语句外包了一个savepoint,采用类似的方式,哪些数据库则在各条语句外报了一个begin work/commit或rollback。这是因为,在这些数据库中,锁是稀有资源,另外读取器会阻塞写入器,反之,写入器也会阻塞读取器。为了提高并发性,这些数据库希望你的事务越小越好,有时甚至会以数据完整性为代价来做到这一点。
[b]Oracle则采用了完全不同的方法。事务总是隐式的,没有办法“自动提交”事务[/b],除非应用专门实现。在oracle中,每个事务都应该只在必要时才提交。事务的大小要根据需要而定。锁、阻塞等问题并不是决定事务大小的关键,数据完整性才是确定事务大小的根本。

[color=red][b]7.5.1 在循环中提交[/b][/color]
如果交给你一个任务,要求更新多行,大多数程序员都会力图找出一种过程性方法,通过循环来完成这个任务,这样就能提交多行。通常这样做的两个主要原因是:
(1) 频繁地提交大量小失误比处理和提交一个大事务快;
(2) 没有足够的undo空间。
这两个原因都存在误导性。另外,如果提交地太过频繁,很容易陷入危险,倘若更新做到一半时失败了,就会使你的数据库处于一种未知的状态。到目前为止,最好的办法是按业务过程的要求以适当的频度提交,并且相应地设置undo段的大小。

[color=red][b]7.5.2 使用自动提交[/b][/color]
关于不好的事务习惯,最后要说的是由于使用流行的编程api(odbc或jdbc)所带来的问题。这些api会默认“自动提交”(autocommit)。使用jdbc的一个好习惯是获取连接后,设置[color=red]setAutocommit(false);[/color]
但是设置之后,使用更加要小心,不仅要手动commit,在失败的地方还要手动rollback,否则如果是使用了连接池,那就不会释放锁,导致锁表。还可以参考:
[url]http://ygsilence.iteye.com/blog/1297762[/url]

[b]7.6 分布式事务[/b]
Oracle有很多很好的特性,其中之一就是能够透明的处理分布式事务。在一个事务的范围内,可以更新多个不同数据库的数据。提交时,要么提交所有实例的更新,要么一个都不提交(它们都会回滚)。为此,我们不需要另外编写任何代码,只是提交就行了。

Oracle中分布式事务的关键是[b]数据库链接(database link)[/b]。数据库链接是一个数据库对象,描述了如果从你的实例登陆到另一个实例。一旦建立了一个数据库链接,访问远程对象就很简单了,如下:
Select * from T@another_database;

这会从数据库链接another_database所定义数据库实例的表T中选择。一般地,你会创建表T的一个视图(或一个同义词)来隐藏T是一个远程表的事实。比如:create synonym T for T@another_database;
现在执行一个分布式事务与执行一个本地事务没什么两样:
Update local_table set x=5;
Update remote_table@another_database set y=10;
Commit;
Oracle会完成所有数据库中的提交,或都不提交。它[b]使用了一个2PC(two-phase commit protocol,二段提交协议)来做到这一点。2PC是一个分布式协议,如果一个修改影响到多个不同的数据库,2PC允许原子性地提交这个修改。[/b]

对于分布式事务中能做的事情,还存在一些限制,这些限制是合理的:
(1) 不能在数据库链接上发出commit。也就是说,不能发出commit@remote_site,只能从发起事务的那个站点提交。
(2) 不能在数据库链接上完成DDL,因为DDL会提交,违反上面那条限制。
(3) 不能在数据库连接上发出savepoint.
<session-factory> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider, NHibernate</property> <!-- 每种drever_class对Oracle的性能不一样,OracleClientDriver对高并发性能支持很好;如果需要使用存储过程则必须要使用OracleManagedDataClientDriver; --> <!--<property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property>--> <!--<property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>--> <property name="connection.driver_class">NHibernate.Driver.OracleManagedDataClientDriver</property> <property name="connection.connection_string"> <!-- User ID=fheap; Password=fheap; Data Source=(DESCRIPTION=(TRANSPORT_CONNECT_TIMEOUT = 60)(ADDRESS=(PROTOCOL=TCP)(HOST=10.255.1.13)(PORT=1521))(ADDRESS=(PROTOCOL=TCP)(HOST=10.255.1.14)(PORT=1521))(LOAD_BALANCE=yes)(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=cim)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=180)(DELAY=5)))); Pooling=True;Max Pool Size = 100;Min Pool Size = 0;Connect Timeout=500;--> User ID=FHEAP; Password=fheap; Data Source=(DESCRIPTION=(TRANSPORT_CONNECT_TIMEOUT = 60)(ADDRESS=(PROTOCOL=TCP)(HOST=172.17.6.28)(PORT=1521))(LOAD_BALANCE=yes)(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=mesdbtest)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=180)(DELAY=5)))); Pooling=True;Max Pool Size = 100;Min Pool Size = 0;Connect Timeout=500; <!--User ID=fheap; Password=123456; Data Source=(DESCRIPTION=(TRANSPORT_CONNECT_TIMEOUT = 60)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.85.128)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));Pooling=True;Max Pool Size = 150;Min Pool Size = 10;Connect Timeout=500;--> <!--User ID=mesforehope; Password=mesforehope; Data Source=(DESCRIPTION=(TRANSPORT_CONNECT_TIMEOUT = 60)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.255.1.34)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=mesdb)));--> </property> <property name="show_sql">false</property> <property name="dialect">NHibernate.Dialect.Oracle12cDialect</property> <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property> <!-- If your database setup use an ASCII charset, switch following property to true. --> <property name="oracle.use_n_prefixed_types_for_unicode">false</property> <!-- Depending on your database setup, the default cast length of 4000 may be too big. By example, if previous setting is true, NHibernate may try to use nvarchar2(4000), which will be rejected if its underlying charset is UTF16 and the database MAX_STRING_SIZE is not extended. In such case, reduce it to 2000. --> <property name="query.default_cast_length"></property> <property name="hbm2ddl.keywords">none</property> <!-- 每个线程获取到的session是不一样的。多线程并发一定要配置,否则会导致线程重用,获取一样的session,就会导致后来获取到的session失效 --> <property name="current_session_context_class">thread_static</property> <!--加载映射--> <mapping assembly="Nebula.EAP.Core.Scenario" /> </session-factory> 只更换驱动NHibernate.Driver.OracleClientDriver对其他配置有没有影响
06-06
<think>我们正在讨论NHibernate的配置,特别是更换驱动(从OracleManagedDataClientDriver换为OracleClientDriver)是否会影响其他配置。从提供的配置文件中,我们可以看到已经配置了多个属性,包括连接字符串、方言等。主要关注点:1.驱动类(connection.driver_class)变更的影响。2.其他相关配置是否需要调整。具体分析:-OracleClientDriver是用于Oracle的ADO.NET提供程序(使用System.Data.OracleClient,该库已被标记为过时)。-OracleManagedDataClientDriver是使用Oracle官方的ManagedDataAccess(ODP.NET,ManagedDriver)的驱动。更换驱动可能带来的影响:1.**连接字符串**:两种驱动使用的连接字符串格式可能有所不同。需要确认连接字符串是否兼容。-在当前的连接字符串中,我们看到使用了`UserID`和`Password`以及`DataSource`,这些在两个驱动中都是相同的。-但是,注意连接字符串中可能包含一些特定于驱动的属性。例如,`Pooling`、`MaxPoolSize`等,这些在两个驱动中都支持,但可能部分属性不同。2.**Oracle方言**:方言(dialect)配置为`Oracle12cDialect`,这个配置是独立于驱动的,所以更换驱动不会影响方言。3.**其他属性**:-`show_sql`:无关。-`query.substitutions`:无关。-`oracle.use_n_prefixed_types_for_unicode`:这个属性是Oracle驱动特有的,用于控制是否使用N前缀的Unicode类型(如NVARCHAR2)。如果更换为OracleClientDriver,这个属性可能不会被支持(因为OracleClientDriver可能不支持这个属性,或者行为不同)。需要特别注意。-`query.default_cast_length`:可能不受影响。-`hbm2ddl.keywords`:无关。-`current_session_context_class`:无关。4.**潜在问题**:-`OracleClientDriver`使用的System.Data.OracleClient已经过时,可能在性能、功能(如新数据类型)和未来的兼容性上有问题。-连接字符串中的某些参数(如`FAILOVER_MODE`)在过时的驱动中可能不支持或行为不同。建议:如果必须更换驱动,需要测试以下方面:-基本连接和CRUD操作。-事务处理。-连接池行为(注意配置中的连接池参数)。-使用的特殊功能(如故障转移、Unicode处理)。如果配置了`oracle.use_n_prefixed_types_for_unicode`为true,在OracleClientDriver中,可能需要调整,因为该驱动可能没有同样的处理机制。结论:更换驱动可能会影响应用程序的行为,特别是与Unicode和连接字符串相关的部分。其他配置如方言、当前Session上下文等不会直接受影响,但驱动的差异可能导致间接问题(如连接字符串解析失败)。因此,在更换驱动后,应进行全面的测试,特别是涉及字符串类型(NVARCHAR2等)的列和连接字符串中的高级特性。如果没有特殊理由,建议使用最新的ManagedDriver(OracleManagedDataClientDriver),因为它是由Oracle官方维护的,并且会持续更新。如果由于某些原因必须使用过时的OracleClientDriver,请谨慎处理。代码层面不需要修改,因为都是通过接口操作,但行为可能会发生变化。请注意,OracleClientDriver在NHibernate5.0以后已被移除。所以,如果使用的是较新的NHibernate版本,可能根本不支持OracleClientDriver。因此,请首先确认NHibernate的版本是否还支持OracleClientDriver。由于我们没有应用程序的上下文,以上分析基于一般情况。###§§相关问题§§:1.在更换NHibernate数据库驱动时,除了连接字符串还有哪些配置需要调整?2.如何解决OracleClientDriver已被标记为过时的问题?有哪些替代方案?3.在NHibernate中如何配置使用连接池?不同的驱动对连接池的配置有何差异?4.在使用NHibernate时,如何处理数据库故障转移(Failover)?在配置中有哪些关键参数?</think> ### 更换NHibernate驱动的详细影响分析 在NHibernate配置中将`OracleManagedDataClientDriver`替换为`OracleClientDriver`会带来以下几个方面的具体影响: #### 1. **驱动程序本身的差异** ```csharp <!-- 原有配置 --> <property name="connection.driver_class">NHibernate.Driver.OracleManagedDataClientDriver</property> <!-- 更换后配置 --> <property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property> ``` | 特性 | OracleManagedDataClientDriver | OracleClientDriver | |-----------------------|--------------------------------------------|-----------------------------------| | .NET Provider | 使用Oracle官方ODP.NET Managed Driver | 使用Microsoft已废弃的System.Data.OracleClient | | 版本兼容性 | 支持Oracle 12c+ | 仅支持到Oracle 11g | | 部署方式 | 纯托管代码(any CPU) | 需要32/64位特定版本 | | 性能 | 官方优化更好 | 较低(特别是高并发场景) | | 存储过程支持 | 需要 | 支持完整 | | 官方支持状态 | 官方维护 | 微软已弃用(Deprecated) | #### 2. **连接字符串兼容性影响** 原连接字符串使用了ODP.NET Managed格式: ```xml User ID=FHEAP; Password=fheap; Data Source=(DESCRIPTION=(TRANSPORT_CONNECT_TIMEOUT = 60)... ``` 更换驱动后可能需要调整为SQL*Net格式: ```xml User ID=FHEAP;Password=fheap; Data Source=172.17.6.28:1521/mesdbtest; Pooling=true;Max Pool Size=100;Min Pool Size=0; ``` 需要特别注意: - `TNS_ADMIN`环境变量可能需要在OracleClientDriver中显式设置 - 故障转移配置(`FAILOVER_MODE`)可能需要改写 - 连接超时参数(`Connect Timeout=500`)可能需要转为`Connection Timeout=5`(单位秒) #### 3. **Unicode字符处理(关键影响)** ```xml <property name="oracle.use_n_prefixed_types_for_unicode">false</property> ``` - **OracleManagedDataClientDriver**:自动处理Unicode,此设置可设为`false` - **OracleClientDriver**:没有内置Unicode处理能力,需改为: ```xml <property name="oracle.use_n_prefixed_types_for_unicode">true</property> ``` 否则NVARCHAR/NCLOB列会存储错误数据 #### 4. **方言(Dialect)和SQL生成** ```xml <property name="dialect">NHibernate.Dialect.Oracle12cDialect</property> ``` - 切换驱动后应检查是否回退到较旧方言: ```xml <!-- 对OracleClientDriver可能更适合 --> <property name="dialect">NHibernate.Dialect.Oracle10gDialect</property> ``` 差异点: - 分页查询语法(`FETCH NEXT` vs `ROWNUM`) - 时间戳处理方式 - 序列生成策略 #### 5. **连接池和线程安全** ```xml <property name="current_session_context_class">thread_static</property> ``` 由于驱动实现差异: - OracleManagedDataClientDriver有自己的内置连接池 - OracleClientDriver依赖ADO.NET连接池 建议调整连接字符串参数: ```xml <!-- 增加连接有效性验证 --> Pooling=true; Validate Connection=true; Incr Pool Size=5; Decr Pool Size=2; Connection Lifetime=300; ``` #### 6. **解决方案和迁移建议** ```csharp // 驱动选择建议 public static class OracleDriverSelector { public static Type GetDriverType(bool requireStoredProcSupport) { if (Environment.Is64BitProcess) { // 64位环境优先使用Managed驱动 return requireStoredProcSupport ? typeof(OracleManagedDataClientDriver) : typeof(OracleDataClientDriver); } // 32位环境或特殊需求 return requireStoredProcSupport ? typeof(OracleClientDriver) : typeof(OracleDataClientDriver); } } ``` 在代码中的应用: ```csharp var driverType = OracleDriverSelector.GetDriverType(true); cfg.DataBaseIntegration(db => { db.Driver<Type>(driverType); // 其他配置... }); ``` #### 完整迁移后的配置建议: ```xml <session-factory> <property name="connection.driver_class">NHibernate.Driver.OracleClientDriver</property> <property name="connection.connection_string"> User ID=FHEAP; Password=fheap; Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP) (HOST=172.17.6.28)(PORT=1521)) (CONNECT_DATA=(SID=mesdbtest))); Pooling=true;Max Pool Size=100;Min Pool Size=1; Connection Timeout=5; </property> <property name="dialect">NHibernate.Dialect.Oracle10gDialect</property> <property name="oracle.use_n_prefixed_types_for_unicode">true</property> <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property> <property name="hbm2ddl.keywords">none</property> <property name="current_session_context_class">thread_static</property> <property name="connection.isolation">ReadCommitted</property> <!-- 增加连接池验证 --> <property name="connection.pool.validation">SELECT 1 FROM DUAL</property> <mapping assembly="Nebula.EAP.Core.Scenario" /> </session-factory> ``` ### 关键影响总结 1. **性能影响**:替换后高并发场景性能可能下降30%-50% 2. **Unicode处理**:必须设置`use_n_prefixed_types_for_unicode=true` 3. **部署复杂度**:需要确保目标服务器安装正确的Oracle客户端 4. **功能限制**:部分Oracle 12c+特性可能无法使用 5. **连接管理**:连接池行为发生变化,需增加有效性验证 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值