2014年6月23日星期一

Cloud_022:数据库事务特性以及隔离级别说明

之所以整理这篇东东,是为了将来和NoSQL中的事务做一个比较,以及和数据网格中的事务做一个比较。

数据库事务具有ACID四个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。

1. 原子性(Atomicity)
原子性是指事务是一个不可再分割的工作单位,事务中的操作要么都发生,要么都不发生。

2. 一致性(Consistency)
一致性是指在事务开始之前和结束以后,数据库的完整性约束(唯一约束、外键约束、Check约束、触发器设置)没有被破坏。

3. 隔离性(Isolation)
隔离性是指多个事务并发操作数据时,事务之间是隔离的,一个事务不会影响其它事务运行结果。
多个事务同时操作相同的数据时,每个事务都有自己独立的数据空间,各个事务之间是隔离的。
隔离性的实现原理是锁和阻塞。

可以为数据库设置不同的隔离级别,不同的级别对隔离性的保障不同,对性能的影响也不同。

多个事务并发操作数据时,可能会产生如下问题:
(1)脏读(Dirty Reads)
脏读指的是一个事务读取了另一个事务未提交的数据。
比如事务A修改了数据但未提交,此时事务B读取了事务A修改后的数据,然后事务A回滚了。
(2)不可复读(Non-Repeatable Reads)
不可复读指的是在一个事务范围内前后两次相同的查询却返回了不同数据。
这是由于在前后两次相同的查询期间,另一个事务修改了数据,并且提交了。
(3)幻读(Phantom Reads)
幻读指的是当事务不是独立执行时发生的一种现象。
事务A对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。
事务B向同一个表中插入一行新数据。
事务A发现表中还有未修改的数据行,好象发生了幻觉一样。
(4)丢失更新
丢失更新指的是两个事务同时读取同一条记录,A先修改记录,B也修改记录(B不知道A修改过),B提交数据后,B的修改结果覆盖了A的修改结果。

以上问题可以通过设置隔离级别来得到不同程度的解决:
(1)未提交读(Read Uncommited):在读数据时不会检查或使用任何锁。因此,在这种隔离级别中可能读取到没有提交的数据。
SELECT语句以非锁定方式被执行,所以有可能读到脏数据,隔离级别最低。
(2)已提交读(Read commited):只读取提交的数据并等待其他事务释放排他锁,读数据的共享锁在读操作完成后立即释放。解决了脏读问题,但未解决不可复读。已提交读是大多数数据库的默认隔离级别。
(3)可重复读(Repeatable Read):和已提交读类似,但是读数据时会保持共享锁直到事务结束。解决了不可复读问题,但未解决幻读问题。
(4)可串行读(Serializable):和可重复读的类似,但它不仅会锁定受影响的数据,还会锁定这个范围。这就阻止了新数据插入查询所涉及的范围。
所有SELECT语句都被隐式的转换成SELECT ... LOCK IN SHARE MODE,即读取使用表级共享锁,读写相互都会阻塞。隔离级别最高。

总结各个隔离级别如下:
隔离级别 
脏读  
丢失更新
不可重复读
 幻读 
 并发模型
更新冲突检测
未提交读:Read Uncommited
悲观
已提交读:Read commited
悲观
可重复读:Repeatable Read
悲观
可串行读:Serializable
悲观

4. 持久性(Durability)
持久性是指在事务完成以后,该事务所对数据库所做的更改持久化的保存在数据库之中。
持久性的实现原理是通过提前把操作日志记录下里,这样即使突然断电,数据库重启之后,检查日志,把未持久化的数据写到数据库中。

参考文献:
1. http://blog.csdn.net/shuaihj/article/details/14163713
2. http://h2appy.blog.51cto.com/609721/771768/
3. http://www.cnblogs.com/malaikuangren/archive/2012/04/06/2434760.html
4. http://blog.csdn.net/sunxing007/article/details/6427290

2014年6月13日星期五

Linux_070:RHEL 7 下 VirtualBox Guest Additions安装失败问题

环境:RHEL 7 + VirtualBox 4.3.12

RHEL 7 昨天刚刚发布,于是装上尝个鲜。
首先在VirtualBox 中安装好RHEL 7,接着安装VirtualBox Guest Additions。

1.  安装编译工具:yum groupinstall "开发工具"

2.  安装kernel-devel:yum install kernel-devel
之所以安装这个,是因为不安装会报出kernel编译错误。
安装后,运行:rpm -qa | grep kernel,看到如下软件包就对了:

kernel-tools-3.10.0-123.1.2.el7.x86_64
kernel-debug-devel-3.10.0-123.1.2.el7.x86_64
kernel-3.10.0-123.el7.x86_64
kernel-headers-3.10.0-123.1.2.el7.x86_64
kernel-devel-3.10.0-123.1.2.el7.x86_64
kernel-tools-libs-3.10.0-123.1.2.el7.x86_64
kernel-3.10.0-123.1.2.el7.x86_64
abrt-addon-kerneloops-2.1.11-12.el7.x86_64

