学习笔记-数据库

2016年03月13日

学习笔记-数据库

Note:参阅书籍《Spring 3.x 企业应用开发实战》

MySQL数据库引擎

MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的。要添加一个新的引擎,就必须重新编译MYSQL。在缺省情况下,MYSQL支持三个引擎:ISAM、MYISAM和HEAP。另外两种类型INNODB和BERKLEY(BDB),也常常可以使用。如果技术高超,还可以使用MySQL+API自己做一个引擎。

  • ISAM:ISAM是一个定义明确且历经时间考验的数据表格管理方法,它在设计之时就考虑到 数据库被查询的次数要远大于更新的次数。因此,ISAM执行读取操作的速度很快,而且不占用大量的内存和存储资源。ISAM的两个主要不足之处在于,它不 支持事务处理,也不能够容错:如果你的硬盘崩溃了,那么数据文件就无法恢复了。如果你正在把ISAM用在关键任务应用程序里,那就必须经常备份你所有的实 时数据,通过其复制特性,MYSQL能够支持这样的备份应用程序。

  • MyISAM:MyISAM是MySQL的ISAM扩展格式和缺省的数据库引擎。除了提供ISAM里所没有的索引和字段管理的大量功能,MyISAM还使用一种表格锁定的机制,来优化多个并发的读写操作,其代价是你需要经常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的空间。MyISAM还有一些有用的扩展,例如用来修复数据库文件的MyISAMCHK工具和用来恢复浪费空间的 MyISAMPACK工具。MYISAM强调了快速读取操作,这可能就是为什么MySQL受到了WEB开发如此青睐的主要原因:在WEB开发中你所进行的大量数据操作都是读取操作。所以,大多数虚拟主机提供商和INTERNET平台提供商只允许使用MYISAM格式。MyISAM格式的一个重要缺陷就是不能在表损坏后恢复数据。

  • InnoDB:InnoDB数据库引擎都是造就MySQL灵活性的技术的直接产品,这项技术就是MYSQL+API。在使用MYSQL的时候,你所面对的每一个挑战几乎都源于ISAM和MyISAM数据库引擎不支持事务处理(transaction process)也不支持外来键。尽管要比ISAM和 MyISAM引擎慢很多,但是InnoDB包括了对事务处理和外来键的支持,这两点都是前两个引擎所没有的。

  • HEAP:HEAP允许只驻留在内存里的临时表格。驻留在内存里让HEAP要比ISAM和MYISAM都快,但是它所管理的数据是不稳定的,而且如果在关机之前没有进行保存,那么所有的数据都会丢失。在数据行被删除的时候,HEAP也不会浪费大量的空间。HEAP表格在你需要使用SELECT表达式来选择和操控数据的时候非常有用。要记住,在用完表格之后就删除表格。

  • MyISAM与InnoDB的区别:InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。

数据库事务基础知识

  • 定义:“一荣俱荣,一损俱损”这句话很能体现事务的思想,很多复杂的事务要分布进行,但它们组成一个整体,要么整体生效,要么整体失败。
  • 事务必须同时满足4个特性:原子性、一致性、隔离性、持久性。简称为ACID,在这些特性中,数据一致性是最终目标,其他的特性都是为达到这个目标的措施、要求或手段。
    • 原子性(Atomic):表示组成一个事务的多个数据库操作是一个不可分割的原子单元,只有所有的操作执行成功,整个事务才提交,事务中任何一个数据库操作失败,已经执行的任何操作都必须撤销,让数据库返回到初始状态。
    • 一致性(Consistency):事务操作成功后,数据库所处的状态和它的业务规则是一致的,即数据不会被破坏。例如:A和B之间进行转账操作,即不论进行何种操作,操作成功与否,A和B的总额是不变的。
    • 隔离性(Isolation):在并发数据操作时,不同事务拥有各自的数据空间,它们的操作不会对对方产生干扰。隔离级别越高,数据一致性越好,并发性越弱。
    • 持久性(Durabiliy):一旦事务提交成功后,事务中所有的数据操作都必须被持久化到数据库中。
  • Java程序采用对象锁机制进行线程同步;数据库管理系统采用数据库锁机制保证事务的隔离性。
  • 本地事务&分布式事务
    • 本地事务:就是普通事务,能保证单台数据库上的操作的ACID,被限定在一台数据库上;
    • 分布式事务:涉及两个或多个数据库源的事务,即跨越多台同类或异类数据库的事务(由每台数据库的本地事务组成的),分布式事务旨在保证这些本地事务的所有操作的ACID,使事务可以跨越多台数据库;

