@Transactional 事务,控制不了缓存的更新。

本文探讨了在使用缓存时遇到的数据库与缓存不一致的问题,特别是在事务中更新缓存实体,当方法抛出异常后,数据库未被更新的情况。通过具体代码示例,分析了缓存对象直接修改所带来的问题,强调了缓存对象应避免提供setter方法,以确保数据一致性。

在一个事务Transactional内,查询缓存,并更新缓存实体;方法异常之后。数据库没有被更新。造成数据库和缓存不一致。

service代码如下:

public interface EmployeeService {

	public void CacheTest();
}

EmployeeServiceImpl代码如下:

@Service
public class EmployeeServiceImpl implements EmployeeService {

	private EmployeeService getProxy() {
		return (EmployeeService)AopContext.currentProxy();
	}
	@Override
	@Transactional
	public void CacheTest() {
		// from db
		Employee employee  = getProxy().findByUid("327d626c-bffc-11e9-b4c9-00163e06591c");
		// from cache
		employee  = getProxy().findByUid("327d626c-bffc-11e9-b4c9-00163e06591c");
		employee.setName("name  update");
		if (employee != null)
			throw new ApiException("dd");
	}
}

测试代码如下:

    @Test
    public void CacheTest(){
        try {

            employeeService.CacheTest();
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.info(employeeService.findByUid("327d626c-bffc-11e9-b4c9-00163e06591c").getName());

    }

打印的结果name update表示名字确实被更新了,但是我们没操作数据库,数据库没有被更新。

结论:

从缓存拿出来的对象不能随便更改。要和数据库保存一致。@Transactional注解对缓存没有效果。如果能实现,最好的方式是缓存的对象都没有setter方法。

转载于:https://my.oschina.net/kunBlog/blog/3095115

### 关于 @Transactional 事务提交慢的原因分析 #### 可能原因 1. **数据库锁竞争** 当多个线程或进程同时访问同一资源时,可能导致数据库锁的竞争。如果某些操作长时间持有锁,则会阻塞其他事务的执行,从而导致整体事务提交变慢[^1]。 2. **SQL 执行效率低下** 如果事务中的 SQL 查询或更新语句存在性能瓶颈(如缺少索引、全表扫描等),则可能显著延长事务的执行时间。这不仅影响当前事务,还可能引发连锁反应,进一步拖慢整个系统的响应速度[^2]。 3. **网络延迟** 数据库与应用程序之间的通信可能存在高延迟问题,尤其是在分布式环境中。这种情况下,每次交互都会增加额外的时间开销,进而影响事务的整体表现[^3]。 4. **日志写入压力** 默认情况下,大多数关系型数据库会在每次事务提交时将更改记录到磁盘上的重做日志文件中。如果日志写入频繁或者存储设备性能不足,则可能会成为性能瓶颈之一[^1]。 5. **隔离级别过高** 设置过高的事务隔离级别虽然可以减少脏读等问题的发生概率,但也增加了并发控制的成本。例如,在 SERIALIZABLE 隔离模式下运行大量复杂查询往往会导致严重的性能下降。 6. **嵌套事务不当配置** 虽然 Spring 支持嵌套事务功能,但如果未合理设置 `nestedTransactionAllowed` 参数 或者错误理解其工作原理,则容易造成不必要的回滚点创建以及其他副作用,最终降低效率。 --- ### 解决方案及优化措施 1. **调整数据库连接池参数** 合理规划最大活跃连接数、等待超时时间和预取大小等关键指标,确保能够满足高峰期负载需求的同时避免浪费系统资源。 2. **改进 SQL 性能** 定期审查并优化涉及的所有查询逻辑,添加适当索引来加速检索过程;对于批量插入/删除操作考虑采用更高效的方法代替逐条处理。 3. **启用异步提交 (Asynchronous Commit)** 对于那些对一致性要求不那么严格的应用场景来说,允许部分数据暂时处于不可见状态直到完全确认后再同步可见或许是一个不错的选择。这样可以在一定程度上缓解因持久化带来的延时困扰。 4. **降低默认隔离等级** 根据实际业务特点重新评估现有设定是否有必要维持如此严格的约束条件,并尝试切换至较低级别的选项比如 READ_COMMITTED 来换取更好的吞吐量表现 5. **利用只读事务特性** 将那些仅仅用于读取而不修改任何内容的操作标记为 readonly=true 属性值 ,以便让框架自动跳过一些耗时步骤如生成 undo log 等动作来提升速率 6. **加强硬件设施投入力度** 升级服务器型号选用更快更强力 的 CPU/GPU 组件 加大内存容量 提升硬盘I/O能力等等都是可行手段 7. **引入缓存机制减轻后台负担** 缓存热点数据减少重复请求次数缩短相应周期提高用户体验满意度 8. **定期清理无用历史记录保持整洁环境** 删除陈旧冗余的数据对象释放空间腾出更多可用额度供新资料储存使用 ```java @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { DataSourceTransactionManager tm = new DataSourceTransactionManager(dataSource); tm.setValidateExistingTransaction(true); // 检查已有事务是否存在冲突 tm.setNestedTransactionAllowed(true); // 开启支持嵌套事务的能力 return tm; } ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值