- 浏览: 2990017 次
- 性别:
- 来自: 河南
文章分类
- 全部博客 (340)
- Java综合 (26)
- 程序人生 (53)
- RIA-ExtJS专栏 (18)
- RIA-mxGraph专栏 (4)
- RIA-Flex4专栏 (43)
- 框架-Spring专栏 (16)
- 框架-持久化专栏 (22)
- 框架-Struts2专栏 (11)
- 框架-Struts专栏 (12)
- SQL/NOSQL (12)
- 报表/图表 (2)
- 工作流 (5)
- XML专栏 (4)
- 日常报错解决方案 (5)
- Web前端-综合 (12)
- Web/JSP (14)
- Web前端-ajax专栏 (14)
- Web前端-JQuery专栏 (9)
- IDE技巧 (6)
- FILE/IO (14)
- 远程服务调用 (2)
- SSO单点登录 (2)
- 资源分享 (22)
- 云计算 (1)
- 项目管理 (3)
- php专栏 (1)
- Python专栏 (2)
- Linux (1)
- 缓存系统 (1)
- 队列服务器 (1)
- 网络编程 (0)
- Node.js (1)
最新评论
-
hui1989106a:
我的也不能解压,360和好压都试了,都不行
《Spring in Action》完整中文版分享下载 -
temotemo:
这些example有些过时了,官方建议使用HBase-1.0 ...
Java操作Hbase进行建表、删表以及对数据进行增删改查,条件查询 -
zy8102:
非常感谢~
HeadFirst系列之七:《深入浅出SQL》原版高清PDF电子书分享下载 -
zy8102:
重命名了一下搞定了
HeadFirst系列之七:《深入浅出SQL》原版高清PDF电子书分享下载 -
zy8102:
为什么下载以后老解压不了呢?
HeadFirst系列之七:《深入浅出SQL》原版高清PDF电子书分享下载
在并发环境,一个数据库系统会同时为各种各样的客户程序提供服务,也就是说,在同一时刻,会有多个客户程序同时访问数据库系统,这多个客户程序中的失误访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种各样的并发问题的发生,这些并发问题可归纳为以下几类
多个事务并发引起的问题:
1)第一类丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
2)脏读:一个事务读到另一个事务未提交的更新数据。
3) 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行。
4)不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样。
5)第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一个事务已提交的更新数据。
事务隔离级别
为了解决多个事务并发会引发的问题。数据库系统提供了四种事务隔离级别供用户选择。
1) Serializable:串行化。隔离级别最高
2) Repeatable Read:可重复读。--MySQL默认是这个
3) Read Committed:读已提交数据。--Oracle默认是这个
4) Read Uncommitted:读未提交数据。隔离级别最差。--sql server默认是这个
数据库系统采用不同的锁类型来实现以上四种隔离级别,具体的实现过程对用户是透明的。用户应该关心的是如何选择合适的隔离级别。
对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed,它能够避免脏读,而且具有较好的并发性能。
每个数据库连接都有一个全局变量@@tx_isolation,表示当前的事务隔离级别。JDBC数据库连接使用数据库系统默认的隔离级别。在Hibernate的配置文件中可以显示地设置隔离级别。每一种隔离级别对应着一个正整数。
Read Uncommitted: 1
Read Committed: 2
Repeatable Read: 4
Serializable: 8
在hibernate.cfg.xml中设置隔离级别如下:
<session-factory>
<!-- 设置JDBC的隔离级别 -->
<property name="hibernate.connection.isolation">2</property>
</session-factory>
设置之后,在开始一个事务之前,Hibernate将为从连接池中获得的JDBC连接设置级别。需要注意的是,在受管理环境中,如果Hibernate使用的数据库连接来自于应用服务器提供的数据源,Hibernate不会改变这些连接的事务隔离级别。在这种情况下,应该通过修改应用服务器的数据源配置来修改隔离级别。
并发控制
当数据库系统采用Red Committed隔离级别时,会导致不可重复读和第二类丢失更新的并发问题,在可能出现这种问题的场合。可以在应用程序中采用悲观锁或乐观锁来避免这类问题。
乐观锁(Optimistic Locking):
乐观锁假定当前事务操纵数据资源时,不会有其他事务同时访问该数据资源,因此不作数据库层次上的锁定。为了维护正确的数据,乐观锁使用应用程序上的版本控制(由程序逻辑来实现的)来避免可能出现的并发问题。
唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、 或者时间戳来检测更新冲突(并且防止更新丢失)。
三种方式。
1)Version版本号
2)时间戳
3)自动版本控制。
这里不建议在新的应用程序中定义没有版本或者时间戳列的版本控制:它更慢,更复杂,如果你正在使用脱管对象,它则不会生效。
通过在表中及POJO中增加一个version字段来表示记录的版本,来达到多用户同时更改一条数据的冲突
数据库脚本:
create table studentVersion (id varchar(32),name varchar(32),ver int);
POJO
package Version;
public class Student {
private String id;
private String name;
private int version;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
Student.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse - Hibernate Tools
-->
<hibernate-mapping>
<class name="Version.Student" table="studentVersion" >
<id name="id" unsaved-value="null">
<generator class="uuid.hex"></generator>
</id>
<!--version标签必须跟在id标签后面-->
<version name="version" column="ver" type="int"></version>
<property name="name" type="string" column="name"></property>
</class>
</hibernate-mapping>
Hibernate.cfg.xml
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">
jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312&useUnicode=true
</property>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="myeclipse.connection.profile">mysql</property>
<property name="connection.password">1234</property>
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="current_session_context_class">thread</property>
<property name="jdbc.batch_size">15</property>
<mapping resource="Version/Student.hbm.xml" />
</session-factory>
</hibernate-configuration>
测试代码
package Version;
import java.io.File;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class Test {
public static void main(String[] args) {
String filePath=System.getProperty("user.dir")+File.separator+"src/Version"+File.separator+"hibernate.cfg.xml";
File file=new File(filePath);
System.out.println(filePath);
SessionFactory sessionFactory=new Configuration().configure(file).buildSessionFactory();
Session session=sessionFactory.openSession();
Transaction t=session.beginTransaction();
Student stu=new Student();
stu.setName("tom11");
session.save(stu);
t.commit();
/*
* 模拟多个session操作student数据表
*/
Session session1=sessionFactory.openSession();
Session session2=sessionFactory.openSession();
Student stu1=(Student)session1.createQuery("from Student s where s.name='tom11'").uniqueResult();
Student stu2=(Student)session2.createQuery("from Student s where s.name='tom11'").uniqueResult();
//这时候,两个版本号是相同的
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
Transaction tx1=session1.beginTransaction();
stu1.setName("session1");
tx1.commit();
//这时候,两个版本号是不同的,其中一个的版本号递增了
System.out.println("v1="+stu1.getVersion()+"--v2="+stu2.getVersion());
Transaction tx2=session2.beginTransaction();
stu2.setName("session2");
tx2.commit();
}
}
测试结果
Hibernate: insert into studentVersion (ver, name, id) values (?, ?,
?)
Hibernate: select student0_.id as id0_, student0_.ver as ver0_,
student0_.name as name0_ from studentVersion student0_ where
student0_.name='tom11'
Hibernate: select student0_.id as id0_, student0_.ver
as ver0_, student0_.name as name0_ from studentVersion student0_ where
student0_.name='tom11'
v1=0--v2=0
Hibernate: update studentVersion set
ver=?, name=? where id=? and ver=?
v1=1--v2=0
Hibernate: update
studentVersion set ver=?, name=? where id=? and ver=?
Exception in thread
"main" org.hibernate.StaleObjectStateException: Row
was updated or deleted by another transaction (or unsaved-value mapping was
incorrect): [Version.Student#4028818316cd6b460116cd6b50830001]
可以看到,第二个“用户”session2修改数据时候,记录的版本号已经被session1更新过了,所以抛出了红色的异常,我们可以在实际应用中处理这个异常,例如在处理中重新读取数据库中的数据,同时将目前的数据与数据库中的数据展示出来,让使用者有机会比较一下,或者设计程序自动读取新的数据
注意: 要注意的是,由于乐观锁定是使用系统中的程式来控制,而不是使用资料库中的锁定机制,因而如果有人特意自行更新版本讯息来越过检查,则锁定机制就会无效,例如在上例中自行更改stu的version属性,使之与资料库中的版本号相同的话就不会有错误,像这样版本号被更改,或是由于资料是由外部系统而来,因而版本资讯不受控制时,锁定机制将会有问题,设计时必须注意。 如果手工设置stu.setVersion()自行更新版本以跳过检查,则这种乐观锁就会失效,应对方法可以将Student.java的setVersion设置成private
如果是注解方式的,POJO应为这样
@Entity
@Table(name="student ")
public class Student {
@Id @GeneratedValue
private Integer id;
private String name;
private Integer version;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
}
悲观锁控制(Pressimistic Locking)
悲观锁...他依赖于数据库机制,在整个过程中将数据库锁定,其他任何用户都不能读取或者修改..通俗一点说,先读的用户就一直占用这个资源,直到结束.这里的例子,我们说一个账户信息.一共有三个字段,一个id,一个name,还有一个money,表示的是账户余额.很明显,当一个人在操作这个账户的时候,其他人是不能操作这个账户的,否则就会造成数据的不一致.
悲观锁的一般实现方式是在应用程序中显式采用数据库系统的独占锁来锁定数据库资源。在如下几种方式时可能显示指定锁定模式为LockMode.UPGRADE
1)调用session的get()或load()方法
2)调用session的lock()方法
3)调用Query的setLockMode()方法
实体类
Acount.java
package com.test.model;
public class Acount
{
private int id;
private String name;
private int money;
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public int getMoney()
{
return money;
}
public void setMoney(int money)
{
this.money = money;
}
}
Account.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping package="com.test.model">
<class name="Acount" table="Acount" >
<id name="id">
<generator class="native"></generator>
</id>
<property name="name"></property>
<property name="money"></property>
</class>
</hibernate-mapping>
上面两个都没啥可以说的,算是最简单的hibernate实体类和配置文件了...
我们使用两个测试方法来模拟两个用户.同样,我们使用JUnit4
package com.test.junit;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;
import org.hibernate.LockMode;
import com.test.model.Acount;
import com.test.util.HibernateSessionFactory;
public class extendsTest
{
@Test
public void test1()
{
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
Acount acount = (Acount)session.load(Acount.class, 1,LockMode.UPGRADE);//注意,这里的最后那个参数..他将锁定这个操作.
System.out.println(acount.getName());
System.out.println(acount.getMoney());
acount.setMoney(acount.getMoney() - 20000);
tx.commit();
session.close();
}
@Test
public void test2()
{
Session session = HibernateSessionFactory.getSession();
Transaction tx = session.beginTransaction();
Acount acount = (Acount)session.load(Acount.class, 1,LockMode.UPGRADE);
System.out.println(acount.getName());
System.out.println(acount.getMoney());
acount.setMoney(acount.getMoney() - 20000);
tx.commit();
session.close();
}
}
具体的做法是,我们在test1方法的事务提交前设置一个断点,然后我们用debug模式运行.然后,我们再直接运行test2方法.我们可以看到下面这样
也就是说,后面那个用户就一直在等待,.只要第一个用户没有提交.他就无法继续运行....这就是悲观锁...
悲观锁的缺点显而易见..他是彻底的占用了这个资源....所以,我们一般需要用这个来解决短事务,也就是周期比较短的事务..否则,第一个用户如果一直不操作,后面任何用户都无法进行...
经过测试,还有一个结论就是:使用悲观锁,session的load方法的延迟加载机制失效
总结:尽管悲观锁能够方式丢失更新和不可重复读之类并发问题的发生的,但是它影响并发性能。因此不建议使用悲观锁,尽量使用乐观锁
发表评论
-
ibatis常用16条SQL语句
2011-07-29 11:08 26020(1) 输入参数为单个值 ... -
iBATIS与Hibernate的异同
2010-12-30 14:47 3664Hibernate Hibernate是一个开放源代 ... -
iBATIS与Spring整合
2010-12-30 14:34 4851接着iBATIS的入门实例来说,ibatis与Spring的 ... -
Hibernate温习(17)--OpenSessionInView模式
2010-11-11 17:04 4527在WEB应用程序中,视图(JSP或Servlet)可能会通过导 ... -
Hibernate温习(16)--性能优化之缓存管理
2010-11-11 16:02 17581.缓存概述 缓存(cache) ... -
Hibernate温习(15)--性能优化之抓取策略
2010-11-11 14:51 3489抓取策略(fetching strategy) 是指:当应 ... -
Hibernate温习(14)--性能优化之延迟加载机制
2010-11-11 11:33 1723延迟加载 延迟加载 ... -
Hibernate温习(13)--Hibernate程序性能优化的考虑要点
2010-11-11 10:55 1310本文依照HIBERNATE帮助文档,一些网络书籍及项目经 ... -
Hibernate温习(12)--基于注解方式的各种映射全面总结
2010-11-11 10:43 35691. 使用Hibernate Annotation来做对 ... -
Hibernate温习(10)--应用程序中的事务管理
2010-11-11 09:26 1899事务的定义 事务就是指作为单个逻辑工作单元执行的一组数据操作 ... -
Hibernate温习(9)--有关Hibernate升级后注解方式的对象关系映射
2010-11-10 17:06 3301我要说的升级指的是我实际中遇到的,由于我之前的项目中Hiber ... -
Hibernate进行测试时时常会有的错误
2010-11-10 14:31 1450在hibernate程序中,如果使用JUNIT进行测试的话,第 ... -
Hibernate温习(8)--使用JPA
2010-11-10 11:00 2333这次讲的JPA前一篇文章都有所介绍,这里呢就是结合hibern ... -
Hibernate温习(7)--JPA回顾
2010-11-10 10:39 1944什么是JPA JPA(Java Pers ... -
Hibernate温习(6)--单向一对一外键关联映射
2010-11-05 10:24 2583hibernate一对一唯一外键关联映射(单向关联Citize ... -
Hibernate温习(5)--集合属性映射
2010-11-04 22:37 2419Hibernate的集合属性映射 ... -
Hibernate温习(3)--有关session的总结
2010-11-04 17:22 4209说到Hibernate那么最核心的就是它的有关数据库的增删改查 ... -
Hibernate温习(1)--最基础的示例
2010-11-04 14:22 3420有关Spring的知识大部分都已经温习完毕,今天开始转向Hib ... -
ibatis入门实例讲解
2010-10-25 10:39 12938之前大家上网的ibatis官方网站:http://www.i ... -
HIbernate温习(2)--连接池配置总结基于第三方c3p0和proxool
2010-07-26 14:42 3407一直都在用连接池技术,也是个好习惯,但用连接 ...
相关推荐
hibernate-commons-annotations-4.0.1.Final.jar hibernate-core-4.1.12.Final.jar hibernate-ehcache-4.1.12.Final.jar hibernate-entitymanager-4.1.12.Final.jar hibernate-jpa-2.0-api-1.0.1.Final.jar ...
赠送jar包:hibernate-jpa-2.1-api-1.0.2.Final.jar; 赠送原API文档:hibernate-jpa-2.1-api-1.0.2.Final-javadoc.jar; 赠送源代码:hibernate-jpa-2.1-api-1.0.2.Final-sources.jar; 赠送Maven依赖信息文件:...
赠送jar包:hibernate-jpa-2.1-api-1.0.2.Final.jar; 赠送原API文档:hibernate-jpa-2.1-api-1.0.2.Final-javadoc.jar; 赠送源代码:hibernate-jpa-2.1-api-1.0.2.Final-sources.jar; 赠送Maven依赖信息文件:...
hibernate-jpa-2.1-api-1.0.0.final-sources.jar 源码 hibernate-jpa-2.1-api-1.0.0.final-sources.jar 源码
很多人为了配置jpa找这个动态产生字节码的jar文件,hibernate-distribution-3.3.1.GA包太大,而hibernate-distribution-3.3.2.GA的jar没有这个jar文件,希望对大家有用
hibernate-jpa-2.0-api-1.0.1.Final.jar
hibernate-annotations-3.4.0.GA hibernate-annotations-3.4.0.GA hibernate-annotations-3.4.0.GA
hibernate-jpa-2.1-api-1.0.0.final.jar.zip,内含hibernate-jpa-2.1-api-1.0.0.final.jar
hibernate-commons-annotations-5.0.1.Final.jar的源码
hibernate-release-4.0.0.Final.zip
hibernate-release-5.3.7.Final
使用hibernate-validator 进行校验的jar包,里面包括了基础hibernate-validator-5.0.0.CR2.jar hibernate-validator-annotation-processor-5.0.0.CR2.jar 之外,还包括了el-api-2.2.jar javax.el-2.2.4等项目必不可...
hibernate-release-4.3.10.Final.zip 官方原版,因上传文件大小限制,去掉里面的project
hibernate-release-5.1.0.Final
hibernate-commons-annotations-4.0.1.Final.jar
hibernate-release-5.0.7.Final压缩包 -document -lib -project 内部Hibernate依赖库: antlr-2.7.7.jar dom4j-1.6.1.jar geronimo-jta_1.1_spec-1.1.1.jar hibernate-commons-annotations-5.0.1.Final.jar ...
hibernate-jpa-2.1-api-1.0.0.Final.jar官方下载,请放心使用
hibernate-jpa-2.0-api-1.0.1.Final-sources.jar hibernate jpa 源代码
hibernate-configuration-3.0.dtd、hibernate-mapping-3.0.dtd、hibernate.properties(5.0.7)
Hibernate稳定版(hibernate-release-5.3.23.Final.zip),Hibernate ORM 是一个为应用程序、库和框架提供对象/关系映射 (ORM) 支持的库。它还提供了 JPA 规范的实现,这是 ORM 的标准 Java 规范。