3. 进入VBoxGuestAdditioins.iso目录,运行:./VBoxLinuxAdditions.run
此时,还是不能编译成功,会报出以下错误:
/tmp/vbox.0/r0drv/linux/memobj-r0drv-linux.c: In function ‘rtR0MemObjNativeMapUser’:
/tmp/vbox.0/r0drv/linux/memobj-r0drv-linux.c:1542:26: error: ‘struct mm_struct’ has no member named ‘numa_next_reset’
                 pTask->mm->numa_next_reset = jiffies + 0x7fffffffffffffffUL;
                          ^
make[2]: *** [/tmp/vbox.0/r0drv/linux/memobj-r0drv-linux.o] Error 1
make[1]: *** [_module_/tmp/vbox.0] Error 2
make: *** [vboxguest] Error 2

几经查找,终于确认这是一个BUG。
一位高人写了个Patch,见参考文献2,下载后,解压,执行 sudo ./install.sh,这次终于安装成功了。

参考文献:
1. https://forums.virtualbox.org/viewtopic.php?f=3&t=59094
2. http://matthewcasperson.blogspot.in/2014/06/rhel-7-virtualbox-guest-additions.html

2014年6月5日星期四

Java_017:jar 命令基本操作


jar命令可以处理.jar、.war、.ear类型的压缩文件。

1. 创建压缩文件:jar -cvf 目标压缩文件 压缩目录/文件(多个目录/文件之间以空格间隔)
(1)jar -cvf ehcache.war META-INF/ WEB-INF/

2. 查看压缩文件:jar -tvf 压缩文件
(1)jar -tvf ehcache.war 

3. 解压压缩文件:jar -xvf 压缩文件
(1)jar -xvf ehcache.war 

参考文献:
1. http://www.jb51.net/article/35881.htm

MAC_016:让MAC的终端多姿多彩

环境:MAC OS X 10.9.3

1. 在用户主目录下创建.bash_profile:touch .bash_profile

2. 使用文本编辑器打开.bash_profile文件:open -e .bash_profile
增加以下内容:
# color
export CLICOLOR="xterm-color"
export LSCOLORS="gxfxcxdxbxegedabagacad"

# aliases
alias cd..="cd .."
alias l="ls"
alias ll="ls -l"
alias la="ls -al"

3. 保存.bash_profile文件,新开一个终端

参考文献:
1. http://memory.blog.51cto.com/6054201/1199721
2. http://sexywp.com/custom-mac-os-x-terminal.htm

2014年6月4日星期三

Linux_068:RHEL下安装Oracle Database XE 11gR2

环境:RHEL 6.5 + Oracle Database XE 11gR2

下载地址:
http://www.oracle.com/technetwork/database/database-technologies/express-edition/downloads/index.html。
选择linux版本:oracle-xe-11.2.0-1.0.x86_64.rpm.zip。

安装步骤如下:

1. 解压:unzip oracle-xe-11.2.0-1.0.x86_64.rpm.zip 
Archive:  oracle-xe-11.2.0-1.0.x86_64.rpm.zip
   creating: Disk1/
   creating: Disk1/upgrade/
  inflating: Disk1/upgrade/gen_inst.sql
   creating: Disk1/response/
  inflating: Disk1/response/xe.rsp
  inflating: Disk1/oracle-xe-11.2.0-1.0.x86_64.rpm

2. 安装:
(1)cd Disk1
(2)rpm -ivh oracle-xe-11.2.0-1.0.x86_64.rpm 
Preparing...                ########################################### [100%]
   1:oracle-xe              ########################################### [100%]
Executing post-install steps...
You must run '/etc/init.d/oracle-xe configure' as the root user to configure the database.
(3)/etc/init.d/oracle-xe configure
Oracle Database 11g Express Edition Configuration
-------------------------------------------------
This will configure on-boot properties of Oracle Database 11g Express
Edition.  The following questions will determine whether the database should
be starting upon system boot, the ports it will use, and the passwords that
will be used for database accounts.  Press to accept the defaults. 
Ctrl-C will abort.

Specify the HTTP port that will be used for Oracle Application Express [8080]:8686

Specify a port that will be used for the database listener [1521]:

Specify a password to be used for database accounts.  Note that the same
password will be used for SYS and SYSTEM.  Oracle recommends the use of
different passwords for each database account.  This can be done after
initial configuration:
Confirm the password:

Do you want Oracle Database 11g Express Edition to be started on boot (y/n) [y]:y

Starting Oracle Net Listener...Done
Configuring database...Done
Starting Oracle Database 11g Express Edition instance...Done
Installation completed successfully.

