java - Hibernate SQlite映射类与内部类异常数据库文件被锁定(database is lock)

标签 java hibernate sqlite mapping hibernate-mapping

我需要将对象与一个内部对象进行映射,该内部对象还有一个内部对象或内部数组。

来自这个答案

{  
   "id":1,
   "zip_code":"0001",
   "user":{  
      "data":{  
         "id":1,
         "username":"user",
         "email":"user@gmail.com"
      }
   }
}

如果我评论对象字段并只留下 zipCode 和 id 则一切正常。

StackOverflow 表示 SQLite 应该有 1 个打开的 session 所以我将hibernate.connection.pool_size设置为1,这样它就会抛出

Java/Hibernate - Exception: The internal connection pool has reached its maximum size and no connection is currently available

但那是昨天的事了。今天我又遇到了“锁定异常”。
我认为级联有问题。当 hibernate 尝试保存第一个 MainEntity 时,它应该保存 User,但 DB 已经锁定,结果会抛出异常。 即使我是对的,我也不知道如何避免它。我尝试使用 MERGE 级联类型,但它在我的情况下不起作用。

将项目添加到 git 存储库 https://github.com/JoaoMunozIII/hibernate

更多信息如下。

此sql查询之后

Hibernate: select mainentity_.mId, mainentity_.mZipCode as mZipCode2_0_ from main_entity mainentity_ where mainentity_.mId=?
Hibernate: select next_val as id_val from hibernate_sequence
Hibernate: update hibernate_sequence set next_val= ? where next_val=?

我遇到了这个异常 [SQLITE_BUSY] 数据库文件已锁定(数据库已锁定)

org.hibernate.exception.LockAcquisitionException: error performing isolated work
    at dialect.SQLiteDialect$3.convert(SQLiteDialect.java:197)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    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.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:651)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:643)
    at org.hibernate.engine.spi.CascadingActions$5.cascade(CascadingActions.java:218)
    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.cascade(Cascade.java:104)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:414)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:252)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:182)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:125)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:97)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSaveOrUpdate(SessionImpl.java:651)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:643)
    at org.hibernate.internal.SessionImpl.saveOrUpdate(SessionImpl.java:638)
    at DAO.saveEntityDb(DAO.java:16)
    at Main.main(Main.java:32)
Caused by: org.sqlite.SQLiteException: [SQLITE_BUSY]  The database file is locked (database is locked)
    at org.sqlite.core.DB.newSQLException(DB.java:909)
    at org.sqlite.core.DB.newSQLException(DB.java:921)
    at org.sqlite.core.DB.throwex(DB.java:886)
    at org.sqlite.core.DB.exec(DB.java:155)
    at org.sqlite.jdbc3.JDBC3Connection.commit(JDBC3Connection.java:174)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcIsolationDelegate.delegateWork(JdbcIsolationDelegate.java:60)

在项目中。 我创建模型: 主要实体类

@Entity
@Table(name = "main_entity")
public class MainEntityModel {

    @Id
    private Long mId;

    private Long mZipCode;

    @OneToOne(cascade = CascadeType.ALL, targetEntity = User.class)
    @JoinColumn(name = "id", insertable = false, updatable = false)
    private User mUser;

    public Long getmId() {
        return mId;
    }

    public void setmId(Long mId) {
        this.mId = mId;
    }

    public Long getmZipCode() {
        return mZipCode;
    }

    public void setmZipCode(Long mZipCode) {
        this.mZipCode = mZipCode;
    }

    public User getmUser() {
        return mUser;
    }

    public void setmUser(User mUser) {
        this.mUser = mUser;
    }
}

用户类别

@Entity
@Table(name = "user_data")
public class User {

    @OneToOne(cascade = CascadeType.ALL, targetEntity = UserEntity.class)
    @JoinColumn(name="mId")
    private UserEntity mData;

    public UserEntity getData() {
        return mData;
    }

    public void setmData(UserEntity mData) {
        this.mData = mData;
    }

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

    public User() {
    }
}

用户实体类

@Entity
@Table(name = "user_entity")
public class UserEntity {

    @Id
    private Long mId;

    private String mUsername;

    public Long getmId() {
        return mId;
    }

    public void setmId(Long mId) {
        this.mId = mId;
    }

    public String getmUsername() {
        return mUsername;
    }

    public void setmUsername(String mUsername) {
        this.mUsername = mUsername;
    }
}

hibernate 实用程序

public class Hibernate {

    private static SessionFactory sessionFactory = null;
    private static String dbPath = "D:" + File.separator + "temp.db";

    public static SessionFactory getSessionFactory() {
        System.out.println("factory " + sessionFactory);
        if (sessionFactory == null) {
            Configuration cfg = new Configuration()
                    .setProperty("hibernate.connection.driver_class", "org.sqlite.JDBC")
                    .setProperty("hibernate.dialect", "dialect.SQLiteDialect")
                    .setProperty("hibernate.connection.pool_size", "1")
                    .setProperty("hibernate.connection.url", "jdbc:sqlite:" + dbPath)
                    .setProperty("hibernate.connection.username", "pass")
                    .setProperty("hibernate.connection.password", "pass")
                    .setProperty("hibernate.show_sql", "true")
                    .setProperty("hibernate.format_sql", "false")
                    .setProperty("hibernate.hbm2ddl.auto", "create-drop")
                    .setProperty("hibernate.use_sql_comments", "false")
                    .addAnnotatedClass(MainEntityModel.class)
                    .addAnnotatedClass(User.class)
                    .addAnnotatedClass(UserEntity.class);
            sessionFactory = cfg.buildSessionFactory();
            return sessionFactory;
        } else {
            return sessionFactory;
        }
    }

和主类

public class Main {

