休眠级联持续存在:执行隔离工作时出错

Posted

技术标签:

【中文标题】休眠级联持续存在:执行隔离工作时出错【英文标题】:Hibernate cascade persist: error performing isolated work 【发布时间】:2016-12-04 13:42:58 【问题描述】:

@ManyToOne 与 Hibernate 和 SQLite 的双向关系存在一些问题。实体是人:

@Entity
public class Person 

    @Id
    @GeneratedValue
    private Long id;

    @ManyToOne
    private Company company;

    public void setCompany(Company company) 
        this.company = company;
    

和公司:

@Entity
public class Company 

    @Id
    @GeneratedValue
    private Long id;

    @OneToMany(mappedBy = "company", cascade =  CascadeType.PERSIST )
    private Set<Person> staff = new HashSet<>();

    public void addPerson(Person person) 

        if (staff.add(person)) 
            person.setCompany(this);
        
    

在一个简单的应用程序中,我使用公司创建了一个初始数据库,之后我打开一个新会话来加载公司实例并添加员工。我坚持公司并期望 Hibernate 坚持在cascade 中添加的人员。

public class App 

    public static void main(String[] args) 

        createDatabase();

        Session session = createSessionFactory("validate").openSession();

        Company company;

        session.beginTransaction();

        company = (Company) session.createCriteria(Company.class).uniqueResult();
        session.getTransaction().commit();

        company.addPerson(new Person());

        session.beginTransaction();
        session.persist(company);
        session.getTransaction().commit();
    

    private static void createDatabase() 

        Session session = createSessionFactory("create").openSession();

        Company company = new Company();
        session.beginTransaction();
        session.persist(company);
        session.getTransaction().commit();

        session.close();
    

    private static SessionFactory createSessionFactory(String ddl) 

        StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder()
            .configure("hibernate.cfg.xml");

        serviceRegistryBuilder
            .applySetting("hibernate.hbm2ddl.auto", ddl);

        SessionFactory sessionFactory = new MetadataSources(serviceRegistryBuilder.build())
            .buildMetadata()
            .buildSessionFactory();

        return sessionFactory;
    

但我得到了错误:

ERROR: database is locked
Exception in thread "main" org.hibernate.exception.GenericJDBCException: error performing isolated work

如果我在加入公司之前坚持这个人(所以没有级联),应用​​程序就可以工作。

我做错了什么?

这是完整的应用程序日志:

    июл 29, 2016 9:07:57 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate Core 5.1.0.Final
июл 29, 2016 9:07:57 PM org.hibernate.cfg.Environment <clinit>
INFO: HHH000206: hibernate.properties not found
июл 29, 2016 9:07:57 PM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: HHH000021: Bytecode provider name : javassist
июл 29, 2016 9:07:57 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit>
INFO: HCANN000001: Hibernate Commons Annotations 5.0.1.Final
июл 29, 2016 9:07:57 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
июл 29, 2016 9:07:57 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [org.sqlite.JDBC] at URL [jdbc:sqlite:default.sqlite]
июл 29, 2016 9:07:57 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: user=, password=****
июл 29, 2016 9:07:57 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
июл 29, 2016 9:07:57 PM org.hibernate.engine.jdbc.connections.internal.PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
июл 29, 2016 9:07:57 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.SQLiteDialect
июл 29, 2016 9:07:57 PM org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl useContextualLobCreation
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [2] less than 4
июл 29, 2016 9:07:57 PM org.hibernate.validator.internal.util.Version <clinit>
INFO: HV000001: Hibernate Validator 5.1.0.Final
Hibernate: 
    drop table if exists Company
Hibernate: 
    drop table if exists hibernate_sequence
Hibernate: 
    drop table if exists Person
Hibernate: 
    create table Company (
        id bigint not null,
        primary key (id)
    )
Hibernate: 
    create table hibernate_sequence (
        next_val bigint
    )
Hibernate: 
    insert into hibernate_sequence values ( 1 )
