Hibernate如何处理pessismistic读取和继承的不兼容



这个问题可以被认为是Hibernate悲观锁定的后续问题,不适用于多态查询

让我们考虑一个比关联问题更简单的情况:两个实体a和B,其中B从a继承,都是具体的类。

我使用的PostgreSQL驱动程序不支持OUTER JOIN和FOR SHARE/FOR UPDATE的组合。

我什么时候做

sessionManager.get(A.class, id, new LockOptions(PESSIMISTIC_READ))); 

我会有逻辑错误:

ERREUR: FOR SHARE ne peut ?e appliqu?ur le c??possiblement NULL d'une jointure externe

这是我前面说的法语版本

我可以";解决";技术上是这样的:

A a = (A) sessionManager.get(B.class, id, new LockOptions(lockMode));
if(a== null) {
return  (A) sessionManager.get(A.class, id, new LockOptions(lockMode));
}else {
return a;
}

但你可以理解我对此有意见。

虽然我不确定能否在当前的项目中做得更好,但我想知道问题出在哪里:

  • 我不应该有两个从另一个继承的具体类,而是应该有一个抽象类和两个具体类吗
  • 当我加载给定的id时,我应该已经知道我加载的具体类型吗
  • 我是否应该考虑一个hibernate错误,它忽略了RDBMS无法处理这种情况并且不调整其请求的事实
  • 还有别的吗

如果有什么不同的话,那就是PostgreSQL(10+(和Hibernate(5.4.3(的最新版本以及驱动程序(42.2+(。使用的方言是PostgreSQL 10方言。

按照@ChristianBeikov的建议,我升级到了Hibernate 5.4.31,我不再有这个问题了。

以下是升级前重现问题的代码:

pom.xml

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>hibernate.test</groupId>
<artifactId>test-outer-join-null</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.23.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.9</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>9.0.1</version>
</dependency>
</dependencies>
@Configuration
@ComponentScan(basePackages = {"hibernate.test.service"})
@EnableTransactionManagement
public class HibernateConf {
@Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("hibernate.test");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://127.0.0.1:5432/test");
dataSource.setUsername("test");
dataSource.setPassword("test");
return dataSource;
}
@Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager
= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}

private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty(
"hibernate.hbm2ddl.auto", "update");
hibernateProperties.setProperty(
"hibernate.show_sql", "true");
hibernateProperties.setProperty(
"hibernate.dialect", "org.hibernate.dialect.PostgreSQL10Dialect");
return hibernateProperties;
}
}

----实体------

@Entity(name = "test_a")
@Inheritance(strategy = InheritanceType.JOINED)
public class A {
@Id
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public A() {
super();
}
public A(int id, String name) {
this.id = id;
this.name = name;
}
}

@Entity(name = "test_b")
@Inheritance(strategy = InheritanceType.JOINED)
public class B extends A{
@Column(name="last_name")
private String lastName;
public String getLastName() {
return lastName;
}
public void setLastName(String name) {
this.lastName = name;
}
public B() {
super();
}
public B(int id, String name, String lastName) {
super(id, name);
this.lastName = lastName;
}   
}

------服务-----

public interface IService {
public void init();
<T extends A> void listCriteria(Class<T> theClass);
}
@org.springframework.stereotype.Service
public class Service implements IService{
@Autowired
SessionFactory sessionFactory;
@Override
@Transactional
public void init() {
Session session = sessionFactory.getCurrentSession();
A a = new A((int)Math.round(Math.random()*1000000), "a");
B b = new B((int)Math.round(Math.random()*1000000), "a", "b");
session.persist(a);
session.persist(b);
}
@Override
@Transactional
public <T extends A> void listCriteria(Class<T> theClass) {
Session session = sessionFactory.getCurrentSession();
T t = session.get(theClass, 3, LockMode.PESSIMISTIC_WRITE); // <---- the error happens HERE
System.out.println(t);
}
}

------主------

public static void main(String[] args) {
try(AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(HibernateConf.class)){
IService manager  = context.getBean(IService.class);
manager.init();
manager.list(A.class);
manager.listCriteria(A.class);
System.out.println("====================");
manager.list(B.class);
manager.listCriteria(B.class);
}
}

最新更新