数据仓库: Oracle 11g
后台报错:DataIntegrityViolationException
详细日志:
Caused by: java.lang.ClassNotFoundException: org.springframework.dao.DataIntegrityViolationException
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at org.springframework.util.ClassUtils.forName(ClassUtils.java:257)
1.为什么报错DataIntegrityViolationException
DataIntegrityViolationException 这个异常是数据库插入时违反数据库约束引起 ,例如主键重复、向非空字段插入空值,或者插入字段违反表结构等
例如:
ORA-01438: value larger than specified precision allowed for this column
; nested exception is java.sql.SQLException: ORA-01438: value larger than specified precision allowed for this column
经过核实 OPERATORLOG 表的主键列设置为999999 ,实际数量只有70W+,并没有达到999999 , 主键列ID 是通过Sequence创建,查询Sequence最的最大值 已经到1000002,因此新插入行对象ID会越界造成DataIntegrityViolationException错误,
2. 为什么表行数和Sequence查询很大
OPERATORLOG 这张表是日志表, 其中会记录一些批量操作的日志, 为了节省效率, 将Sequence 设置了 cache =500, 但是一些异常情况下Spring事务回滚, 但是Sequence 不会回滚 造成 SEQ 值的浪费 因此出现了表行数小于 Sequence数值的情况
3. 为什么巡检没有发现问题
项目使用Oracle数据库,没有做分库分表,而是使用Oracle分区分表技术来解决表过大引起的性能问题
表的数量会持续增加,因此就需要售后人员定期巡检系统,当序列达到一定字段的时候,运行脚本扩容,因此团队要求序列的长度严格和主键长度一致,巡检时查询长度达到N%后对字段做扩容处理
--例如达到70%需要扩容
SELECT * FROM USER_SEQUENCES UC where UC.last_number > UC.max_value * 0.7
从脚本分析看由于序列的最大值没有设置成和主键长度一致造成了巡检时候没有发现问题
--记录SQL:通过Sequence找到表名和主键名等信息
--Oracle信息 USER_SEQUENCES 序列信息,USER_TAB_COLUMNS 表字段信息,USER_CONSTRAINTS 约束信息
--A:需列信息 序列命名要求SEQ_表名,所以使用了SUBSTR函数
--B:主键列:约束类型是P主键约束并且,POWER实现N次方计算
SELECT *
FROM (SELECT Q.SEQUENCE_NAME, Q.MAX_VALUE, Q.LAST_NUMBER, T.TABLE_NAME
FROM USER_SEQUENCES Q, USER_TABLES T
WHERE T.TABLE_NAME = SUBSTR(Q.SEQUENCE_NAME, 5)) A,
(SELECT C.TABLE_NAME,
CC.COLUMN_NAME,
TC.DATA_PRECISION,
POWER(10, TC.DATA_PRECISION) - 1 MAX
FROM USER_CONSTRAINTS C,
USER_CONS_COLUMNS CC,
USER_TAB_COLUMNS TC
WHERE CC.CONSTRAINT_NAME = C.CONSTRAINT_NAME
AND C.CONSTRAINT_TYPE = 'P'
AND TC.COLUMN_NAME = CC.COLUMN_NAME
AND TC.TABLE_NAME = C.TABLE_NAME) B
WHERE A.TABLE_NAME = B.TABLE_NAME
AND A.LAST_NUMBER > A.MAX_VALUE * 0.7
修改增加操作日志表OPERATORLOG主键的值,实现扩容
alter table OPERATORLOG modify OPERATORLOG_PK NUMBER(10);
1. 表空间和表分区
2. 表分区作用
Oracle的表分区功能通过改善可管理性、性能和可用性,从而为各式应用程序带来了极大的好处。通常,分区可以使某些查询以及维护操作的性能大大提高。此外,分区还可以极大简化常见的管理任务,分区是构建千兆字节数据系统或超高可用性系统的关键工具。
分区功能能够将表、索引或索引组织表进一步细分为段,这些数据库对象的段叫做分区。每个分区有自己的名称,还可以选择自己的存储特性。从数据库管理员的角度来看,一个分区后的对象具有多个段,这些段既可进行集体管理,也可单独管理,这就使数据库管理员在管理分区后的对象时有相当大的灵活性。但是,从应用程序的角度来看,分区后的表与非分区表完全相同,使用 SQL DML 命令访问分区后的表时,无需任何修改
3. 表分区的优缺点
优点:
缺点: