SqlServer : java.sql.SQLException: 无法将 NULL 值插入列

文章详细解析了使用ibatis和hibernate时遇到的数据库操作错误,即无法将null值插入主键列导致的DataIntegrityViolationException。通过分析XML配置文件、SQL语句及异常堆栈,作者最终定位到问题原因在于数据库表的主键默认值配置不当,并提供了修改数据库表字段属性的解决方案。
调用ibatis的DAO:
2008-9-23 15:43:09 org.apache.catalina.core.ApplicationContext log
信息: org.springframework.dao.DataIntegrityViolationException: SqlMapClient operation; SQL [];
--- The error occurred in com/miracle/dm/sysmgr/log/sqlmapxml/Log_SqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the insertLog-InlineParameterMap.
--- Check the statement (update failed).
--- Cause: java.sql.SQLException: 无法将 NULL 值插入列 'log_id',表 'mloa.dbo.tb_log';该列不允许空值。INSERT 失败。; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
--- The error occurred in com/miracle/dm/sysmgr/log/sqlmapxml/Log_SqlMap.xml.
--- The error occurred while applying a parameter map.
--- Check the insertLog-InlineParameterMap.
--- Check the statement (update failed).
--- Cause: java.sql.SQLException: 无法将 NULL 值插入列 'log_id',表 'mloa.dbo.tb_log';该列不允许空值。INSERT 失败。



调用hibernate的DAO:
Hibernate: insert into TB_LOG (LOG_TYPE, LOG_USERID, USER_NAME, LOG_TIME, MODULE_CODE, LOG_CONTENT, OPER_CODE, REMARK) values (?, ?, ?, ?, ?, ?, ?, ?)
[@APPNAME@] WARN [http-80-8] JDBCExceptionReporter.logExceptions(77) | SQL Error: 515, SQLState: 23000
[@APPNAME@] ERROR [http-80-8] JDBCExceptionReporter.logExceptions(78) | 无法将 NULL 值插入列 'log_id',表 'mloa.dbo.tb_log';该列不允许空值。INSERT 失败。
org.springframework.dao.DataIntegrityViolationException: could not insert: [com.miracle.dm.sysmgr.log.model.LogInfo]; nested exception is org.hibernate.exception.ConstraintViolationException: could not insert: [com.miracle.dm.sysmgr.log.model.LogInfo]
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:628)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:408)
Log.hbm.xml中主键id的配置:
<id name="logId" column="LOG_ID">
<generator class="native"/>
</id>
按理说配置为native则会根据数据库自动帮你选择自增的类型,可为何还是报错?


直接采用查询分析器执行代码:

INSERT INTO TB_LOG (LOG_TYPE , LOG_USERID , USER_NAME , LOG_TIME , MODULE_CODE , LOG_CONTENT , OPER_CODE , REMARK ) VALUES ('DocumentAction' , '4212100010160', 'admin', '2008-09-23 15:43:09.156', 'Module1', 'admin用户新增文档ID_:547', 'ADD' ,'')
一样出现问题,显示结果:无法将 NULL 值插入列 'log_id',表 'mloa.dbo.tb_log';该列不允许空值。INSERT 失败。

修改sql语句,执行:
INSERT INTO TB_LOG (log_id,LOG_TYPE , LOG_USERID , USER_NAME , LOG_TIME , MODULE_CODE , LOG_CONTENT , OPER_CODE , REMARK ) VALUES ( 0, 'DocumentAction' , '4212100010160', 'admin', '2008-09-23 15:43:09.156', 'Module1', 'admin用户新增文档ID_:547', 'ADD' ,'')
显示结果:(所影响的行数为 1 行)

