首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Hibernate版本控制/乐观锁定本身是否会使实例变脏

问Hibernate版本控制/乐观锁定本身是否会使实例变脏
EN

Stack Overflow用户
提问于 2019-10-30 03:41:29
回答 2查看 158关注 0票数 1

使用@Version注释进行乐观锁定时,更新现有记录时出现问题。

具有这样一个注解方法的表(比如:"X"):

代码语言:javascript
复制
@Id()  @GeneratedValue(strategy = GenerationType.SEQUENCE)   
@Column(name="calcid")
private int calcId;
@Version @Column(name="version")
protected Integer version;

使用这种方法(pp是单例持久化提供程序):

获取记录:

代码语言:javascript
复制
Session session = [my persistency provider singleton].openSession();
session.beginTransaction();
List<X> xx = session.createQuery("from x",X.class).getResultList();
pp.closeSession();
return xx

更改xx-list中的记录x,并将此记录(仅此记录)放入列表,发送到合并例程(不要混淆列表-其中只有一条记录-已更改的记录,但这样我就可以合并多条记录了):

合并相同的记录

代码语言:javascript
复制
  Session session = [my persistency provider singleton].openSession();
  session.beginTransaction(); 
  xx.forEach(x -> { session.merge(x);});
  try {
    session.getTransaction().commit();
  } catch (OptimisticLockException e) {
    pp.closeSession();
    throw e;
  }     
  pp.closeSession();

虽然我可以在合并之前检查@Id,并看到它与最初获取的记录相同,但结果是一个具有新id的新记录。

如果我只是删除版本注释(和版本字段),合并就会像预期的那样运行(与上面的代码完全相同,只是没有@Version和version-column),从而更新现有的记录。

请注意,尽管问题似乎与乐观锁定方法中涉及的@版本有关,但在上面的示例中,只涉及一个会话。

似乎@版本本身就使Hibernate将原始实例视为新实例(即使id是相同的),从而使用新的Id创建新的实例。

Hibernate新手,所以TIA需要任何帮助!

使用MariaDB (FKA MySQL)版本10.Hibernate 5和以下配置文件:

代码语言:javascript
复制
    <?xml version="1.0" encoding="UTF-8"?>

<!-- <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 5.3//EN" "http://www.hibernate.org/dtd/hibernate-configuration-5.3.dtd"> -->

<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd" PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN">
-<hibernate-configuration>
-<session-factory>
<!-- <property name="hbm2ddl.auto">update</property> -->
<property name="hbm2ddl.auto">update</property>
<property name="dialect">org.hibernate.dialect.MySQL8Dialect</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">xxx</property>
<property name="connection.password"/>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.show_sql">false</property>
<mapping class="niels.test.Test"/>
</session-factory>
</hibernate-configuration>

诚挚的问候

EN

回答 2

Stack Overflow用户

发布于 2019-10-30 11:57:23

有关更多信息,请参阅以下文章

https://vladmihalcea.com/jpa-entity-version-property-hibernate/

票数 0
EN

Stack Overflow用户

发布于 2019-11-03 04:02:12

老实说,我不能重现你的问题。因此,我提供了完整的工作示例。希望,这将是有帮助的。

测试数据定义:

代码语言:javascript
复制
create table TST_DATA
(
   RECID int primary key,
   VAL varchar(100),
   OPTLOCK int
);
create sequence SEQ_TST_DATA_RECID start with 1 increment by 1;
insert into TST_DATA(RECID, VAL, OPTLOCK)
values (NEXTVAL(SEQ_TST_DATA_RECID), "row 1", 0), (NEXTVAL(SEQ_TST_DATA_RECID), "row 2", 0);

hibernate配置hibernate.cfg.xml

代码语言:javascript
复制
<!DOCTYPE hibernate-configuration SYSTEM "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.mariadb.jdbc.Driver</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MariaDB103Dialect</property> 

        <property name="hibernate.connection.url">jdbc:mariadb://localhost:3306/TEST_HIBERNATE</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.connection.password">xxxx</property>

        <property name="hibernate.id.new_generator_mappings">true</property>

        <property name="hibernate.current_session_context_class">thread</property>

        <!-- https://stackoverflow.com/questions/438146 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- You can use this for checking actually generated sql -->
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="use_sql_comments">true</property>
    </session-factory>
</hibernate-configuration>

实体:

代码语言:javascript
复制
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Version;

