从Devart迁移至ODP.NET时遭遇ORA-08177事务序列化访问错误
ORA-08177: can't serialize access for this transaction 迁移问题排查
问题背景
从Devart数据库连接器切换到ODP.NET后,执行EF数据库迁移时触发ORA-08177错误。已完成以下操作但未解决:
- 安装指定版本ODP.NET,Oracle数据库版本符合要求
- 更新web.config、DBContext及基础控制器引用
- 删除所有迁移后重新创建首个迁移并清空库中表和视图
- 修改事务隔离级别为READ COMMITTED
- 降级ODP.NET版本
相关配置
web.config
<connectionStrings> <add name="DBContext" connectionString="User Id=aaaa;Password=1234;Data Source=OracleDataSource" providerName="Oracle.ManagedDataAccess.Client" /> </connectionStrings> <oracle.manageddataaccess.client> <version number="*"> <dataSources> <!-- Customize these connection alias settings to connect to Oracle DB --> <dataSource alias="OracleDataSource" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.68.202)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XE))) " /> </dataSources> </version> </oracle.manageddataaccess.client> <DbProviderFactories> <remove invariant="Oracle.ManagedDataAccess.Client" /> <add name="ODP.NET, Managed Driver" invariant="Oracle.ManagedDataAccess.Client" description="Oracle Data Provider for .NET, Managed Driver" type="Oracle.ManagedDataAccess.Client.OracleClientFactory, Oracle.ManagedDataAccess, Version=4.122.21.1, Culture=neutral, PublicKeyToken=89b483f429c47342" /> </DbProviderFactories> <dependentAssembly> <publisherPolicy apply="no" /> <assemblyIdentity name="Oracle.ManagedDataAccess" publicKeyToken="89b483f429c47342" culture="neutral" /> </dependentAssembly> </assemblyBinding> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework"> <parameters> <parameter value="v13.0" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" /> <provider invariantName="Oracle.ManagedDataAccess.Client" type="Oracle.ManagedDataAccess.EntityFramework.EFOracleProviderServices, Oracle.ManagedDataAccess.EntityFramework, Version=6.122.21.1, Culture=neutral, PublicKeyToken=89b483f429c47342" /> </providers> </entityFramework>
DBContext代码
namespace UFV.DBContext { public class UFVDBContext : DbContext { static UFVDBContext() { Database.SetInitializer<UFVDBContext>(new MigrateDatabaseToLatestVersion<UFVDBContext, Configuration>()); } //my entities... protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.HasDefaultSchema("MyScheme"); modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); } } }
排查方向与解决方案
1. 自定义迁移初始化器,强制设置事务隔离级别
MigrateDatabaseToLatestVersion默认可能使用序列化隔离级别执行迁移,即使全局设置了READ COMMITTED,迁移过程仍可能单独指定。可以自定义初始化器,显式设置事务隔离级别:
public class CustomMigrateInitializer : MigrateDatabaseToLatestVersion<UFVDBContext, Configuration> { public override void InitializeDatabase(UFVDBContext context) { // 获取底层Oracle连接并设置隔离级别 var oracleConn = context.Database.Connection as OracleConnection; if (oracleConn != null && oracleConn.State == ConnectionState.Closed) { oracleConn.Open(); using (var cmd = oracleConn.CreateCommand()) { cmd.CommandText = "SET TRANSACTION ISOLATION LEVEL READ COMMITTED"; cmd.ExecuteNonQuery(); } } base.InitializeDatabase(context); } } // 在DBContext静态构造函数中替换初始化器 static UFVDBContext() { Database.SetInitializer<UFVDBContext>(new CustomMigrateInitializer()); }
2. 修改连接字符串,显式指定隔离级别
在连接字符串中添加Isolation Level=ReadCommitted参数,强制ODP.NET使用指定隔离级别:
<add name="DBContext" connectionString="User Id=aaaa;Password=1234;Data Source=OracleDataSource;Isolation Level=ReadCommitted" providerName="Oracle.ManagedDataAccess.Client" />
3. 检查Oracle数据库的事务参数
- 确认数据库的
COMPATIBLE参数是否符合ODP.NET要求(XE版本需确保是11gR2及以上) - 检查是否有其他会话占用系统表(比如EF迁移用到的
__MigrationHistory表),可以通过查询V$SESSION查看当前活跃会话:
SELECT sid, serial#, username, status FROM v$session WHERE username = 'AAAA';
如果有残留会话,手动终止后再执行迁移。
4. 验证EF与ODP.NET版本兼容性
确保EF版本与Oracle.ManagedDataAccess.EntityFramework版本完全匹配:
- 若使用EF6,需对应ODP.NET的EF6组件版本(比如你当前用的6.122.21.1,需确认EF版本是6.x且无版本冲突)
- 清理项目的NuGet缓存,重新安装ODP.NET相关包,避免版本依赖混乱
5. 禁用EF迁移的事务(临时排查)
作为临时测试,可以禁用迁移过程中的事务,确认是否是事务隔离级别导致:
修改迁移配置类(Configuration.cs),设置AutomaticMigrationsEnabled = true并覆盖Seed方法,或者在Package Manager Console执行命令:
Add-Migration InitialCreate -NoTransaction Update-Database -NoTransaction
内容的提问来源于stack exchange,提问作者Victor Amell
相关产品推荐
相关产品推荐

