You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 07:55:55