Spring Boot应用程序无法找到SQLite jdbc驱动程序类。

3

在我的Spring Boot应用程序中,我已经指定了sqlite jdbc驱动器的依赖关系:

<dependency>
  <groupId>org.xerial</groupId>
  <artifactId>sqlite-jdbc</artifactId>
  <version>3.34.0</version>
</dependency>

还有在pom.xml属性中

<hibernate.version>5.1.0.Final</hibernate.version>

我在我的application.properties文件中有以下内容:

spring.jpa.database-platform=com.springboot.sqlite.SQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.defer-datasource-initialization = true

spring.datasource.url = jdbc:sqlite:cryptobot.db
spring.datasource.driver-class-name = org.sqlite.JDBC

我提供的SQLDialect类是从这篇文章中复制的。但是运行应用程序失败了。
org.springframework.beans.factory.UnsatisfiedDependencyException: 在 classpath 路径下定义的 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class] 中创建名为 'entityManagerFactory' 的 bean 时出错:在表示方法 'entityManagerFactory' 的参数 0 时表达的不满意依赖关系。嵌套异常是 org.springframework.beans.factory.UnsatisfiedDependencyException: 在 classpath 路径下定义的 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class] 中创建名为 'entityManagerFactoryBuilder' 的 bean 时出错:在表示方法 'entityManagerFactoryBuilder' 的参数 0 时表达的不满意依赖关系。嵌套异常是 org.springframework.beans.factory.BeanCreationException: 创建名为 'jpaVendorAdapter' 的 bean 时出错,在 classpath 路径资源 [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class] 中定义:通过工厂方法实例化 Bean 失败。嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [org.springframework.orm.jpa.JpaVendorAdapter],因为工厂方法 'jpaVendorAdapter' 抛出异常。嵌套异常是 java.lang.NoClassDefFoundError: org/hibernate/jpa/HibernatePersistenceProvider

这里出了什么问题?


1
@HughDarling 你是否通过扩展 org.hibernate.dialect.Dialect 配置了 SQLDialect - I AM GROOT
1
是的,com.springboot.sqlite.SQLDialect是我自己的,实际上是从你提到的文章中复制过来的。 - Walking Corpse
1
我几天后重新尝试,但现在它显示了一个不同的错误:java.lang.NoClassDefFoundError: org/hibernate/jpa/HibernatePersistenceProvider。 - Walking Corpse
1
请更新您的问题,包括最新的异常信息。更重要的是,您使用的是哪个版本的Spring Boot?如果您告诉我这些信息,我可能会有一些想法。 - Ken Chan
@HughDarling。请更新我的答案。这应该解决你的问题。请检查。 - Ken Chan
显示剩余4条评论
3个回答

3

主要问题是你在pom.xml中的以下配置明确地配置了使用Hibernate 5.1.0

<hibernate.version>5.1.0.Final</hibernate.version>

这个(指的是Hibernate版本)太旧了(已发布6年),而spring-boot 2.6.1已经长时间不再支持它。

从技术上讲,spring-boot 2.6基于spring 5.3开发和测试,并针对Hibernate 5.3+进行优化,同时试图在运行时基于最佳努力原则与Hibernate 5.2保持向后兼容性。您可以在HibernateJpaVendorAdapter的javadoc以及这个issue中找到这样的信息。

它尝试在某个时刻加载org.hibernate.jpa.HibernatePersistenceProvider,但是该类仅自Hibernate 5.2起存在。由于您现在正在使用Hibernate 5.1,因此它会报错,无法加载,如下所示:

[org.springframework.orm.jpa.JpaVendorAdapter]: Factory method 'jpaVendorAdapter' threw exception; nested exception is java.lang.NoClassDefFoundError: org/hibernate/jpa/HibernatePersistenceProvider

因此,只需在pom.xml中删除上述的<hibernate.version>,这样它将使用由spring-boot 2.6.1定义的hibernate 5.6.1,然后您的问题就可以解决了。对于新项目使用非常旧的Hibernate版本是没有意义的。


我知道你提到你已经解决了这个问题,现在我的回答与你的问题不匹配了。我稍后会查看你更新后的问题,并在那之后更新我的回答。谢谢。 - Ken Chan
我在pom.xml中删除了hibernate.version,但仍然会下载并设置hibernate 5.1.0的jar包到classpath中,并出现HibernatePersistenceProvider的NoClassDefFound错误。我不知道从哪里指定了5.1.0 final版本。我已经执行了mvn clean install,但没有改变任何东西。 - Walking Corpse
我已经在这里放置了pom.xml,/tmp/jvm.out 显示正在运行的应用程序类路径和 mvn dependency:tree 输出:shorturl.at/tINY7。 - Walking Corpse
你的 pom.xml 应该是正确的。所以看起来是你的 IDE 配置问题导致它仍然在类路径中包含了 hibernate 5.1.0。你可以尝试刷新项目吗?或者只需创建一个新项目再试一次? - Ken Chan
1
是的,现在它可以工作了,确认是一个IDE问题。 - Walking Corpse
显示剩余3条评论

0

我尝试在我的本地机器上复制这个问题,并找到了解决方案。

您需要通过扩展org.hibernate.dialect来创建自己的方言

package com.mehul.SQLiteDemo.dialect;

import java.sql.Types;

import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.function.SQLFunctionTemplate;
import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.dialect.function.VarArgsSQLFunction;
import org.hibernate.type.StringType;

