我们要怎样才能解决并发问题呢?一种方式是使用乐观锁设计模式.乐观锁并不是把所有的传统的感觉锁在里面.它在bookPassage( ) 方法下工作,我们假设没有其它的用户在相同时间里预定相同的Cabin.那么,在时务提交时,我们让数据库决定是否Cabin被预定.如果被预定,我们抛出一个异常并回滚事务.换句话来说,我们是乐观的,那么没有其它的用户来预定相同的Cabin.这如何运作? 这如何避免表级锁? 好吧,为了使用乐观锁,我们必需把泰坦预定系统稍做修改和使用Java持久化的特殊功能.
我们需要做的第一件事是创建一个新的实体类保存关于一个指定巡航上指定小屋的信息.让我们调用这个新的实体类CruiseCabin。一个CruiseCabin实体类将会被创建为每次巡航的每个小屋:
package com.titan.domain;
import javax.persistence.*;
@Entity
public class CruiseCabin {
private int id;
private Cabin cabin;
private Cruise cruise;
private boolean isReserved;
private long version;
@Id @GeneratedValue
public int getId( ) {
return id;
}
public void setId(int id) {
this.id = id;
}
@OneToOne
public Cabin getCabin( ) {
return cabin;
}
public void setCabin(Cabin cabin) {
this.cabin = cabin;
}
@OneToOne
public Cruise getCruise( ) {
return cruise;
}
public void setCruise(Cruise cruise) {
this.cruise = cruise;
}
public boolean getIsReserved( ) {
return isReserved;
}
public void setIsReserved(boolean is) {
isReserved = is;
}
@Version
protected long getVersion( ) {
return version;
}
protected void setVersion(long version) {
this.version = version;
}
}
CruiseCabin实体类参考小屋和它属于的巡航.isReserved 属性让我们知道是否有人预定小屋为巡航.一个新的有趣的属性是version,它使用注释@javax.persistence.Version.一个@Version属性是一个栏位在CruiseCabin表,它将保存一个指定的CruiseCabin 记录的版本ID.只要CruiseCabin 实体被更新,版本栏会增长.当事务开始提交处理和业务逻辑更新CruiseCabin,实体管理器首先检查是否内存在CruiseCabin实例匹配的version属性,数据库中现在存储的版本栏.如果版本匹配,那么version属性增长.如果他们不匹配,那么实体管理抛出一个异常,并且整个事务回滚.让我们改变bookPassage()使用新功能:
public TicketDO bookPassage(CreditCardDO card, double price)
throws IncompleteConversationalState {
if (customer == null || cruise == null || cabin == null) {
throw new IncompleteConversationalState( );
}
try {
Query getCruiseCabin = entityManager.createQuery(
"SELECT cc FROM CruiseCabin cc WHERE" +
"cc.cabin = :cabin AND cc.cruise = :cruise");
getCruiseCabin.setParameter("cabin", cabin);
getCruiseCabin.setParameter("cruise", cruise);
CruiseCabin cc = (CruiseCabin)getCruiseCabin.getSingleResult( );
if (cc.getIsReserved( ))
throw new EJBException("Cabin is already reserved for cruise");
cc.setIsReserved(true);
Reservation reservation = new Reservation(
customer, cruise, cabin, price);
entityManager.persist(reservation);
this.process.byCredit(customer, card, price);
TicketDO ticket = new TicketDO(customer,cruise,cabin,price);
return ticket;
} catch(Exception e) {
throw new EJBException(e);
}
}
bookPassage( )方法为相关的CruiseCabin实体类操纵查询.如果它被预定,它终止事务。如果不是,那么设置isReserved属性和继续同其它的方法.在事务提交时,实体管理调用一个SQL查询验让和增长实体的version栏.我们假定查询CruiseCabin有一个ID为1并且当前version是101:
update CRUISE_CABIN set isReserved=true, version=version + 1
where id = 1 AND version = 101;
如果这个更新返回零个修改记录,那么实体管理知道CruiseCabin被更新通过其它的事务,并且一个并发的事务会发生.在这种错误情形下,它抛出javax.persistence.OptimisticLock-Exception 异常和回滚事务.另外,事务成功完成,并且查询CruiseCabin被更新为预定和它的version属性增长.这种乐观锁解创建一个快速的写锁在一我们的数据库中的一行代替串行级别的大范围的表锁.
应该注意的是,乐观锁的设计模式并不是一直工作的.如果你数据库中有一行有更高的数据写争夺,那么使用乐观锁模式会降低效率,因为,它将会创建很多回滚,会增加更多的系统开支.在那种情况下,串行化解决可能会更好.重新设计你的数据模式可能会更适合在这种情形,然而,如果在你的数据库中有更高的并发访问同一个指定行,那么,你的系统可能不依比例决定.
分享到:
相关推荐
同时,JPA支持乐观锁和悲观锁,以处理多线程环境下的数据一致性问题。 除此之外,这本书可能还涉及了JPA的扩展特性,如第二级缓存、实体监听器、回调方法(如`@PrePersist`、`@PostLoad`等)以及JPA与其他Java EE...
5. **版本控制**:CMP还支持数据版本控制,用于乐观锁机制,防止并发更新冲突。 尽管CMP在EJB 3.0之后逐渐被注解驱动的JPA(Java Persistence API)取代,因为JPA提供了更多的灵活性和更好的开发者体验。然而,理解...
4. 并发控制:处理多用户同时操作同一数据的问题,如选课时防止冲突,可能采用了乐观锁或悲观锁机制。 5. 事务管理:EJB支持事务处理,确保选课、退选等操作的原子性和一致性。 通过EJB的组件化和JBuilder2006的...
`@Version`注解用于实现乐观锁,如: ```java @Entity public class Flight implements Serializable { @Id private Long id; // ... @Version private int version; // ... } ``` 在这个例子中,`version`...
在EJB 3中,这些注解主要定义在`javax.persistence.*`包中,与JDK 5.0兼容,因此大多数现代IDE如Eclipse、IntelliJ IDEA和Netbeans都支持注解的自动补全功能。 **实体Bean声明**: 使用`@Entity`注解标记一个类为...
5. **并发控制**:容器通过乐观锁、悲观锁等机制管理多个线程对同一实体bean的并发访问。 **三、容器管理实体EJB的使用** 1. **接口定义**:实体bean通常需要定义两个接口,一个是远程接口(Remote Interface),...
- **并发控制**:通过锁和乐观锁定等机制来处理并发访问问题。 #### 四、Java Persistence API (JPA) 1. **领域模型的实现**:JPA允许开发者将Java对象映射到数据库表上,简化了数据持久化的操作。 2. **对象关系...
EJB支持悲观锁和乐观锁策略,确保在多线程环境下对数据的正确访问。例如,Entity Bean可以使用锁机制来防止多个线程同时修改同一数据。 8. **EJB与JMS的结合**: MDB与JMS的结合使应用程序能够处理异步通信,提高...
1. **乐观锁 (Optimistic Locking):** - 基于版本号来检测冲突。 2. **悲观锁 (Pessimistic Locking):** - 在事务开始时锁定资源直到事务结束。 - 适用于高度竞争的资源。 3. **线程安全性 (Thread Safety):** ...
8. **持久性上下文**:讲解实体管理器的持久性上下文,包括它的生命周期、缓存机制和乐观锁/悲观锁策略。 9. **性能优化**:讨论如何通过批处理、懒加载和查询优化来提高EJB 3.0应用的性能。 10. **实战案例**:...
- **Version**: 用于乐观锁的版本字段。 - **Lob**: 映射大对象类型如BLOB/CLOB。 - **JoinTable**: 用于多对多映射的中间表。 - **TableGenerator**: 用于生成主键值的表。 - **SequenceGenerator**: 使用序列生成...
乐观锁是一种防止并发修改问题的机制,通常通过版本号或时间戳来实现。 **示例代码**: ```java @Entity public class Employee { @Id private Long id; private String firstName; private String lastName;...
此外,JPA还提供了乐观锁和悲观锁机制,用于处理并发更新冲突。 总的来说,《Apress.Pro.EJB.3.Java.Persistence.API》是一本全面覆盖JPA的指南,无论是对初学者还是有经验的开发者,都能从中获得关于如何高效、...
这可以通过乐观锁、悲观锁或其他并发控制策略来实现。 6. **事务管理**:由于文档操作通常涉及复杂的业务流程,EJB必须支持事务处理,确保操作的一致性和原子性。 7. **性能优化**:考虑到大型企业可能需要处理...
描述中的“消息EJB的并发控制”可能指的是EJB容器提供的并发策略,如悲观锁或乐观锁,用于防止多个线程同时修改同一数据,确保数据的一致性和完整性。 4. **文件www.pudn.com.txt**:这个文件可能是项目的一些说明...
例如,@GeneratedValue可以帮助我们自动生成主键值,@Temporal用于处理日期和时间类型,@Version则实现了乐观锁机制,确保并发访问时的数据一致性。 这三个库文件共同构成了Hibernate ORM的核心组件,使得开发者...
4. 版本控制:@Version注解用于声明乐观锁机制,通常配合版本号字段使用,以确保并发操作时数据的一致性。 5. 非持久化属性:@Transient注解用于标识那些在数据库中无需持久化的属性。 Hibernate注解的优势在于其...
1. **乐观锁**:乐观锁通常基于版本号或时间戳机制。当多个事务尝试修改同一数据时,只有在提交时检查当前版本号是否与预期一致。如果一致,则事务成功;如果不一致,说明有其他事务进行了修改,当前事务将被回滚。...