Hibernate第七课--事务,悲观锁,乐观锁

来源:互联网 发布:电视机网络电视怎么调 编辑:程序博客网 时间:2024/06/11 01:55
一 事务
二 悲观锁
三 乐观锁


一 事务
(一)、 数据库的隔离级别:并发性作用。
1、   ReadUncommited(未提交读):没有提交就可以读取到数据(发出了Insert,但没有commit就可以读取到。)很少用
2、   ReadCommited(提交读):只有提交后才可以读,常用
3、   RepeatableRead(可重复读):mysql默认级别, 必需提交才能见到,读取数据时数据被锁住。
4、   Serialiazble(序列化读):最高隔离级别,串型的,你操作完了,我才可以操作,并发性特别不好


隔离级别

是否存在脏读

是否存在不可重复读

是否存在幻读

Read Uncommitted(未提交读)

Y

Y

Y

Read Commited(提交读)

N

Y(可采用悲观锁解决)

Y

Repeatable Read(可重复读)

N

N

Y

Serialiazble(序列化读)

 

 

 








 
脏读:没有提交就可以读取到数据称为脏读

不可重复读:再重复读一次,数据与你上的不一样。称不可重复读。

幻读:在查询某一条件的数据,开始查询的后,别人又加入或删除些数据,再读取时与原来的数据不一样了。


1、   Mysql查看数据库隔离级别:

方法:select @@tx_isolation;



2、   Mysql数据库修改隔离级别:

方法:set transactionisolation level 隔离级别名称;


例如:修改为未提交读:settransaction isolation level read uncommitted;



(二)、 事务概念(ACID)

ACID即:事务的原子性、一致性、独立性及持久性 

事务的原子性:是指一个事务要么全部执行,要么不执行.也就是说一个事务不可能只执行了一半就停止了.比如你从取款机取钱,这个事务可以分成两个步骤:1划卡,2出钱.不可能划了卡,而钱却没出来.这两步必须同时完成.要么就不完成.

事务的一致性:是指事务的运行并不改变数据库中数据的一致性.例如,完整性约束了a+b=10,一个事务改变了a,那么b也应该随之改变.

事务的独立性:是指两个以上的事务不会出现交错执行的状态.因为这样可能会导致数据不一致. 

事务的持久性:是指事务运行成功以后,就系统的更新是永久的.不会无缘无故的回滚.


(三)、 事务并发时可能出现问题

1、第一类丢失更新(Lost Update)


二  悲观锁 乐观锁

Hibernate谈到悲观锁、乐观锁,就要谈到数据库的并发问题,数据库的隔离级别越高它的并发性就越差

         并发性:当前系统进行了序列化后,当前读取数据后,别人查询不了,看不了。称为并发性不好

    数据库隔离级别:见前面章级

(一)、 悲观锁

悲观锁:具有排他性(我锁住当前数据后,别人看到不此数据)

悲观锁一般由数据机制来做到的。

1、   悲观锁的实现

通常依赖于数据库机制,在整修过程中将数据锁定,其它任何用户都不能读取或修改(如:必需我修改完之后,别人才可以修改)

2、   悲观锁的适用场景:

悲观锁一般适合短事务比较多(如某一数据取出后加1,立即释放)

长事务占有时间(如果占有1个小时,那么这个1小时别人就不可以使用这些数据),不常用。


实例:

package com.liuhao.hibernate4.demo.pessimistilock;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
 
import org.apache.commons.lang3.builder.ToStringBuilder;
 
@Entity
public class Inventory {
 
private int itemNo;
private String itemName;
private int quantity;
 
public Inventory() {
}
 
public Inventory(int itemNo, String itemName, int quantity) {
super();
this.itemNo = itemNo;
this.itemName = itemName;
this.quantity = quantity;
};
 
@Id
@GeneratedValue
public int getItemNo() {
return itemNo;
}
 
public void setItemNo(int itemNo) {
this.itemNo = itemNo;
}
 
public String getItemName() {
return itemName;
}
 
public void setItemName(String itemName) {
this.itemName = itemName;
}
 
public int getQuantity() {
return quantity;
}
 
public void setQuantity(int quantity) {
this.quantity = quantity;
}
 
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("itemNo", itemNo);
builder.append("itemName", itemName);
builder.append("quantity", quantity);
return builder.toString();
}
 
}


3、   悲观锁的使用
如果需要使用悲观锁,肯定在加载数据时就要锁住,通常采用数据库的for update语句。
Hibernate使用Load进行悲观锁加载。
Session.load(Classarg0, Serializable arg1, LockMode arg2) throws HibernateException
LockMode:悲观锁模式(一般使用LockMode.UPGRADE)
 
@Test
public void testPessimisticLock ()
{
SessionFactory sfactory = HibernateUtil.getSessionFactory();
Session session = sfactory.openSession();
session.beginTransaction();
Inventory i = (Inventory) session.load(Inventory.class,1,LockOptions.UPGRADE);
i.setQuantity(i.getQuantity()-200);
session.update(i);
session.getTransaction().commit();
session.close();
sfactory.close();
}



(二),乐观锁
原理:不是锁,是一种冲突检测机制。
乐观锁的并发性较好,因为我改的时候,别人随边修改。
乐观锁的实现方式:常用的是版本的方式(每个数据表中有一个版本字段version,
某一个用户更新数据后,版本号+1,另一个用户修改后再+1,
当用户更新发现数据库当前版本号与读取数据时版本号不一致(等于小于数据库当前版本号),则更新不了。


使用:
@Version
添加的版本字段version,hibernate维护。
package com.liuhao.hibernate4.demo.optimisticLock;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Version;
 
import org.apache.commons.lang3.builder.ToStringBuilder;
 
@Entity
public class Inventory {
 
private int itemNo;
private int version;
private String itemName;
private int quantity;
 
public Inventory() {
}
 
public Inventory(int itemNo, int version, String itemName, int quantity) {
super();
this.itemNo = itemNo;
this.version = version;
this.itemName = itemName;
this.quantity = quantity;
};
 
@Id
@GeneratedValue
public int getItemNo() {
return itemNo;
}
 
public void setItemNo(int itemNo) {
this.itemNo = itemNo;
}
 
@Version
public int getVersion() {
return version;
}
 
public void setVersion(int version) {
this.version = version;
}
 
public String getItemName() {
return itemName;
}
 
public void setItemName(String itemName) {
this.itemName = itemName;
}
 
public int getQuantity() {
return quantity;
}
 
public void setQuantity(int quantity) {
this.quantity = quantity;
}
 
@Override
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("itemNo", itemNo);
builder.append("itemName", itemName);
builder.append("quantity", quantity);
builder.append("version", version);
return builder.toString();
}
 
}



@Test
public void testOptimisticLock ()
{
SessionFactory sfactory = HibernateUtil.getSessionFactory();
Session session = sfactory.openSession();
session.beginTransaction();
Inventory i = (Inventory) session.load(Inventory.class,1);
i.setQuantity(i.getQuantity()-200);
session.update(i);
session.getTransaction().commit();
session.close();
sfactory.close();
}