学习笔记-数据库
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在更新时自动校验该字段。