hibernate 一些bug的分析

来源:互联网 发布:电视机安卓软件 编辑:程序博客网 时间:2024/05/22 12:08
 hibernate 错误分析
错误1:
 代码:
  Peopletable people=(Peopletable)session.load(Peopletable.class,"2");
  在hibernate3.1版中报的错误是:
  org.hibernate.exception.SQLGrammarException: could not insert: [net.gaoxin.Computertable]
  在hibernate3.2.6中报的错误是:
  Exception in thread "main" org.hibernate.TypeMismatchException: Provided id of the wrong type. Expected: class
java.lang.Integer, got class java.lang.String
  看来3.2版比3.1版更人性化,提示信息更明确。
  解决:
  Peopletable people=(Peopletable)session.load(Peopletable.class,new java.lang.Integer(2));
  后面的参数类型换成Integer/int的就可以了。
     看来后面一个变量的类型是int的。
 错误2:
 版本:hibernate-3.1
 代码:
     Peopletable people=(Peopletable)session.load(Peopletable.class,"2");
     computer.setPeople(people);
     session.save(computer);//错误行
 错误:
    Hibernate: insert into computertable (cmodel, people) values (?, ?) select scope_identity()
    16:34:17,953  INFO IntegerType:89 - could not bind value '2' to parameter: 2
    16:34:17,953  WARN JDBCExceptionReporter:71 - SQL Error: 0, SQLState: 07009
    16:34:17,984 ERROR JDBCExceptionReporter:72 - [Microsoft][SQLServer 2000 Driver for JDBC]Invalid parameter binding(s).
    Exception in thread "main" org.hibernate.exception.SQLGrammarException: could not insert: [net.gaoxin.Computertable]
    Caused by: java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC]Invalid parameter binding(s).
解决:
 更新hibernate的版本到3.2.6 ,会产生错误1,然后把错误一解决就可以了。hibernate的bug啊。
错误3:
版本hibernate-3.1
错误:
Exception in thread "main" org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned
before calling save(): net.gaoxin.Computertable
原因 是在hbm.xml的    <generator class="assigned"/>
解决:手动设置id。
错误4:
Invalid parameter binding(s).
16:43:10,078 ERROR AbstractFlushingEventListener:299 - Could not synchronize database state with session
原因:<generator class="assigned"/>
解决:<generator class="nativ"/>
总之:hibernate-3.1有bug还是要升级到3.2,bug应该会少些。
错误5:
11:24:27,613 ERROR  JDBCExceptionReporter  ORA-01747: invalid user.table.column, table.column, or column specification
11:24:27,613 ERROR  AbstractFlushingEventListener  Could not synchronize database state with session
原因:可能是使用了数据库的关键词
解决:该列的定义。
错误6:
org.hibernate.exception.GenericJDBCException:   could   not   load   an   entity:   [mypack.Customer#3]  
 原因:意思是不能加载这个实体,没有主键=3   的这条记录

问题7:按照夏昕的教程《Hibernate 开发指南 v1.0》
使用Middlegen-Hibernate-r5 配置sqlserver2000数据库,然后运行ant的话会产生如下错误:
No <table> elements specified. Reading all tables. This might take a while...
build failed.
这个是因为在mssql中的属性名schema,catalog不应该去掉,应该有内容,
在mssql.xml中内容如下:
   <property name="database.schema"                value="dbo"/>
   <property name="database.catalog"               value="pubs"/>
在 build.xml中内容如下:
  schema="${database.schema}"
  catalog="${database.catalog}"
   注意在build.xml不要有空格。
错误8:
 Peopletable people=(Peopletable)session.load(Peopletable.class,4);
 这一句话应该是有错的啊,没有serializable =4的记录啊。是不是bug?但是报了下面的错误:  
   ERROR JDBCExceptionReporter:72 - [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]INSERT 语句与 COLUMN FOREIGN KEY
约束 'FK__computert__peopl__7A672E12' 冲突。该冲突发生于数据库 'pubs',表 'peopletable', column 'PID'。
   没有主键的值=4的记录。
   使用session.get可以解决上面的问题。
   session.load()的调用过程使用了内部缓存和二级缓存,然后再从数据中读取。
   而session.get()只使用了内部缓存,如果内部缓存没有数据将越过二级缓存,直接调用数据库读取数据。
   因此load函数可能在二级缓存中发生了问题,在使用session.load的时候使用监视器,发现people的内容是    
com.sun.jdi.InvocationException occurred invoking method.
   people的值都是null,但是在代码中用 if(people!=null)做判断不是空。
   printf的时候报错:No row with the given identifier
exists。说明你load了一个非代理对象或者是你load了一个代理对象但是后来又访问了这个对象。
   说明我们在print的时候才读取到那个实体类,没有print的时候只是一个代理类,不为空也就可以接受。
 
 错误9:
在报了错误8之后,我插入一个正确的记录,却发现在表中的主键的值应该是10的,现在是11了,也就是说刚才虽然由于错误8,提示没有成功
。但是那个独立的主键值还是生成了。
分析10:
目的:批量插入数据
        Transaction t=session.beginTransaction();
        Peopletable people=new Peopletable();
        int seed=100;
        for(int i=0;i<seed;i++){
            people.setPname(String.valueOf(new java.util.Random().nextInt(seed)));
            session.save(people);
            session.flush();
            t.commit(); //没有办法批量处理
        }
结果:Transaction not successfully
started,但是在数据库中插入了一条记录,这个不是我们想要的结果。百度了一下,发现是事务的原因。
将Transaction t=session.beginTransaction();
发到for循环中;没有报错,但是显示用事件查看器发现只插入了一条,其余执行update操作。
考虑批量处理有问题。百度之。
分析:首先程序有问题,在上面的过程中只创建了一个peopletable对象。每次都是更改那个对象中的值,这个是hibernate机理的作用,在
cache应该有缓存,而people对象现在是属于persistent状态,因此每次的save和submit都做update操作。
因此需要重新创建对象才会有用。
修改后的代码:
        Transaction t=session.beginTransaction();
        int seed=100;
        for(int i=0;i<seed;i++){
        Peopletable people=new Peopletable();
            people.setPname(String.valueOf(new java.util.Random().nextInt(seed)));
            session.save(people);
        }
            t.commit();
            现在ok了。
            但是可能在数据量大的时候,数据处理很慢。如果启用了second level cache的话,对批处理不利,因为每次执行insert/update操作,
            hibernate在transaction后不得不通告second level cache缓存这个记录,造成很慢,因此在batch操作的时候要禁用cache,
            并且每隔一批记录要执行session.flush()和clear()。
            一般数据是放在session中,只有在显式执行session.flush();或transaction.commit();操作之后才将数据保存到数据库中。
            一级缓存:session实例维护 ,内部缓存
            二级缓存:SessionFactory
            
            如果我们只想获取表中记录的一个字段,我们可以使用延迟加载的方式,即设置表对应的类的加载方式lazy="true".
            <class name="Computertable" table="computertable"        lazy="true"    >
             Computertable computer=(Computertable)session.load(Computertable.class, new Integer(2));    
            通过查看computertable的内存快照,我们可以发现computertable的属性都是null。
            原理是:hibernate的代理机制load的加载方式是通过代理类实现的。