3. 配置
安装成功后,会创建一个名为oracle的用户,主目录在:/u01/app/oracle/。
为了使用方便,我从其他用户目录下把 .bashrc 和 .bash_profile 文件拷贝到oracle用户主目录下。

# chown oracle:dba .bash_profile
# chown oracle:dba .bashrc
# chmod 755 .bashrc
# chmod 755 .bash_profile

修改.bashrc(新打开一个shell)或 .bash_profile(每次登录)文件,增加一行内容如下:
. /u01/app/oracle/product/11.2.0/xe/bin/oracle_env.sh

允许远程用户访问:
$ sqlplus system
SQL> EXEC DBMS_XDB.SETLISTENERLOCALACCESS(FALSE);

4. 解锁HR用户,并增加数据库连接数
(1)以DBA身份连接数据库
connect sys/welcome1 as sysdba;
(2)然后给HR Schema解锁,做有关HR Schema的实验需要设置此项。
alter user hr identified by hr account unlock;
(3)修改允许的数据库连接数
alter system set processes=500 scope=spfile;

5. 启动与停止
(1)/etc/init.d/oracle-xe start
(2)/etc/init.d/oracle-xe stop
更多命令参数可以敲入:service oracle-xe,回车会显示如下信息:
Usage: /etc/init.d/oracle-xe {start|stop|restart|force-reload|configure|status|enable|disable}

6. 卸载
# rpm -e oracle-xe

7. 远程无法访问的问题
开始以为是防火墙和SELinux的问题,再确认防火墙和SELinux都关闭的情况下,依然无法远程访问,只能在本机访问。
经过进一步检查,这是因为使用DHCP动态获取了IP地址和主机名导致的问题。
使用hostname可以检查机器的主机名,或者从Shell Prompt中也可以看出来。

解决方法如下:
(1)修改文件:/u01/app/oracle/product/11.2.0/xe/network/admin/listener.ora
把 HOST = localhost.localdomain改成IP地址即可。

# listener.ora Network Configuration File:

SID_LIST_LISTENER =
  (SID_LIST =
    (SID_DESC =
      (SID_NAME = PLSExtProc)
      (ORACLE_HOME = /u01/app/oracle/product/11.2.0/xe)
      (PROGRAM = extproc)
    )
  )

LISTENER =
  (DESCRIPTION_LIST =
    (DESCRIPTION =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC_FOR_XE))
      (ADDRESS = (PROTOCOL = TCP)(HOST = localhost.localdomain)(PORT = 1521))
    )
  )

(2)修改文件:/u01/app/oracle/product/11.2.0/xe/network/admin/tnsnames.ora

把 HOST = localhost.localdomain改成IP地址即可。

# tnsnames.ora Network Configuration File:

XE =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost.localdomain)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = XE)
    )
  )

EXTPROC_CONNECTION_DATA =
  (DESCRIPTION =
    (ADDRESS_LIST =
      (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC_FOR_XE))
    )
    (CONNECT_DATA =
      (SID = PLSExtProc)
      (PRESENTATION = RO)
    )
  )

参考文献:
1. http://www.linuxidc.com/Linux/2012-08/66974.htm

2014年6月1日星期日

Linux_067:RHEL下的重启与关机 (摘录+整理)

环境:RHEL 6.5

在Linux下常用的重启与关机命令有 shutdown、halt、reboot和init。

1.shutdown [选项] [时间] [警告信息]
shutdown命令可以安全地重启或关闭系统,使用直接断电的方式来关闭计算机的方式是十分危险的。
使用shutdown命令,系统管理员会通知所有登录的用户系统将要关闭,并且login命令会被冻结,新的用户不能再登录。直接关机或者延迟一定的时间才关机都是可能的,还可能重启。
选项说明:
(1)-k:并不真正关机,只是发出警告信息给所有用户。
(2)-r: 关机后立即重新启动。
(3)-h:关机后不重新启动。
(4)-f: 快速关机,重启动时跳过fsck。
(5)-n:快速关机,不经过init程序。
(6)-c:取消一个已经运行的shutdown。
(7)[-time]:设定关机前的时间。

使用例子:
(1)#shutdown –h now 立即关闭系统
(2)#shutdown –h 45 定时45分钟后关闭系统
(3)#shutdown –r now “system will be reboot now!”重新启动系统,并发出警告信息

2.halt [选项]
其实halt命令就是调用“shutdown -h”命令执行的。
选项说明:
(1)-c: 防止sync系统调用,它用在fsck修补根分区之后,以阻止内核用老版本的超级块覆盖修补过的超级块。
(2)-w: 并不是真正的重启或关机,只是写wtmp(/var/log/wtmp)记录。
(3)-d: 不写wtmp记录(已包含在选项[-n]中)。
(4)-f: 没有调用shutdown而强制关机或重启。
(5)-I: 关机(或重启)前,关掉所有的网络接口。
(6)-p: 该选项为缺省选项,即关机时调用poeroff。