解决方法:
修改数据库中表的字段属性,注意默认值不要填,否则你无法设置标识为是,那么你将看到标识种子,标识递增量都显示为灰色。
“标识”选择为“是”,“标识种子”为1,“标识递增量”为1


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/foamflower/archive/2008/09/24/2972566.aspx
<think>嗯,我现在遇到了一个关于Spring事务嵌套的问题。用户提到在内层使用REQUIRES_NEW后,外层事务无法切换回来,而且还有SQLException导致的无法获取事务只读状态的错误。让我仔细想想怎么解决这个问题。 首先,我需要回忆一下Spring事务的传播机制。REQUIRES_NEW的意思是每次都会新建一个事务,如果当前存在事务,就将当前事务挂起。这样内层事务和外层事务应该是独立的,内层提交或回滚不会影响外层。但用户说外层事务无法切换回来,这可能是什么原因呢? 根据引用[2],当使用PROPAGATION_REQUIRES_NEW时,会暂停当前事务,创建新事务。这时候外层事务被挂起,内层事务完成后应该恢复外层事务。但如果恢复过程中出现问题,比如资源没有正确释放或连接未恢复,可能导致外层事务无法继续。可能需要检查事务管理器的实现,比如DataSourceTransactionManager是否正确处理连接的挂起和恢复。 另外,用户提到的SQLException关于只读状态的问题。假设某个操作尝试在只读事务中执行写操作,数据库会抛出异常。根据引用[3],事务的read-only属性默认是false,如果设置为true,但代码中有写操作,就会出错。或者,可能在配置事务时,某些方法错误地标记为只读,而实际需要写操作。 接下来,我需要考虑事务管理器的具体实现。比如,DataSourceTransactionManager在挂起事务时,会如何处理ConnectionHolder?根据引用[1],isExistingTransaction方法检查是否存在活跃的事务连接。如果内层事务提交后,连接没有被正确释放或重置状态,可能导致外层事务恢复时拿到的是一个已经关闭或只读的连接,从而引发异常。 可能的问题点: 1. 外层事务被挂起后,恢复时获取的连接状态不正确,比如仍处于只读模式。 2. 内层事务完成后,没有正确释放连接,导致外层事务使用的连接被污染。 3. 事务管理器的实现是否存在bug,或者配置有误,比如没有正确设置数据源的自动提交状态。 解决方案可能包括检查事务管理器的配置,确保连接池正确处理事务的挂起和恢复。另外,检查是否存在嵌套事务中混用只读和非只读的情况,导致连接状态冲突。 还需要查看具体的异常堆栈,确定SQLException的具体原因。例如,是否在恢复外层事务时,尝试在只读连接上执行写操作,从而触发异常。这时候需要检查事务定义中的read-only属性是否正确设置,以及方法是否需要写权限。 此外,可能涉及到的事务同步问题。比如,内层事务提交后,外层事务继续使用旧的连接,但该连接可能已经被设置为自动提交,或者状态未重置,导致后续操作失败。这时候需要确保事务管理器在恢复外层事务时,能够正确重置连接的状态。 可能还需要检查数据库驱动和Spring版本的兼容性,是否存在已知的问题。例如,某些旧版本的驱动在处理嵌套事务时可能有bug,导致连接状态管理错误。 总结一下,解决步骤可能包括: 1. 检查事务传播配置是否正确,确保内层方法使用REQUIRES_NEW。 2. 确认事务管理器是否正确处理连接的挂起和恢复,尤其是只读状态的切换。 3. 查看异常堆栈,定位具体的SQL错误,确认是否与只读状态相关。 4. 检查数据源配置,确保连接池支持嵌套事务的正确处理。 5. 考虑升级Spring或数据库驱动版本,修复可能的已知问题。</think>### 问题分析与解决方案 #### 1. 事务嵌套中REQUIRES_NEW导致外层事务无法恢复 **原因分析**: - **事务挂起与恢复机制问题**:当内层事务使用`PROPAGATION_REQUIRES_NEW`时,外层事务会被挂起,内层事务结束后应恢复外层事务。若事务管理器(如`DataSourceTransactionManager`)未正确恢复外层事务的连接状态(如只读标记、隔离级别等),可能导致后续操作失败[^2]。 - **连接未重置**:内层事务提交后,若连接未重置为非只读状态,可能导致外层事务继续使用该连接时触发`SQLException`。 **解决方案**: 1. **验证事务管理器配置**: - 确保事务管理器(如`DataSourceTransactionManager`)支持事务挂起和恢复。检查是否启用了`TransactionAwareDataSourceProxy`或`DataSource`是否支持连接绑定。 ```xml <bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> <constructor-arg ref="realDataSource"/> </bean> ``` 2. **检查连接状态恢复逻辑**: - 事务恢复时,需确保连接的只读状态和隔离级别与外层事务一致。例如,若外层事务为非只读,内层事务提交后需调用`Connection.setReadOnly(false)`重置状态[^1]。 3. **排查事务同步问题**: - 使用`TransactionSynchronizationManager`的调试日志,观察事务资源(如`ConnectionHolder`)的绑定与解绑过程。 --- #### 2. SQLException: 无法获取事务只读状态 **原因分析**: - **只读事务与写操作冲突**:若事务标记为只读(`read-only="true"`),但尝试执行写操作(如`INSERT`),数据库会拒绝并抛出异常。 - **连接池配置问题**:连接池未正确重置连接的只读状态,导致跨事务污染。 **解决方案**: 1. **检查事务定义**: - 确认`<tx:method>`中未错误标记写操作为只读。例如: ```xml <tx:method name="update*" read-only="false" propagation="REQUIRED"/> ``` 2. **显式设置只读状态**: - 在代码中通过`TransactionTemplate`显式控制只读标记: ```java transactionTemplate.setReadOnly(false); transactionTemplate.execute(status -> { // 执行写操作 return null; }); ``` 3. **验证数据库驱动兼容性**: - 某些数据库驱动(如MySQL)在只读连接上执行写操作时可能不会立即报错,但提交时会失败。需确保驱动版本与Spring兼容。 --- ### 代码示例:事务配置与调试 ```java // 启用事务调试日志 @Configuration @EnableTransactionManagement(order = Ordered.HIGHEST_PRECEDENCE) public class TransactionConfig implements TransactionManagementConfigurer { @Override public PlatformTransactionManager annotationDrivenTransactionManager() { DataSourceTransactionManager txManager = new DataSourceTransactionManager(dataSource()); txManager.setNestedTransactionAllowed(true); // 允许嵌套事务 return txManager; } } ``` --- ### 相关问题 1. **如何验证Spring事务的传播行为是否符合预期?** *回答提示*:通过`TransactionSynchronizationManager`日志或AOP切面记录事务边界。 2. **DataSourceTransactionManager和JpaTransactionManager在处理嵌套事务时有何区别?** *回答提示*:`JpaTransactionManager`依赖JPA提供者(如Hibernate)的事务管理能力,可能对连接池有额外要求[^3]。 3. **如何避免只读事务与写操作冲突?** *回答提示*:通过静态代码分析工具(如`Spring AOP`切面)拦截`@Transactional`注解并验证方法操作类型。 --- ### 引用说明 [^1]: `DataSourceTransactionManager`通过`ConnectionHolder`判断事务活跃状态,并在事务恢复时重置连接属性。 [^2]: `PROPAGATION_REQUIRES_NEW`会挂起当前事务并创建独立的新事务,二者状态需通过事务管理器严格隔离。 [^3]: 事务属性(如只读标记)需与方法实际操作一致,否则可能触发数据库级异常。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值