数据并发问题

  • 数据库并发问题可以归结为5类:3类数据读问题(脏读,不可重复读,幻象读),2类数据更新问题(第一类丢失更新,第二类丢失更新。)
    • 脏读(dirty read):A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。Oracle数据库中,不会发生脏读的情况。
    • 不可重复读(unrepeatable read):不可重复读是指A事务读取了B事务已经提交的更改数据。
    • 幻象读(phantom read):A事务读取B事务提交的新增数据,这时A事务将出现幻象读的问题。
    • 第一类丢失更新:A事务撤销时,把已经提交的B事务的更新数据覆盖了。
    • 第二类丢失更行:A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失。

数据库锁机制

  • 数据库通过锁的机制解决并发访问的问题。
    • 锁定的对象的不同,可以分为表锁定行锁定,前者对整个表进行锁定,后者对表中特定行进行锁定。
    • 从并发事务锁定的关系上看,可以分为共享锁定独占锁定。共享锁定会防止独占锁定,但允许其他的共享锁定。而独占锁定既防止其他的独占锁定,也防止其他的共享锁定。
  • 为了更改数据,数据库必须在进行更改的行上施加行独占锁定,insert,update,delete和select for update语句都会隐式采用必要的行锁定。
  • Oracle数据库常用的5种锁定:
    • 行共享锁定:一般通过select for update语句隐式获得行共享锁定。
    • 行独占锁定:通过一条insert、update 或 delete语句隐式获取。
    • 表共享锁定:通过lock table in share mode语句显示获得。
    • 表共享行独占:通过lock table in share row exclusive mode语句显示获得。
    • 表独占:通过lock table in exclusive mode 显示获得。

事务隔离级别

  • 数据库为用户提供了自动锁机制,只要用户指定会话的事务隔离级别,数据库就会分析事务中SQL语句。
隔离级别脏读不可重复读幻象读第一类丢失更新第二类丢失更新
READ UNCOMMITED允许允许允许不允许允许
READ COMMITED不允许允许允许不允许允许
REPEATABLE READ不允许不允许允许不允许不允许
SERIALIZABLE不允许不允许不允许不允许不允许

事物传播行为类型

事物传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务;如果已经存在一个事务中,加入到这个事务中。默认值。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,把当前事务挂起。
PROPAGATION_NVERER 以非事务方式执行操作,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED的操作。

事务嵌套机制


@Transactional
Class One{
    public void a(){
        b();
        Two.c();
    }
    
    public void b(){}
}

@Transactional
Class Two{
    public void c(){}
}

#执行过程 execution process

------start-----

#1、创建一个事务
exucate method a()
**create new transaction with name** [One.a]
#2、method a(),b() 在同一个Bean中,并未发生加入已存在事务上下文的动作,而是天然地工作于相同的事务上下文中
excute method b()
#3、method c() 加入到1处启动的事务上下文中
excute method c()
**Participating in existing transaction**

-------end------


乐观锁&悲观锁

  • 悲观锁
    • 定义:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。悲观锁假定其他用户企图访问或者改变你正在访问、更改的对象的概率是很高的,因此在悲观锁的环境中,在你开始改变此对象之前就将该对象锁住,并且直到你提交了所作的更改之后才释放锁。悲观的缺陷是不论是页锁还是行锁,加锁的时间可能会很长,这样可能会长时间的限制其他用户的访问,也就是说悲观锁的并发访问性不好。
    • 应用:需要使用数据库的锁机制,比如SQL SERVER 的TABLOCKX(排它表锁) 此选项被选中时,SQL Server 将在整个表上置排它锁直至该命令或事务结束。这将防止其他进程读取或修改表中的数据。
  • 乐观锁
    • 定义:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。乐观锁不能解决脏读的问题。乐观锁则认为其他用户企图改变你正在更改的对象的概率是很小的,因此乐观锁直到你准备提交所作的更改时才将对象锁住,当你读取以及改变该对象时并不加锁。可见乐观锁加锁的时间要比悲观锁短,乐观锁可以用较大的锁粒度获得较好的并发访问性能。但是如果第二个用户恰好在第一个用户提交更改之前读取了该对象,那么当他完成了自己的更改进行提交时,数据库就会发现该对象已经变化了,这样,第二个用户不得不重新读取该对象并作出更改。这说明在乐观锁环境中,会增加并发用户读取对象的次数。
    • 应用:
      • 使用自增长的整数表示数据版本号。更新时检查版本号是否一致,比如数据库中数据版本为6,更新提交时version=6+1,使用该version值(=7)与数据库version+1(=7)作比较,如果相等,则可以更新,如果不等则有可能其他程序已更新该记录,所以返回错误;
      • 使用时间戳来实现.
      • 对于以上两种方式,Hibernate自带实现方式:在使用乐观锁的字段前加annotation: @Version, Hibernate在更新时自动校验该字段。

参考文档

1.事务隔离级别
2.MySQL数据库引擎介绍、区别、创建和性能测试的深入分析
3.乐观锁与悲观锁的区别