使用@Version注释进行乐观锁定时,更新现有记录时出现问题。
具有这样一个注解方法的表(比如:"X"):
@Id() @GeneratedValue(strategy = GenerationType.SEQUENCE)
@Column(name="calcid")
private int calcId;
@Version @Column(name="version")
protected Integer version;使用这种方法(pp是单例持久化提供程序):
获取记录:
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,并将此记录(仅此记录)放入列表,发送到合并例程(不要混淆列表-其中只有一条记录-已更改的记录,但这样我就可以合并多条记录了):
合并相同的记录
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和以下配置文件:
<?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>诚挚的问候
发布于 2019-10-30 11:57:23
发布于 2019-11-03 04:02:12
老实说,我不能重现你的问题。因此,我提供了完整的工作示例。希望,这将是有帮助的。
测试数据定义:
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
<!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>实体:
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;
}
}启动器:
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
<?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状态:
SQL> select * from TST_DATA;
RECID VAL OPTLOCK
------ ------------ --------
1 row 1 new 1
2 row 2 new 1
3 test www... 0https://stackoverflow.com/questions/58614327
复制相似问题