使用例子:
(1)#halt 立即关闭系统

3.reboot
reboot的工作过程与halt相似,不过halt是引发主机关机,而reboot是引发主机重启。
reboot的选项与halt选项类似。

使用例子:
(1)#reboot 立即重启系统

4.init
因为init进程是所有进程的祖先(进程号始终为1),因此发送TREM信号给init进程会终止所有的用户进程和守护进程等。
shutdown就是使用这种机制。
init定义了7个运行级别,其中init 0为关机,init 6为重启。

参考文献:
1. http://www.360doc.com/content/10/0612/16/1692086_32718402.shtml
2. http://zhoujingxian.iteye.com/blog/1198380

Linux_066:故障分析 High I/O Wait (摘录+整理)

定位I/O Wait问题需要组合一些命令。

1. 首先判定系统变慢是不是I/O引起的?
使用命令:top,查看CPU一行中的%wa数据,该数据是CPU用于I/O Wait的百分比,比如:
Cpu(s): 2.3%us, 1.7%sy, 0.0%ni, 0.0%id, 96.0%wa, 0.0%hi, 0.0%si, 0.0%st

2. 如果确实是I/O Wait引起的问题,查找是哪个磁盘在做频繁的写入操作?
使用命令:iostat -x 2 5,查看磁盘的%util数据,比如:
Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
 sda 44.50 39.27 117.28 29.32 11220.94 13126.70 332.17 65.77 462.79 9.80 2274.71 7.60 111.41

3. 查找哪个进程引起的High I/O?
使用 ps 命令查看进程的状态码,进程状态码说明如下:
(1)D uninterruptible sleep (usually IO)
(2)R running or runnable (on run queue)
(3)S interruptible sleep (waiting for an event to complete)
(4)T stopped, either by a job control signal or because it is being traced.
(5)W paging (not valid since the 2.6.xx kernel)
(6)X dead (should never be seen)
(7)Z defunct ("zombie") process, terminated but not reaped by its parent.

使用如下脚本,打印状态为D的进程,每隔5秒打印一次,打印10次:
for x in `seq 1 1 10`; do ps -eo state,pid,cmd | grep "^D"; echo "----"; sleep 5; done
比如输出如下:
D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp
----
D 16528 bonnie++ -n 0 -u 0 -r 239 -s 478 -f -b -d /tmp
----
可以看出,进程16528是引起High I/O的罪魁祸首,找到进程ID,后面的事就好办了。

4. 根据找到的进程ID,查看该进程的I/O统计数据
使用命令:cat /proc/16528/io,比如输出如下:
 rchar: 48752567
 wchar: 549961789
 syscr: 5967
 syscw: 67138
 read_bytes: 49020928
 write_bytes: 549961728
 cancelled_write_bytes: 0

5. 根据找到的进程ID,查看该进程都在读写哪些文件?
使用命令:lsof -p 16528,比如输出如下:
 bonnie++ 16528 root 8u REG 252,0 501219328 131869 /tmp/Bonnie.16528
 bonnie++ 16528 root 9u REG 252,0 501219328 131869 /tmp/Bonnie.16528
 bonnie++ 16528 root 10u REG 252,0 501219328 131869 /tmp/Bonnie.16528
 bonnie++ 16528 root 11u REG 252,0 501219328 131869 /tmp/Bonnie.16528

6. 使用命令:df /tmp,查看该文件的文件系统
 Filesystem 1K-blocks Used Available Use% Mounted on
 /dev/mapper/workstation-root 7667140 2628608 4653920 37% /
可以看出,/tmp所在的文件系统是workstation-root。

7. 使用命令:pvdisplay,查看物理卷在哪个磁盘上?
  --- Physical volume ---
  PV Name /dev/sda5
  VG Name workstation
  PV Size 7.76 GiB / not usable 2.00 MiB
  Allocatable yes
  PE Size 4.00 MiB
  Total PE 1986
  Free PE 8
  Allocated PE 1978
  PV UUID CLbABb-GcLB-l5z3-TCj3-IOK3-SQ2p-RDPW5S
可以看出,文件系统的名称是workstation,说明/tmp所在的文件系统:workstation-root,是其的一部分。
因此,可以断定,High I/O的问题是由进程16528频繁在/tmp目录进行写操作导致的,
而且/tmp就位于磁盘sda。

参考文献:
1. http://www.360doc.com/content/14/0109/14/13876790_343856081.shtml
2. http://bencane.com/2012/08/06/troubleshooting-high-io-wait-in-linux/
3. http://www.360doc.com/content/14/0109/14/13876790_343856953.shtml