Hibernate: 
    insert into hibernate_sequence values ( 1 )
Hibernate: 
    create table Person (
        id bigint not null,
        company_id bigint,
        primary key (id)
    )
июл 29, 2016 9:07:58 PM org.hibernate.tool.schema.internal.SchemaCreatorImpl applyImportSources
INFO: HHH000476: Executing import script 'org.hibernate.tool.schema.internal.exec.ScriptSourceInputNonExistentImpl@43f82e78'
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
Hibernate: 
    insert 
    into
        Company
        (id) 
    values
        (?)
июл 29, 2016 9:07:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!)
июл 29, 2016 9:07:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: using driver [org.sqlite.JDBC] at URL [jdbc:sqlite:default.sqlite]
июл 29, 2016 9:07:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: user=, password=****
июл 29, 2016 9:07:59 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
июл 29, 2016 9:07:59 PM org.hibernate.engine.jdbc.connections.internal.PooledConnections <init>
INFO: HHH000115: Hibernate connection pool size: 20 (min=1)
июл 29, 2016 9:07:59 PM org.hibernate.dialect.Dialect <init>
INFO: HHH000400: Using dialect: org.hibernate.dialect.SQLiteDialect
июл 29, 2016 9:07:59 PM org.hibernate.engine.jdbc.env.internal.LobCreatorBuilderImpl useContextualLobCreation
INFO: HHH000423: Disabling contextual LOB creation as JDBC driver reported JDBC version [2] less than 4
Hibernate: 
    select
        this_.id as id1_0_0_ 
    from
        Company this_
Hibernate: 
    select
        personal0_.company_id as company_2_1_0_,
        personal0_.id as id1_1_0_,
        personal0_.id as id1_1_1_,
        personal0_.company_id as company_2_1_1_ 
    from
        Person personal0_ 
    where
        personal0_.company_id=?
Hibernate: 
    select
        next_val as id_val 
    from
        hibernate_sequence
Hibernate: 
    update
        hibernate_sequence 
    set
        next_val= ? 
    where
        next_val=?
июл 29, 2016 9:08:02 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
WARN: SQL Error: 0, SQLState: null
июл 29, 2016 9:08:02 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions
ERROR: database is locked
Exception in thread "main" org.hibernate.exception.GenericJDBCException: error performing isolated work
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:47)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:111)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:97)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:79)
    at org.hibernate.id.enhanced.TableStructure$1.getNextValue(TableStructure.java:125)
    at org.hibernate.id.enhanced.NoopOptimizer.generate(NoopOptimizer.java:40)
    at org.hibernate.id.enhanced.SequenceStyleGenerator.generate(SequenceStyleGenerator.java:412)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:105)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:189)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:132)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:768)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:761)
    at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:297)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:391)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:316)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:155)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:424)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:356)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:319)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:155)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:104)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:445)
    at org.hibernate.event.internal.DefaultPersistEventListener.justCascade(DefaultPersistEventListener.java:172)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsPersistent(DefaultPersistEventListener.java:164)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:128)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:778)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:751)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:756)
    at my.tests.hibernate.App.main(App.java:29)
Caused by: java.sql.SQLException: database is locked
    at org.sqlite.core.DB.throwex(DB.java:859)
    at org.sqlite.core.DB.exec(DB.java:142)
    at org.sqlite.jdbc3.JDBC3Connection.commit(JDBC3Connection.java:165)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:60)
    ... 26 more

更新似乎,这是一个 Hibernate-SQLite 问题,因为如果我更改 H2 上的数据库,一切正常。

【问题讨论】:

【参考方案1】:

可以尝试添加strategy,生成id:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

【讨论】:

以上是关于休眠级联持续存在:执行隔离工作时出错的主要内容,如果未能解决你的问题,请参考以下文章

隔离存储中的数据持续多长时间

mysql 四种隔离级别

ACID数据库隔离级别

事务隔离级别

事务的特性和隔离级别

事务隔离级别