openSession事务提交不起作用

本文介绍了一个关于Hibernate中实体保存操作的改进案例。原先的方法中,保存操作与事务提交使用了不同的Session实例,导致事务提交无法影响之前的保存操作。通过调整代码确保两者使用同一个Session,从而实现了正确的事务管理。

源码:

public Long save(Person entity) {
        // TODO Auto-generated method stub
        Transaction tr=getSession().getTransaction();
        tr.begin();
        Long i=(Long)getSession().save(entity);
        getSession().flush();
        tr.commit();
        return i;

    }

更改为:

public Long save(Person entity) {
        // TODO Auto-generated method stub
        Session session=getSession();
        Transaction tr=session.getTransaction();
        tr.begin();
        Long i=(Long)session.save(entity);
        session.flush();
        tr.commit();
        return i;

    }

解释:

openSession每次调用都会新建一个session.所以源码中保存save和事务提交用的不是一个session,提交不对保存起作用。



<think> 我们参考了多个来源的资料,特别是MySQL事务提交、Spring事务提交以及Hibernate批量提交的相关内容。下面将结合这些资料逐步解释事务提交的步骤。 在数据库系统中,事务提交(Commit)是指将当前事务中的所有操作永久保存到数据库的过程。提交后,事务对数据库的修改将变为永久性的,其他事务可见。下面以MySQL为例,结合Spring框架和Hibernate ORM,详细说明事务提交的步骤: ### 1. **事务的开始与执行** - 事务通常以`BEGIN`或`START TRANSACTION`语句开始(在自动提交模式下,每个SQL语句本身就是一个事务)。 - 在事务中,执行一系列的SQL操作(如INSERT、UPDATE、DELETE等),这些操作会记录在事务日志(如InnoDB的undo log和redo log)中,但此时修改并未永久写入磁盘。 ### 2. **事务的两阶段提交(2PC)** 当MySQL开启binlog时(通常用于复制或恢复),事务提交采用两阶段提交协议(内部XA事务)[^1]: - **Prepare阶段**: - 存储引擎(如InnoDB)将事务的redo log写入磁盘,并将事务状态标记为"Prepare"。 - 此时事务尚未提交,但已确保日志持久化。 - **Commit阶段**: - 将事务的binlog写入磁盘。 - 存储引擎提交事务(将事务标记为已提交),并释放锁等资源。 - 最后,存储引擎清理undo log(根据隔离级别可能延迟清理)。 这种机制确保了binlog和存储引擎日志的一致性,即使系统崩溃也能恢复。 ### 3. **手动提交与自动提交** - **自动提交模式**(MySQL默认): 每个SQL语句执行后自动提交(隐式提交),无需显式调用`COMMIT`[^3]。 - **手动提交模式**: 用户需显式执行`COMMIT`语句提交事务。若未提交而关闭连接,事务将回滚[^3]。 ### 4. **Spring框架中的事务提交** 在Spring中,事务提交通过`PlatformTransactionManager.commit()`方法触发[^2]: - 若事务未标记为回滚(即`TransactionStatus.isRollbackOnly()==false`),则提交事务。 - Spring会调用底层资源管理器(如DataSourceTransactionManager)的提交逻辑: ```java // 简化后的Spring提交逻辑 public void commit(TransactionStatus status) { if (status.isRollbackOnly()) { rollback(status); // 回滚事务 } else { // 执行实际提交 doCommit(status); } } ``` - 对于JDBC事务,`doCommit()`最终调用`java.sql.Connection.commit()`。 ### 5. **Hibernate中的批量提交** 在Hibernate中,批量操作时建议显式管理事务[^4]: ```java Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for (int i = 0; i < 100000; i++) { session.save(new Entity(...)); if (i % 50 == 0) { // 分批刷新并清理缓存 session.flush(); session.clear(); } } tx.commit(); // 提交事务 session.close(); ``` - 这里`tx.commit()`触发Hibernate将缓存中的SQL批量发送到数据库执行并提交。 ### 6. **提交后的行为** - 事务提交后,释放所有锁资源。 - 在MySQL中,提交后修改对其他事务可见(取决于隔离级别)。 - 若提交失败(如违反约束),事务将回滚并抛出异常。 ### 总结事务提交的关键步骤: 1. **开始事务**(显式或隐式)。 2. **执行操作**(记录日志,暂存修改)。 3. **准备阶段**(持久化redo log,若启用binlog则进入2PC)。 4. **提交阶段**(持久化binlog,标记事务提交)。 5. **清理资源**(释放锁,清理undo log)。 6. **结束事务**(通知客户端成功)。 §§相关问题§§ 1. MySQL的两阶段提交是如何保证数据一致性的? 2. Spring事务管理中,如何配置事务的传播行为? 3. Hibernate批量提交时如何避免内存溢出? 4. 事务提交后还能回滚吗?为什么? </think> ### 事务提交步骤详解 结合MySQL、Spring框架及Hibernate的实现逻辑,事务提交的核心步骤如下: --- #### 1. **事务开始与操作积累** - 事务启动后(手动或自动),所有SQL操作(如INSERT/UPDATE/DELETE)暂存于**事务缓冲区**,而非直接写入磁盘。 - 修改仅在事务内可见(隔离级别控制),其他事务无法感知未提交的数据[^3][^4]。 --- #### 2. **日志写入(Prepare阶段)** - **开启binlog时(MySQL内部XA事务)**: - **Prepare阶段**:存储引擎(如InnoDB)将操作记录写入**redo log**(重做日志),并标记状态为`PREPARE`,确保崩溃可恢复[^1]。 - **Binlog写入**:将操作记录写入二进制日志(binlog),用于主从复制或数据恢复[^1]。 - **未开启binlog时**:直接进入存储引擎提交阶段[^3]。 --- #### 3. **正式提交(Commit阶段)** - **存储引擎提交**: - 将`PREPARE`状态的redo log标记为`COMMIT`,表明事务提交。 - 数据页修改按策略刷盘(可能延迟写入,依赖日志持久化保证一致性)[^1][^3]。 - **资源释放**: - 释放事务持有的**行锁/表锁**,其他事务可访问已提交数据。 - 清理undo log(回滚日志)中该事务的历史版本(根据隔离级别决定清理时机)[^3]。 --- #### 4. **框架层提交(以Spring为例)** - Spring调用`PlatformTransactionManager.commit()`: - 检查事务状态(`txInfo.getTransactionStatus()`),若非回滚状态则提交。 - 委托JDBC连接执行底层`java.sql.Connection.commit()`[^2]。 ```java // Spring事务提交伪代码 public void commit(TransactionStatus status) { if (status.isRollbackOnly()) { rollback(status); // 若需回滚则终止提交 } else { doCommit(status); // 执行数据库连接的commit() } } ``` --- #### 5. **批量提交优化(如Hibernate)** - **批处理场景**: - 循环执行`session.save()`暂存数据于内存,**不立即提交SQL**。 - 显式调用`tx.commit()`时,Hibernate将批量SQL一次性发送数据库,减少网络开销[^4]。 ```java Transaction tx = session.beginTransaction(); for (int i = 0; i < 10000; i++) { session.save(new Entity(i)); // 缓存操作 if (i % 50 == 0) { session.flush(); // 分批刷入数据库(未提交) session.clear(); // 清缓存防OOM } } tx.commit(); // 最终提交事务 ``` --- #### 关键特性总结 | 阶段 | 核心动作 | 依赖组件 | |---------------|--------------------------------------------------------------------------|-----------------------| | **操作积累** | SQL暂存事务缓冲区,修改不可见 | 事务隔离机制 | | **日志写入** | redo log → binlog(2PC), 确保持久化 | InnoDB存储引擎 | | **提交生效** | 日志标记`COMMIT`,释放锁,数据页异步刷盘 | 存储引擎日志系统 | | **框架提交** | Spring/Hibernate调用底层JDBC commit() | 应用层事务管理器 | | **批量优化** | 延迟提交+分批flush,避免内存溢出 | ORM框架缓存机制 | > ⚠️ **注意**:自动提交模式下(`@@autocommit=1`),每个SQL独立作为事务提交[^3];DDL语句(如`CREATE TABLE`)会触发隐式提交
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值