mysql+Spring数据库隔离级别与性能分析

所属分类: 数据库 / Mysql 阅读数: 1950
收藏 0 赞 0 分享

这里以mysql为例,先明确以下几个问题:

一.一般项目如果不自己配置事务的话,一般默认的是autocommit,即执行完一个操作后自动commit,提交事务。

(注:事务是绑定在数据库操作上的,也就是当程序执行(statement.excute等操作)转而到数据库层面上的时候,事务才开始发生)
当然spring可以将几个数据库操作动作绑在一个事务中,这样就需要介绍下spring事务配置方法,下面介绍的是常用方法,其他方法网上有很多。
spring提供了很多事务配置的策略,很方便,简要介绍一下:

复制代码 代码如下:

 <property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
</props>

一般spring配置事务都是以上的配法,具体参数的意思有不懂的上网自己查吧,那么需要注意以下几点:(题外话)
1.我习惯将事务配置在service上,这时需要注意,只有service中以save、update等开头的方法,配置的事务才有效果。如果service中的方法名不是以save等开头的,比如taskSave()方法,即使在实现类中调用了service中的update方法,配置事务也失效,我试过。
2.readOnly这个属性很有意思,因为用了它后,会自动将数据库的隔离级别提高了一级,由提交读变为重复读,这块我后面说明。

二.数据库隔离级别

数据库隔离级别主要有以下四个:不可提交读,提交读,重复读和序列化读(以下理解可以不看)。
1. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
     这种隔离级别会产生脏读,不可重复读和幻像读。
2. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据
3. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
     它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
4. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
     除了防止脏读,不可重复读外,还避免了幻像读。
mysql默认的隔离级别是重复读,即 ISOLATION_REPEATABLE_READ。

注意:其中未提交读与序列化读不常用,未提交读危险性太高,会读到很多脏数据。而可串行化读是通过将读取的每一行数据加锁,以耗费性能为代价换取的,所以使用也很少,大部分数据库的隔离级别是提交读,比如oracle、sqlserver。而mysql默认的数据隔离级别是可重复读。

下面我来结合项目分析以下调整数据库隔离级别对性能的影响:
本地mysql数据库由ISOLATION_REPEATABLE_READ级别降低到ISOLATION_READ_COMMITTED级别:

场景:未用Spring,用户A在一个事务中对数据库发出两次查询请求,在两次查询之间,用户B对数据库的记录进行修改。

结果:ISOLATION_REPEATABLE_READ级别:用户A两次查询结果不一样。

          ISOLATION_READ_COMMITTED级别:用户A两次查询结果一样,因为对记录进行了加锁操作。


以task模块为例,在本地运行任务首页,通过对比分析两种事务处理方式得到如下结果(每次统计数据前均清理浏览器缓存,统计3次取平均值):


发现降低数据库事务的隔离级别,对于一些特殊逻辑的操作上,性能有所提升。
但是如果查询过程中,不涉及同一事务中多次对数据库操作的复杂逻辑及同一事务中多次查询同一结果集的逻辑,则对速度的提升效果并不明显,即事务进行时对数据集加锁的时间是可以忽略的,下面再来理解一下事务隔离级别与锁的关系。

谈到数据库隔离级别,就要说一下锁的概念:

主要分为共享锁和排他锁。
共享锁:由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写

排它锁:由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁,典型是mysql事务中。

个人理解:共享锁和排他锁没有严格的界限,我认为应该通过结果确定加的是共享锁还是排他锁。

例如:用户A修改一条数据,用户B也修改这条数据,挂起。 但是B查看这个数据可以,证明A用户添加了行级共享锁。

再例如:用户A修改一条数据,用户B查询这条数据失败,查询其他数据也失败。那么肯定A加了表级排他锁。

再例如:用户A修改一条数据,用户B查询记录可以,但是修改这条记录不行,修改其他记录也不行,那么A加了表级共享锁。

不同的数据隔离级别,加的锁是不一样的。

回到前面的问题,readonly属性一旦被设置后,数据库级别如果为提交读,那么同一个事务中,如果对两次结果集进行查询,中间间隔修改数据库,那么应该会是同一个结果集,相当于查询的时候采用的是重复读的隔离级别。

更多精彩内容其他人还在看

Mac 将mysql路径加入环境变量的方法

这篇文章主要介绍了Mac如何将mysql路径加入环境变量,有需要的朋友好按照下面的步骤操作即可
收藏 0 赞 0 分享

mysql 增加修改字段类型及删除字段类型

本节主要介绍了mysql如何增加修改字段类型及删除字段类型,需要的朋友可以参考下
收藏 0 赞 0 分享

Mysql主从复制(master-slave)实际操作案例

这篇文章主要介绍了Mysql主从复制(master-slave)实际操作案例,同时介绍了Mysql grant 用户授权的相关内容,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL异常处理浅析

这篇文章主要介绍了MySQL的异常处理,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL存储毫秒数据的方法

MySQL中没有可以直接存储毫秒数据的数据类型,但是不过MySQL却能识别时间中的毫秒部分。这篇文章主要介绍了MySQL存储毫秒数据的方法,需要的朋友可以参考下
收藏 0 赞 0 分享

MySql中使用INSERT INTO语句更新多条数据的例子

这篇文章主要介绍了MySql中使用INSERT INTO语句更新多条数据的例子,MySQL的特有语法,需要的朋友可以参考下
收藏 0 赞 0 分享

Windows下MySql错误代码1045的解决方法

这篇文章主要介绍了Windows下MySql错误代码1045的解决方法,文中还包含了2个Linux下的解决方法,需要的朋友可以参考下
收藏 0 赞 0 分享

mysql查询今天、昨天、近7天、近30天、本月、上一月的SQL语句

这篇文章主要介绍了mysql查询今天、昨天、近7天、近30天、本月、上一月的SQL语句,一般在一些统计报表中比较常用这个时间段,需要的朋友可以参考下
收藏 0 赞 0 分享

mysql的中文数据按拼音排序的2个方法

这篇文章主要介绍了mysql的中文数据按拼音排序的2个方法,用于一些特殊环境,需要的朋友可以参考下
收藏 0 赞 0 分享

MySQL定期分析检查与优化表的方法小结

听DBA的人说,相比oracle,MySQL就是一个玩具级别的数据库,在网易门户中,DBA基本很少去管理到MySQL的东西,所以我们产品使用到的MySQL的一些配置和优化还是需要我们开发人员自己动手,下面就简单介绍一下实用的定期优化方法
收藏 0 赞 0 分享
查看更多