    static Long userId = 1l;
    private static Long entityId = 1l;
    private static Long entityZip = 1000l;
    private static List<MainEntityModel> mainEntityModelList = new ArrayList();

    public static void main(String[] args) {

        UserEntity userEntity = new UserEntity();
        userEntity.setmId(userId);
        userEntity.setmUsername("User Name " + userId++);

        User user = new User();
        user.setmData(userEntity);

        for (int i = 0; i < 5; i++) {
            MainEntityModel mainEntityModel = new MainEntityModel();
            mainEntityModel.setmId(entityId++);
            mainEntityModel.setmUser(user);
            mainEntityModel.setmZipCode(entityZip++);
            mainEntityModelList.add(mainEntityModel);
        }

        DAO.saveEntityDb(mainEntityModelList);

        System.out.println("saved");

        List<MainEntityModel> savedList = DAO.getEntityDb();

        for (MainEntityModel entity: savedList) {
            System.out.println(entity.getmZipCode() + "\t"
                            + entity.getmUser().getData().getmUsername()
            );
        }
    }
}

DAO 类

public class DAO {
    static final Session session = Hibernate.getSessionFactory().openSession();

    public static void saveEntityDb(List<MainEntityModel> entityList){
        Transaction tx=null;
        try {
            tx = session.beginTransaction();
            for (MainEntityModel entity : entityList) {
                session.saveOrUpdate(entity);
            }
            session.flush();
            tx.commit();
        } catch (Exception ex) {
            ex.printStackTrace();
            tx.rollback();
        } finally{
            if(session != null) {
                session.close();
            }
        }
    }

    public static List<MainEntityModel> getEntityDb(){
        Session session = Hibernate.getSessionFactory().openSession();
        List<MainEntityModel> entityModel = session.createQuery("from MainEntityModel").list();
        session.close();
        return entityModel;
    }
}

最佳答案

  1. 问题:自动生成user.id - 它与插入语句相互锁定/一致。
  2. 问题:锁定修复后,我们在输出循环中遇到 NPE

解决方案:

  1. 问题

    • 手动分配user.id并删除@GenerateValue()注释。 (已验证/测试)

      Main.java://or somewhere else
      ...
      user.setId(userId);
      ...
      
      
      User.java:
      ...
      @Id
      //!@GeneratedValue(strategy=GenerationType.AUTO)
      private Long id;
      ...
      
      • “其他地方”的一个不错的选择是:

        User.java:
        ...
        public void setmData(UserEntity mData) {
            this.mData = mData;
            if(mData == null) {
              this.id = null;
            } else {
              this.id = mData.getmId();
            }
        }
        
        @Id
        //!@GeneratedValue(strategy=GenerationType.AUTO)
        private Long id;
        ...
        
    • 或者:在先前/单独的事务中保留用户/用户数据。 ...就像...

      • “改进”你的 DAO.java:

        public static <T extends Object> void saveEntityDb(T... entityList) {
          //local variable!
          final Session session = Hibernate.getSessionFactory().openSession();
          Transaction tx = null;
          try {
            if (session.isConnected()) {
              tx = session.beginTransaction();
              for (T entity : entityList) {
                session.saveOrUpdate(entity);
              }
              session.flush();
              tx.commit();
            }
          } catch (HibernateException ex) {
            if (tx != null && tx.getStatus().canRollback()) {
              tx.rollback();
            }
          } finally {
            if (session != null) {
              session.close();
            }
          }
        }
        
      • 并使用它两次(!):

        Main.java:
        ...
        User user = new User();
        user.setmData(userEntity);
        //do this before...
        DAO.saveEntityDb(user);
        
        List<MainEntityModel> mainEntityModelList = ...
        //...you do this
        DAO.saveEntityDb(mainEntityModelList.toArray(new MainEntityModel[0]));
        
  2. 问题

    • 删除 MainEntityModelJoinColumn 上的 insertable = false, updatable = false

...这里的 OneToOne 有点奇怪 (@MainEntityModel) ,它可以工作,但可以用作 ManyToOne (5 到1?!)

关于java - Hibernate SQlite映射类与内部类异常数据库文件被锁定(database is lock),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48587094/

相关文章:

java - Hibernate:如何从 Hibernate 测试套件开始单个测试?

html - 在 IndexedDB 中,有没有办法进行排序复合查询?

Java 和 Hibernate - 如何与 SuperMappedClass 而不是实体建立 OneToOne 关系

sqlite - sqlite studio中引用数据库名称

c++ - 如何在一个 SQL 查询中更新和选择

java - 滚动条并导入 com.github.barteksc.pdfviewer.ScrollBar;是错误,PDF 查看器也会崩溃

java - Eclipse内容辅助,创建新对象时没有帮助

java - apacheds 和 tomcat docker 容器之间的连接问题

Java类类型

hibernate - 使用带有 hibernate 和 spring data jpa 的entityManager.getReference() 获取实体代理时避免不必要的 SQL 选择查询