oracle 修改nls_characterset,修改props$.NLS_CHARACTERSET导致ORA-00900异常恢复

今天一朋友和我说他的数据库不能open,open过程提示ORA-00900错误,通过分析alert日志和props$表,发现他们修改了一个无效的NLS_CHARACTERSET值,导致数据库无法正常启动(准确的说,因为数据库里面该值无效,当数据库open的过程中,检测到控制文件指定的编码和该值不一致,然后修改控制文件的编码,修改之后,数据库一到mount状态执行任何语句都报ORA-00900错误),通过一些工具修改NLS_CHARACTERSET为正确值该故障解决

重现ORA-00900故障

SQL> select * from v$version;

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - Production

PL/SQL Release 11.2.0.3.0 - Production

CORE 11.2.0.3.0 Production

TNS for Linux: Version 11.2.0.3.0 - Production

NLSRTL Version 11.2.0.3.0 - Production

SQL> select value$ from props$ where name='NLS_CHARACTERSET';

VALUE$

-------------------------------------------------------

ZHS16GBK

SQL> update props$ set value$='AL16UTF16' where name='NLS_CHARACTERSET';

1 row updated.

SQL> commit;

Commit complete.

SQL> alter database backup controlfile to trace as '/tmp/ora11g.ctl';

Database altered.

SQL> shutdown immediate;

Database closed.

Database dismounted.

ORACLE instance shut down.

SQL> startup

ORACLE instance started.

Total System Global Area 175775744 bytes

Fixed Size 1343668 bytes

Variable Size 117444428 bytes

Database Buffers 50331648 bytes

Redo Buffers 6656000 bytes

Database mounted.

ORA-01092: ORACLE instance terminated. Disconnection forced

ORA-00604: error occurred at recursive SQL level 1

ORA-00900: invalid SQL statement

Process ID: 5277

Session ID: 125 Serial number: 5

SQL> startup nomount;

ORACLE instance started.

Total System Global Area 175775744 bytes

Fixed Size 1343668 bytes

Variable Size 117444428 bytes

Database Buffers 50331648 bytes

Redo Buffers 6656000 bytes

SQL> alter database mount;

Database altered.

SQL> alter database open;

alter database open

*

ERROR at line 1:

ORA-00900: invalid SQL statement

SQL>select * from dual;

select * from dual

*

ERROR at line 1:

ORA-00900: invalid SQL statement

SQL> shutdown abort

ORACLE instance shut down.

第一次startup(open)过程报错

SMON: enabling tx recovery

Updating character set in controlfile to AL16UTF16

Errors in file /u01/oracle/diag/rdbms/ora11g/ora11g/trace/ora11g_ora_5277.trc:

ORA-00604: error occurred at recursive SQL level %s

ORA-00900: invalid SQL statementursive SQL level %s

Errors in file /u01/oracle/diag/rdbms/ora11g/ora11g/trace/ora11g_ora_5277.trc:

ORA-00604: error occurred at recursive SQL level %s

ORA-00900: invalid SQL statementursive SQL level %s

Error 604 happened during db open, shutting down database

USER (ospid: 5277): terminating the instance due to error 604

Errors in file /u01/oracle/diag/rdbms/ora11g/ora11g/trace/ora11g_smon_5243.trc:

ORA-00604: error occurred at recursive SQL level %s

ORA-00900: invalid SQL statementursive SQL level %s

Instance terminated by USER, pid = 5277

ORA-1092 signalled during: ALTER DATABASE OPEN...

opiodr aborting process unknown ospid (5277) as a result of ORA-1092

Sat May 18 00:44:27 2013

ORA-1092 : opitsk aborting process

这里比较明显的看到有一条(Updating character set in controlfile to AL16UTF16),正是由于这个操作,更新控制文件的编码为一个无效的编码,从而导致在后面数据库mount(加载控制文件)之后,就不能再进行其他任何操作

解决思路

使用odu找出来block位置,或者在同版本库中查询

使用dul或者bbed修改props$的NLS_CHARACTERSET值

重建控制文件(noresetlogs方式)

处理过程

SQL> shutdown abort

ORACLE instance shut down.

odu找出来block位置

dul或者bbed修改block值

重建控制文件(noresetlogs方式)

SQL> startup

ORACLE instance started.

Total System Global Area 175775744 bytes

Fixed Size 1343668 bytes

Variable Size 117444428 bytes

Database Buffers 50331648 bytes

Redo Buffers 6656000 bytes

Database mounted.

ORA-01113: file 1 needs media recovery

ORA-01110: data file 1: '/u01/oracle/oradata/ora11g/system01.dbf'

SQL> recover database;

Media recovery complete.

SQL> alter database open;

Database altered.

从oracle 9i开始,修改数据库的编码,直接使用alter database character set internal_use方式进行,而不要使用直接修改props$基表,更不能修改一个实际中不存在的编码值(本文中数据库编码和国家编码搞混淆从而出现该故障)

