使用mybatis向数据库插入不进数据并且不报错

本文通过一个具体的例子说明了在使用MyBatis进行数据库操作时,如果忘记调用commit方法,即使程序运行成功也无法将数据插入到数据库中。作者原本认为在session关闭前会自动提交事务,但实际情况并非如此。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天在学习mybatis操作数据库时,发现程序运行成功,却一直插入不进数据。后来才发现是因为没有commit的问题,我原来以为session关闭之前它会帮我commit的,没想到并不是这样。

//添加用户
@Test
public void Test02() throws IOException{
//配置文件
String resource = "conf.xml";
//加载配置文件
Reader reader = Resources.getResourceAsReader(resource);
//构建sqlsession的工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(reader);
//创建能执行映射文件中sql的sqlSession
SqlSession session = sessionFactory.openSession();
//映射sql的表述字符串
String statement = "com.krt.mapping.userMapper.addUser";
User user = new User();
user.setName("用户神秘的男子");
user.setAge(22);
//执行插入操作
int retResult  = session.insert(statement, user);

session.commit();
//使用session执行完SQL之后需要关闭SqlSession
session.close();
System.out.println(retResult);
}

<think>我们正在处理的问题是:在Spring整合MyBatis环境下,执行插入操作时报错,但数据库中没有数据。根据用户提供的引用和之前的回答,我们可以从多个角度来排查。可能的原因及解决方案:1.**事务未提交**:在Spring中,如果使用了声明式事务(@Transactional),但事务配置正确,可能导致事务回滚而报错。或者,如果没有使用事务,但自动提交(autoCommit)被设置为false,且没有显式提交。-检查Spring的事务配置。确保在插入操作的方法或类上使用了`@Transactional`注解,并且事务管理器配置正确(如引用[4]中的`DataSourceTransactionManager`)。-检查数据库连接的autoCommit属性。在Spring配置的数据源中,可以设置autoCommit为true(但通常事务由事务管理器控制,建议直接设置autoCommit)。2.**MyBatis批处理操作未刷新**:如果使用MyBatis的批处理操作(如ExecutorType.BATCH),需要确保在操作后执行了`sqlSession.flushStatements()`和提交事务。-检查是否使用了批处理,如果是,确保刷新并提交。3.**MyBatis映射问题**:可能存在实体类属性与数据库字段映射一致的情况,导致插入时实际上插入了空值(但数据库可能因为主键约束等原因没有报错,或者插入的是空记录,但用户看不到)。-检查实体类与数据库表的映射。可以使用别名或者在MyBatis映射文件使用`resultMap`确保映射正确(如引用[5]中提到的别名方法)。4.**数据库连接问题**:虽然报错,但可能是数据库连接超时或连接被提前回收(如引用[2]中的连接超时问题)。-检查数据源配置,包括连接超时时间、空闲时间等。确保连接有效。5.**触发器或约束导致静默失败**:数据库中的触发器或约束可能导致插入被静默回滚(如之前的回答中提到的)。-检查数据库表是否有触发器或约束(如外键约束、唯一约束等),这些可能导致插入失败但报错。6.**日志级别设置过高**:可能错误日志被设置为显示,导致实际有错误但没有输出。-降低日志级别(如DEBUG级别),查看MyBatis执行时的详细日志。7.**插入操作未执行**:可能是代码逻辑问题,插入操作实际上没有被执行。-在插入操作前后打日志,确认是否执行到了插入语句。8.**主键冲突**:如果使用自增主键,但插入时指定了主键值,可能因为主键冲突导致插入失败,但MyBatis可能没有抛出异常(取决于配置)。-检查数据库表的主键设置和插入时是否提供了主键值。9.**数据库连接池配置问题**:如引用[2]中提到的,连接池配置当可能导致连接被回收,从而插入失败。-检查连接池配置(如最大连接数、最小空闲连接数、超时时间等)。具体排查步骤:步骤1:检查事务配置-确保在Service层的插入方法上添加了`@Transactional`注解。-检查事务管理器配置,如引用[4]中的配置:```xml<beanid="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><propertyname="dataSource"ref="VacationDataSource"/></bean>```确保数据源引用正确。步骤2:检查MyBatis的SQL执行日志-在日志配置文件中,将MyBatis的日志级别设置为DEBUG,例如在logback.xml中添加:```xml<loggername="com.your.mapper.package"level="DEBUG"/>```观察控制台输出的SQL语句,确认插入语句是否正确生成,以及参数是否正常。步骤3:手动提交事务(测试用)-在测试代码中,尝试在插入后手动提交事务(如果是编程式事务),但通常声明式事务会在方法结束时提交。步骤4:检查数据源配置-确保数据源的autoCommit属性没有被设置为false(除非使用事务管理)。在SpringBoot中,默认数据源(如HikariCP)的autoCommit是true,但事务管理器会覆盖它。-检查连接池的健康状态,确保连接有效。步骤5:检查数据库触发器-登录数据库,检查目标表是否有触发器,特别是`INSTEADOFINSERT`类型的触发器。步骤6:检查实体类映射-确认实体类中的字段与数据库表字段匹配,如果使用了`@Column`注解,确保名称正确。或者,在MyBatis的映射文件中,检查`insert`语句中的字段与数据库字段是否一致。步骤7:捕获MyBatis执行后的返回值-MyBatis插入操作会返回一个整数(受影响的行数)。在Service层,可以打印该返回值,确认是否成功插入了记录(返回值大于0表示成功)。```javaintrows=yourMapper.insert(yourEntity);System.out.println("插入行数:"+rows);```步骤8:检查数据库表结构-确认插入数据是否符合表结构约束(非空约束、唯一约束等)。虽然违反约束通常会抛出异常,但某些情况下(如触发器)可能会。示例解决方案:假设问题是由于事务未提交导致的,我们可以这样修改:1.在Service层方法上添加`@Transactional`:```java@ServicepublicclassYourServiceImplimplementsYourService{@AutowiredprivateYourMapperyourMapper;@Transactional//添加事务注解@OverridepublicvoidinsertData(YourEntityentity){yourMapper.insert(entity);}}```2.确保Spring配置中启用了注解驱动的事务管理:```xml<tx:annotation-driventransaction-manager="transactionManager"/>```如果问题仍然存在,请按照上述步骤逐一排查。如果以上步骤无法解决问题,可以考虑在插入后立即查询该数据(在同一事务中),看是否能查询到,以确定是插入失败还是查询时机问题。相关问题:1.如何在Spring中配置MyBatis的事务管理?2.MyBatis如何获取插入操作影响的行数?3.如何启用MyBatis的详细日志?4.Spring事务管理器的配置方式有哪些?5.如何检查数据库中的触发器?</think>### Spring + MyBatis 插入数据报错数据库为空解决方案 根据引用内容[1][4][5],结合Spring整合MyBatis的常见问题,以下是系统性排查方案: --- #### 1. **事务未提交(最常见原因)[^4]** **问题原因**: Spring事务管理未生效,导致操作在内存中完成但未持久化到数据库。 **解决方案**: ```xml <!-- 确保事务管理器配置正确 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 启用注解驱动事务 --> <tx:annotation-driven transaction-manager="transactionManager"/> ``` **代码层验证**: ```java @Service public class UserService { @Transactional // 必须添加事务注解 public void insertUser(User user) { userMapper.insert(user); // 测试事务:故意抛出异常观察数据是否回滚 // throw new RuntimeException("Test rollback"); } } ``` --- #### 2. **MyBatis映射错误(静默失败)[^5]** **问题原因**: 实体类字段与数据库列名匹配,导致数据被过滤。 **解决方案**: ```xml <!-- 方案1:在SQL中使用别名匹配 --> <insert id="insertUser"> INSERT INTO t_user(user_name AS name, user_age AS age) VALUES(#{name}, #{age}) </insert> <!-- 方案2:配置全局驼峰转换 --> <settings> <setting name="mapUnderscoreToCamelCase" value="true"/> </settings> <!-- 方案3:使用resultMap精确映射 --> <resultMap id="UserMap" type="User"> <result column="user_name" property="name"/> <result column="user_age" property="age"/> </resultMap> ``` --- #### 3. **连接池配置问题[^2]** **问题原因**: 连接池未正确提交事务或连接被提前回收。 **解决方案**: ```yaml # Spring Boot配置示例 (application.yml) spring: datasource: hikari: auto-commit: true # 关键配置 connection-timeout: 30000 max-lifetime: 1800000 ``` **代码验证**: ```java // 手动获取连接测试 try(Connection conn = dataSource.getConnection()) { conn.setAutoCommit(false); userMapper.insert(user); conn.commit(); // 显式提交 System.out.println("Inserted: " + user.getId()); } ``` --- #### 4. **MyBatis执行器类型问题** **问题原因**: 批处理模式(`ExecutorType.BATCH`)需要手动刷新。 **解决方案**: ```java // 手动刷新批处理 @Autowired private SqlSessionFactory sqlSessionFactory; public void batchInsert(List<User> users) { try(SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH)) { UserMapper mapper = session.getMapper(UserMapper.class); for(User user : users) { mapper.insert(user); } session.flushStatements(); // 关键刷新操作 session.commit(); } } ``` --- #### 5. **触发器/约束拦截(静默失败)** **诊断方法**: ```java // 在MyBatis日志中查看实际执行的SQL <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> ``` **数据库检查**: ```sql -- 检查MySQL触发器 SHOW TRIGGERS LIKE 'your_table'; -- 检查约束 SELECT * FROM information_schema.TABLE_CONSTRAINTS WHERE TABLE_NAME = 'your_table'; ``` --- #### 6. **主键生成策略错误** **问题原因**: ID生成策略导致数据看似插入成功但实际冲突。 **解决方案**: ```xml <!-- 明确指定主键策略 --> <insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> INSERT INTO t_user(name) VALUES(#{name}) </insert> ``` --- #### 排查流程图 ```mermaid graph TD A[数据未保存] --> B{检查MyBatis日志} B -->|无INSERT日志| C[验证Mapper调用] B -->|有INSERT日志| D[检查事务提交] D -->|事务未提交| E[添加@Transactional] D -->|事务已提交| F[检查字段映射] F -->|映射错误| G[配置resultMap] F -->|映射正常| H[检查连接池autoCommit] H -->|autoCommit=false| I[配置连接池] H -->|配置正常| J[检查数据库触发器] ``` --- #### 验证工具 1. **日志监控**: ```xml <!-- logback.xml配置 --> <logger name="org.mybatis" level="DEBUG"/> <logger name="org.springframework.jdbc" level="DEBUG"/> ``` 2. **即时查询验证**: ```java @Transactional public void insertAndVerify(User user) { userMapper.insert(user); User inserted = userMapper.selectById(user.getId()); if(inserted == null) { throw new RuntimeException("数据未持久化!"); } } ``` ---
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值