当前位置: 首页 > 知识库问答 >
问题:

JPA实体在Ubuntu上得到更新,但在Windows上抛出乐观锁定异常

徐栋
2023-03-14

考虑这个例子,在这个例子中,我创建了两个JPA实体,并使用Spring Data JPA存储库来执行简单的CRUD-

import java.sql.Timestamp;
import javax.persistence.Version;

@MappedSuperclass
public class AbstractValueObject {
    @Id
    @GeneratedValue
    private Long id;

    @Version
    @Column(name = "time_stamp")
    private Timestamp version;

    public Long getId() {
        return id;
    }

    @Override
    public String toString() {
        if (id == null) {
            return "";
        }

        return id.toString();
    }
}

@Entity
@Table(name = "demo")
public class Demo extends AbstractValueObject {
    private String name;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "demo")
    private List<Owner> owners;

    public Demo() {
        owners = new ArrayList<>();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Owner> getOwners() {
        return Collections.unmodifiableList(owners);
    }

    public void addOwner(Owner owner) {
        this.owners.add(owner);
        owner.setDemo(this);
    }

    public void addAllOwners(List<Owner> owners) {
        this.owners.addAll(owners);

        for (Owner owner : owners) {
            owner.setDemo(this);
        }
    }

    public void update(Demo demo) {
        this.setName(demo.getName());
        this.owners.clear();
        this.addAllOwners(demo.getOwners());
    }
}

@Entity
@Table(name = "owner")
public class Owner extends AbstractValueObject {
    private String attribute;

    @ManyToOne(cascade = CascadeType.ALL, optional = false)
    @JoinColumn(name = "demo_id", nullable = false)
    private Demo demo;

    public String getAttribute() {
        return attribute;
    }

    public void setAttribute(String attribute) {
        this.attribute = attribute;
    }

    public Demo getDemo() {
        return demo;
    }

    public void setDemo(Demo demo) {
        this.demo = demo;
    }
}

之后,我为demo实体创建了一个JPA存储库,扩展自jparepository-

import org.springframework.data.jpa.repository.JpaRepository;

public interface DemoRepository extends JpaRepository<Demo, Long> {}
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;

public class DemoServiceImpl implements DemoService {
    @Resource
    private DemoRepository demoRepository;

    @Override
    @Transactional
    public Demo create(Demo demo) {
        return demoRepository.save(demo);
    }

    @Override
    @Transactional
    public Demo update(long id, Demo demo) {
        Demo dbDemo = demoRepository.findOne(id);
        if (dbDemo == null) {
            return demo;
        }

        dbDemo.update(demo);
        return dbDemo;
    }

    @Transactional
    public void testRun() {
        Owner owner = new Owner();
        owner.setAttribute("attribute");

        Demo demo = new Demo();
        demo.setName("demo");
        demo.addOwner(owner);

        this.create(demo);

        demo.setName("another");
        this.update(demo.getId(), demo);
    }
}

persistence.xml文件-

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
    version="2.1">

    <persistence-unit name="jpa-optimistic-locking" transaction-type="RESOURCE_LOCAL">
    </persistence-unit>
</persistence>

Spring应用程序-context.xml-

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <context:component-scan base-package="com.keertimaan.example.jpaoptimisticlocking" />
    <jpa:repositories base-package="com.keertimaan.example.jpaoptimisticlocking.repository" />

    <bean id="demoService" class="com.keertimaan.example.jpaoptimisticlocking.service.DemoServiceImpl" />

    <!-- JPA/Database/Transaction Configuration -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" />
        <property name="user" value="root" />
        <property name="password" value="admin123" />

        <property name="minPoolSize" value="1" />
        <property name="maxPoolSize" value="2" />
        <property name="acquireIncrement" value="1" />
        <property name="maxStatements" value="5" />
        <property name="idleConnectionTestPeriod" value="500" />
        <property name="maxIdleTime" value="1000" />
        <property name="loginTimeout" value="800" />
    </bean>
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="jpa-optimistic-locking" />
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
        </property>
        <property name="persistenceProvider">
            <bean class="org.hibernate.jpa.HibernatePersistenceProvider" />
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">validate</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
            </props>
        </property>
    </bean>
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

现在,每当我试图在Windows7上更新这样的实体时-

public class App {
    public static void main(String[] args) {
        DemoService demoService = (DemoService) SpringHelper.INSTANCE.getBean("demoService");
        demoService.testRun();
    }
}

我使用的是windowsw7 64位版-

操作系统名称:Microsoft Windows 7 Enterprise

操作系统版本:6.1.7601 Service Pack 1 Build 7601

Windows中的MySQL Server版本:5.6.23-日志MySQL Community Server(GPL)

Ubuntu中的MySQL服务器版本:5.5.41-0ubuntu0.12.04.1(Ubuntu)

共有1个答案

慕冠宇
2023-03-14

我有一种感觉,这与MySQL 5.6的时间戳精度有关。MySQL5.6.4引入了微秒级精度,这将导致版本不匹配,锁定将失败。

 类似资料:
  • 我在Oracle的博客上读到一篇关于JPA和锁定模式的文章。 我不完全理解和锁定模式类型之间的区别。 模式: 当用户选择这种模式时,他必须将EntityManager的状态flush()放到数据库中,以手动增加版本字段。因此,所有其他乐观事务都将失效(回滚)。在事务结束时还会对版本进行检查,以提交或回滚事务。 这似乎很清楚,但什么时候应该使用模式与模式?我看到的唯一标准是,当我希望事务优先于其他事

  • 我使用SpringDataJPA和Hibernate作为PostgreSQL上的持久性提供者。我试图提供悲观锁定: 我尝试从两个线程中调用< code>findOneAndLock。我认为,如果< code >线程A锁定了对象,那么< code >线程B应该等到锁被释放。而是< code >线程B抛出< code > org . spring framework . ORM . objectopt

  • 我最近在ubuntu 16.04中查看了node的版本,当使用命令时,它显示了版本6.9.1,但当使用此命令之前,它显示了6.9.2。 现在,和有什么区别?以及如何更新到node/nodejs的最新LTS版本?

  • 我们有一个系统,我们偶尔会得到一个乐观的锁定异常。我们在代码中已经解决了这个问题,但现在我正在查看JPA 2,并看到它有一个用于处理这个问题的注释(@版本) 我们的问题是,一个表上有多个事务,如果表锁已满,则即使未对相同的记录进行更改,也会导致乐观锁定异常。 我们在JBoss 4.2服务器上使用hibernate,数据库可以是MySQL或SQL服务器。 如果改为使用@Version,这会在两个数据

  • 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,会产生冲突,解决方案有两种:乐观锁、悲观锁。 悲观锁在这里不讲,自行Google。 乐观锁假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性,不完整则更新失败。 乐观锁实现方式 使用整数表示数据版本号.更新时检查版本号是否一致,如果相等,则更新成功,且版本号+1.如果不等,则数据已经被修改过,更新失败。 使用时间戳来实现。 本质上也