<think>好的,我现在需要帮助用户解决在使用Java读写Oracle数据库时如何根据NLS配置参数正确设置编码格式的问题。首先,我得理解用户的需求。用户提到了OracleNLS参数,如NLS_LANGUAGE、NLS_TERRITORY、NLS_CHARACTERSET等,并且具体版本是Oracle 11.2.0.4.0。用户想知道如何在Java中根据这些参数设置正确的字符编码进行读写操作。 首先,我需要回忆一下OracleNLS参数的作用。根据用户提供的引用内容,NLS参数决定了数据库的本地化设置,比如语言、日期格式、字符集等。特别是NLS_CHARACTERSET,这应该直接关系到数据库使用的字符编码,比如AL32UTF8对应UTF-8编码。而NLS_LANGUAGE和NLS_TERRITORY可能影响日期、货币格式,但字符编码主要还是看NLS_CHARACTERSET。 接下来,Java连接Oracle数据库通常使用JDBC驱动。用户需要使用合适的JDBC URL,并且在其中指定字符集。例如,在连接字符串中添加字符集参数,比如useUnicode=true和characterEncoding=UTF-8。这部分是关键,因为如果数据库的字符集是AL32UTF8,而Java端使用UTF-8编码,就能正确转换字符。 然后,可能需要考虑数据库和Java应用的字符集一致性。如果数据库使用ZHS16GBK,而Java应用使用UTF-8,这时候可能会出现乱码。因此,必须确保两边的字符集设置匹配,或者在Java中进行适当的转换。 另外,NLS_LANG环境变量的作用是什么?根据引用内容,NLS_LANG参数格式为NLS_LANGUAGE_NLS_TERRITORY.NLS_CHARACTERSET。例如,AMERICAN_AMERICA.AL32UTF8。这个环境变量告诉Oracle客户端(包括JDBC驱动)如何解析和发送数据。如果Java应用运行的环境没有正确设置NLS_LANG,可能会导致字符转换错误。因此,用户可能需要设置这个环境变量,或者在Java代码中通过参数传递。 不过,根据我的记忆,在Java中,有时候JDBC驱动会忽略NLS_LANG的设置,而是依赖于连接参数。所以,用户更应该关注JDBC连接字符串中的字符编码设置,以及确保Java应用的默认编码与数据库一致。 然后,我需要验证这些信息是否正确。比如,当数据库字符集是AL32UTF8时,JDBC连接应该使用UTF-8编码。如果数据库是ZHS16GBK,则Java端可能需要使用GBK编码。此外,在Java代码中处理字符串时,确保所有输入输出都使用正确的字符集,避免使用默认的平台编码,这可能会导致不一致。 还有,用户可能需要检查数据库的NLS参数,可以通过查询NLS_DATABASE_PARAMETERS或NLS_SESSION_PARAMETERS。例如,运行SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_LANGUAGE', 'NLS_TERRITORY'); 来获取实际的字符集设置。这一步很重要,因为只有知道数据库的实际配置,才能正确设置Java端的编码。 另外,关于Oracle的版本11.2.0.4.0,这个版本是否对字符集处理有特别的要求?可能需要确认JDBC驱动的版本是否兼容,推荐使用ojdbc6或ojdbc7驱动,因为旧版本驱动可能存在编码问题。 还有可能涉及到的点是,在Java中处理字符串时,特别是从ResultSet读取或向PreparedStatement写入数据时,确保使用了正确的字符集。例如,在读取时使用getString()方法,JDBC驱动应该会自动处理编码转换,前提是连接参数正确设置。 总结一下,解决步骤应该是: 1. 确定数据库的NLS_CHARACTERSET,这是关键参数。 2. 在Java的JDBC连接字符串中指定对应的字符编码,如characterEncoding=UTF-8。 3. 确保Java应用的默认编码与数据库字符集一致,或者在代码中显式处理编码转换。 4. 必要时设置NLS_LANG环境变量,但可能JDBC驱动会覆盖这个设置。 5. 使用合适的JDBC驱动版本。 可能还需要提到如何在代码中处理字符编码,比如使用字节数组转换,或者在读写时指定字符集,但一般来说,只要JDBC连接参数正确,驱动会自动处理这些转换。 最后,生成相关问题的时候,需要考虑用户可能进一步的问题,比如如何查询NLS参数,如何处理乱码,或者不同字符集之间的转换问题等。</think>在使用Java读写Oracle数据库时,正确设置字符编码需遵循以下步骤: ### 一、理解NLS参数与编码的关系 1. **NLS_CHARACTERSET**:数据库字符集(如`AL32UTF8`或`ZHS16GBK`),直接决定字段的字符编码方式。Java应用编码需与之匹配[^2]。 2. **NLS_LANGUAGE/NLS_TERRITORY**:影响日期、货币格式,但不直接影响字符编码[^1]。 ### 二、Java端配置步骤 #### 1. 确定数据库字符集 ```sql SELECT VALUE FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET'; ``` 若结果为`AL32UTF8`,则需使用UTF-8编码;若为`ZHS16GBK`,则需使用GBK编码。 #### 2. 配置JDBC连接参数 在连接URL中显式声明字符集: ```java String url = "jdbc:oracle:thin:@host:1521/service"; url += "?useUnicode=true&characterEncoding=UTF-8"; // 与NLS_CHARACTERSET对应 ``` #### 3. 设置JVM默认编码 启动JVM时添加参数: ```bash -Dfile.encoding=UTF-8 ``` #### 4. 验证环境变量 确保服务端/客户端的`NLS_LANG`与数据库字符集一致: ```bash export NLS_LANG=AMERICAN_AMERICA.AL32UTF8 ``` ### 三、代码示例(UTF-8环境) ```java // 加载驱动 Class.forName("oracle.jdbc.driver.OracleDriver"); // 连接字符串包含编码参数 String url = "jdbc:oracle:thin:@localhost:1521/ORCLCDB?useUnicode=true&characterEncoding=UTF-8"; try (Connection conn = DriverManager.getConnection(url, "user", "pass"); PreparedStatement pstmt = conn.prepareStatement("INSERT INTO test VALUES(?)")) { // 直接使用String类型,JDBC会自动转码 pstmt.setString(1, "中文测试"); pstmt.executeUpdate(); } ``` ### 四、特殊场景处理 若遇到`ORA-29275`编码错误,需通过字节流转换: ```java String chineseStr = "中文"; byte[] bytes = chineseStr.getBytes("GBK"); // 当数据库为ZHS16GBK时 Blob blob = conn.createBlob(); blob.setBytes(1, bytes); ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值