在高并发的计算机群组成的负载均衡环境中,经常会碰到多个节点更新同一条数据,从而引起数据不一致的问题!
场景
有 A ,B 2台WEB服务器,负载均衡处理请求, C为数据库服务器, 有订单Order, 订单初始的金额为 300
如果 A B同时调整订单金额 减少100元,将会存在如下情况。
A -> Order.amount(200) -100 = 200
B -> Order.amount(200)- 100 = 200;
但是原本是 A ,B 分别减少100 ,正确的Order.amount的最终值应该是 100, 而现在变成了 200,这个错误的值
如果你的系统采用原生的SQL 那么在做Update操作的时候,是不会存在这个问题
- update order set amount=amount -100 where id=xxxx
update order set amount=amount -100 where id=xxxx
由数据库进行并发同步。
可是我们在开发JAVA系统时,大多数都会采用Hibernate这种ORM框架,所以在做更新操作的时候,是不太可能直接写SQL, 往往都会先读取实体的值,再进行Update操作,那么就会出现上面所说的问题。
在解决这类问题时,我们想到的就是采用数据库的乐观锁原理。 给数据库表添加一个version的版本号字段,每次更新的时候都会带上这个version作为where 条件,如果更新的记录返回为0条,表示数据已经被其它人所修改
在Hibernate3的时候,已经有一个@Version的标签,只要给实体标记就可以了,每次Update操作的时候,都会自动带上这个 version条件
- @Entity
- public class VersionTest {
- private Long id;
- private Integer version;
- private BigDecimal amount;
- @Id
- @Column(name = "oid")
- @GeneratedValue
- public Long getId() {
- return this.id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- @Version
- @OptimisticLock(excluded=true)
- public Integer getVersion() {
- return version;
- }
- public void setVersion(Integer version) {
- this.version = version;
- }
- public BigDecimal getAmount() {
- return amount;
- }
- public void setAmount(BigDecimal amount) {
- this.amount = amount;
- }
- }