@Entity
@Table(name="TST_DATA")
public class TestData
{
   private Long recId;
   private String value;
   private int version;

   @Id
   @Column(name="RECID")
   @SequenceGenerator(name="SEQ_TST_GEN", sequenceName="SEQ_TST_DATA_RECID", allocationSize=1)
   @GeneratedValue(generator="SEQ_TST_GEN", strategy=GenerationType.SEQUENCE) 
   public Long getRecId()
   {
      return recId;
   }
   public void setRecId(Long val)
   {
      recId = val;
   }

   @Column(name="VAL")
   public String getValue()
   {
      return value;
   }
   public void setValue(String val)
   {
      value = val;
   }

   @Version
   @Column(name="OPTLOCK")
   public int getVersion()
   {
      return version;
   }
   public void setVersion(int val)
   {
      version = val;
   }
}

启动器:

代码语言:javascript
复制
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import com.sternkn.inhibernate.entities.TestData;


public class Main
{
   private static final SessionFactory sessionFactory;

   static {
      MetadataSources metadata = new MetadataSources(
            new StandardServiceRegistryBuilder().configure("hibernate.cfg.xml").build()
      );
      metadata.addAnnotatedClass(TestData.class);
      sessionFactory = metadata.buildMetadata().buildSessionFactory();
   }

   public static void main(String[] args)
   {
      List<TestData> datas = getData();
      print(datas);

      merge(datas);
      print(datas);

      datas.forEach(row -> {
         row.setValue(row.getValue() + " new");
      });
      merge(datas);
      print(datas);

      TestData data = new TestData();
      data.setValue("test www...");
      data.setVersion(0);
      create(data);
   }

   private static void print(List<TestData> datas)
   {
      datas.forEach(row -> {
         System.out.println("row(" + row.getRecId() + ", " + row.getValue() + ", " + row.getVersion() + ")");
      });
   }

   private static List<TestData> getData()
   {
      Session session = sessionFactory.openSession();
      List<TestData> data;
      try
      {
         Transaction transaction = session.beginTransaction();
         data = session.createQuery("from TestData", TestData.class).getResultList();
         transaction.commit();
      }
      finally {
         session.close();
      }
      return data;
   }

   private static void merge(List<TestData> datas)
   {
      Session session = sessionFactory.openSession();
      try
      {
         Transaction transaction = session.beginTransaction();
         datas.forEach(row -> {
            session.merge(row);
         });
         transaction.commit();
      }
      finally {
         session.close();
      }

   }

   private static void create(TestData data)
   {
      Session session = sessionFactory.openSession();
      try
      {
         Transaction transaction = session.beginTransaction();
         session.persist(data);
         transaction.commit();
      }
      finally {
         session.close();
      }
   }
}

最后是maven pom.xml

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sternkn.inhibernate</groupId>
    <artifactId>InHibernate</artifactId>
    <version>0.1</version>
    <packaging>jar</packaging>
    <name>InHibernate</name>
    <description>Hibernate learning project</description>

    <properties>
        <outputDirectory>${project.build.directory}/lib</outputDirectory>
        <java.version>1.8</java.version>
        <hibernate.version>5.4.4.Final</hibernate.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mariadb.jdbc</groupId>
            <artifactId>mariadb-java-client</artifactId>
            <version>2.5.1</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
      <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.xml.bind</groupId>
                    <artifactId>jaxb-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.glassfish.jaxb</groupId>
                    <artifactId>jaxb-runtime</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
      </dependencies>
    </dependencyManagement>

    <build>
        <sourceDirectory>src</sourceDirectory>
        <resources>
            <resource>
                <directory>resources</directory>
            </resource>
        </resources>

        <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>3.8.1</version>
               <configuration>
                   <source>${java.version}</source>
                   <target>${java.version}</target>
               </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.10</version>
                <configuration>
                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    <overWriteReleases>true</overWriteReleases>
                    <overWriteSnapshots>true</overWriteSnapshots>
                    <overWriteIfNewer>true</overWriteIfNewer>
                </configuration>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib</classpathPrefix>
                            <mainClass>com.sternkn.inhibernate.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

作为上述示例工作的结果,我们将具有以下db状态:

代码语言:javascript
复制
SQL> select * from TST_DATA;
RECID  VAL          OPTLOCK
------ ------------ --------
1      row 1 new    1
2      row 2 new    1
3      test www...  0
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58614327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档