public class SQLDialect extends Dialect {
    public SQLDialect() {
        registerColumnType(Types.BIT, "integer");
        registerColumnType(Types.TINYINT, "tinyint");
        registerColumnType(Types.SMALLINT, "smallint");
        registerColumnType(Types.INTEGER, "integer");
        registerColumnType(Types.BIGINT, "bigint");
        registerColumnType(Types.FLOAT, "float");
        registerColumnType(Types.REAL, "real");
        registerColumnType(Types.DOUBLE, "double");
        registerColumnType(Types.NUMERIC, "numeric");
        registerColumnType(Types.DECIMAL, "decimal");
        registerColumnType(Types.CHAR, "char");
        registerColumnType(Types.VARCHAR, "varchar");
        registerColumnType(Types.LONGVARCHAR, "longvarchar");
        registerColumnType(Types.DATE, "date");
        registerColumnType(Types.TIME, "time");
        registerColumnType(Types.TIMESTAMP, "timestamp");
        registerColumnType(Types.BINARY, "blob");
        registerColumnType(Types.VARBINARY, "blob");
        registerColumnType(Types.LONGVARBINARY, "blob");
        // registerColumnType(Types.NULL, "null");
        registerColumnType(Types.BLOB, "blob");
        registerColumnType(Types.CLOB, "clob");
        registerColumnType(Types.BOOLEAN, "integer");

        registerFunction("concat", new VarArgsSQLFunction(StringType.INSTANCE, "", "||", ""));
        registerFunction("mod", new SQLFunctionTemplate(StringType.INSTANCE, "?1 % ?2"));
        registerFunction("substr", new StandardSQLFunction("substr", StringType.INSTANCE));
        registerFunction("substring", new StandardSQLFunction("substr", StringType.INSTANCE));
    }

    public boolean supportsIdentityColumns() {
        return true;
    }

    public boolean hasDataTypeInIdentityColumn() {
        return false; // As specify in NHibernate dialect
    }

    public String getIdentityColumnString() {
        // return "integer primary key autoincrement";
        return "integer";
    }

    public String getIdentitySelectString() {
        return "select last_insert_rowid()";
    }

    public boolean supportsLimit() {
        return true;
    }

    protected String getLimitString(String query, boolean hasOffset) {
        return new StringBuffer(query.length() + 20).append(query).append(hasOffset ? " limit ? offset ?" : " limit ?")
                .toString();
    }

    public boolean supportsTemporaryTables() {
        return true;
    }

    public String getCreateTemporaryTableString() {
        return "create temporary table if not exists";
    }

    public boolean dropTemporaryTableAfterUse() {
        return false;
    }

    public boolean supportsCurrentTimestampSelection() {
        return true;
    }

    public boolean isCurrentTimestampSelectStringCallable() {
        return false;
    }

    public String getCurrentTimestampSelectString() {
        return "select current_timestamp";
    }

    public boolean supportsUnionAll() {
        return true;
    }

    public boolean hasAlterTable() {
        return false; // As specify in NHibernate dialect
    }

    public boolean dropConstraints() {
        return false;
    }

    public String getAddColumnString() {
        return "add column";
    }

    public String getForUpdateString() {
        return "";
    }

    public boolean supportsOuterJoinForUpdate() {
        return false;
    }

    public String getDropForeignKeyString() {
        throw new UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect");
    }

    public String getAddForeignKeyConstraintString(String constraintName, String[] foreignKey, String referencedTable,
            String[] primaryKey, boolean referencesPrimaryKey) {
        throw new UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect");
    }

    public String getAddPrimaryKeyConstraintString(String constraintName) {
        throw new UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect");
    }

    public boolean supportsIfExistsBeforeTableName() {
        return true;
    }

    public boolean supportsCascadeDelete() {
        return false;
    }
}

还需更新spring.jpa.database-platform=com.mehul.SQLiteDemo.dialect.SQLDialect到您的包名和类名。

注:我使用了<hibernate.version>5.6.3.Final</hibernate.version>


0

由于Hibernate没有SQLite的方言,您可以按照以下路径进行操作:

1. 通过扩展Dialect创建自己的方言类。

import java.sql.Types;
import org.hibernate.dialect.Dialect;

public class SQLiteDialect extends Dialect {
 public SQLiteDialect() {
  super();
  registerColumnType(Types.BIT, "integer");
  registerColumnType(Types.TINYINT, "tinyint");
  registerColumnType(Types.SMALLINT, "smallint");
  registerColumnType(Types.INTEGER, "integer");
  registerColumnType(Types.BIGINT, "bigint");
  registerColumnType(Types.FLOAT, "float");
  registerColumnType(Types.REAL, "real");
  registerColumnType(Types.DOUBLE, "double");
  registerColumnType(Types.NUMERIC, "numeric");
  registerColumnType(Types.DECIMAL, "decimal");
  registerColumnType(Types.CHAR, "char");
  registerColumnType(Types.VARCHAR, "varchar");
  .
  .
  .
 }
}

点击查看完整示例。

2. 您可以使用第三方方言。

对于Hibernate 5,请添加依赖项

    <dependency>
        <groupId>com.github.gwenn</groupId>
        <artifactId>sqlite-dialect</artifactId>
        <version>0.1.2</version>
    </dependency>

以及配置:

hibernate.dialect=org.sqlite.hibernate.dialect.SQLiteDialect


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接