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

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

宓文斌
2023-03-14

这个问题可以看作是Hibernate悲观锁定不适用于多态查询的后续问题

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

我使用的PostgreSQL驱动程序不支持外部联接和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 bug,它忽略了RDBMS不能处理这个情况并且不适应它的请求的事实?
  • 还有别的吗

如果有什么区别的话,这是PostgreSQL(10)、Hibernate(5.4.3)和驱动程序(42.2)的最新版本。使用的方言是PostgreSQL10方言。

共有1个答案

东方华荣
2023-03-14

我按照@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);
    }
}
 类似资料:
  • 问题内容: 当我尝试编译时,它给了我错误 我应该如何解决这个问题? 问题答案: 该错误是由于以下事实导致的:调用将是不明确的- 应该调用两种方法中的哪一种?从JLS§8.4.2开始: 在类中声明两个具有重写等效签名的方法是编译时错误。 方法的返回类型不是其签名的一部分,因此根据上述说明,您将收到错误。 假设您不能简单地重命名冲突的方法,在这种情况下就不能使用继承,并且需要使用诸如compositi

  • 我有一个简单的类,注释为 例如: 然后我有一个扩展这个bean的配置bean: 似乎忽略了有条件的,无论条件如何解决,都会始终处理配置(甚至没有调用) 只要我将有条件注释移动到MyConfig,一切都会正常工作。 从文档: @条件注释可以以下列任何一种方式使用: 作为使用@组件直接或间接注释的任何类的类型级注释,包括@配置类 我假设第一点适用于这里,即MyConfig间接地用配置注释。或者间接引用

  • 问题内容: 我在使用Python进行面向对象的编程方面非常陌生,并且在理解函数(新样式类)时遇到困难,特别是在涉及多重继承时。 例如,如果你有类似的东西: 我不明白的是:该类会继承两个构造函数方法吗?如果是,那么哪个将与一起运行,为什么? 而如果要运行另一个呢?我知道这与Python方法解析顺序有关。 问题答案: Guido自己在他的博客文章(包括两次较早的尝试)中对此进行了合理的详细说明。 在你

  • 处理 css 兼容性需要使用到 postcss-loader 和postcss-preset-env两个插件 一、css 兼容性处理核心配置 1.1、修改webpack.config.js 配置文件 // webpack.config.js webpack的配置文件 // 路径: ./webpack.config.js ………… // 设置 nodejs 环境变量 process.

  • 我在抽象课上有以下内容... 还有另一个类,它继承了这个类... 当我从主类执行以下调用时,我收到一个错误... 我的问题是..为什么会发生这种情况?我的getEntityById不是返回T型的东西,在这种情况下应该是产品吗? 我在 Netbeans 中工作,编译时未显示任何错误。 感谢您的帮助=)

  • 并尝试通过Hibernate使用策略连接实现继承,但当我使用此策略时,我收到异常: 奇怪的是,如果我选择另一个策略(单表或TABLE_PER_CLASS),错误不会出现