测试方法都是把数据库中的表全部删除,通过运行测试案例时,让系统自动建立数据库。
ERROR com.jdon.persistence.hibernate.HibernateTemplate - exception while execute
org.hibernate.PropertyValueException: not-null property references a null or transient value: sample.model.User.address
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
...
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at com.jdon.persistence.hibernate.HibernateTemplate$12.execute(HibernateTemplate.java:259)
at com.jdon.persistence.hibernate.HibernateTemplate.doHibernate(HibernateTemplate.java:74)
at com.jdon.persistence.hibernate.HibernateTemplate.save(HibernateTemplate.java:257)
at com.jdon.persistence.hibernate.HibernateCRUDTemplate.insert(HibernateCRUDTemplate.java:68)
at com.jdon.persistence.DaoCRUDTemplate.insert(DaoCRUDTemplate.java:54)
at sample.service.UserServiceImp.create(UserServiceImp.java:55)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
这些都是Hibernate的错误:你数据表字段大概设置不为空,但是对应对象字段为空。
你现在已经进入深入调试,建议使用Eclipse断点调试跟踪程序,很难根据错误结果准确推断到错误原因的。
当前的数据库设置是, user 表中的 addressId 不允许为空。而问题恰恰出现在这里。
为什么在 junit 上的插入操作可以完成而在 msweb 上操作却不能完成呢?我们看一下这两者保存数据时的区别。
在 junit 上,数据保存时,是按一定的顺序保存的。
其顺序是,先保存 address 记录,然后把 address 记录设置给 user ,这时保存 user 的时候, address 的主键已经不是空了,所以保存可以正常进行。
而在 msweb 上操作时,数据的保存是让 hibernate 自己的内部机制来保存的。通过日志输出可以看到,hibernate 先保存 user 数据,其语句输出如下:
Hibernate: insert into nec_userb (name, deptid, addressid) values (?, ?, ?)
接着再保存 address、property 等数据:
Hibernate: insert into nec_address (name, id) values (?, ?)
Hibernate: insert into nec_property (name, value, id) values (?, ?, ?)
...
而我们看一下 User.hbm.xml 里相应 address 的配置:
...
...
当 hibernate 进行保存 user 数据的时候,由于 address 数据还没有保存,也就不存在 addressId ,而 user 表中的 addressId 又不允许为空,所以保存的时候,自然出错了。
因此更正的办法是,修改 User.hbm.xml 里相应 address 的配置为:
...
...
这时数据保存正确,msweb 运行时不再有错误。
当然更好的办法是在设置“双向一对多关联”,这个可以参考《深入浅出Hibernate》中的第4.4章节里的“双向一对多关联”(P157)。
在 UserService 接口中,有两个方法:
public abstract User getUser(Integer id);
public abstract User findUser(Integer id);
我看了一下,这两个方法在 UserServiceImp 实现时,就是 findUser 方法调用 getUser 方法来实现的。我搞不明白为什么要实现两个方法。能解释一下吗?
getXXX 与findXXX区别在于,get会被缓存拦截,而find不会。
在jivejdon3中,进行这两个区分则是为权限问题,get会检查权限,而find不会
User user = (User)session.get(User.class, 1);
又运行不下去了。后来我定义了一个类变量:
private Integer newUserId;
在语句
private HibernateTemplate ht;
后面,然后在方法 testCreate() 的语句
ht.save(user);
后添加了保存这个新用户的 id 语句:
newUserId = user.getId();
最后把方法 testGetUser() 中的读取用户信息的语句改为:
User user = (User)session.get(User.class, newUserId);
但测试时仍然出错,我把 newUserId 打印输出后发现它的值竟然是 null
于是再把类变量定义语句定义为静态变量:
private static Integer newUserId;
这时,测试终于不再出错。
测试程序中的原语句中的
session.get(User.class, "402881e614ed5dbd0114ed5dbf660004");
字符串,应该是在 banq 测试时,在他的机器上产生的新用户 id
我现在通过静态变量从 testCreate() 方法传入 testGetUser() 后,这个程序应该可以跑在任意的机器上了。
[该贴被lqixv于2008-03-11 12:41修改过]
public void testUpdate()
中有语句
User user = (User)ht.load(User.class, 0);
但这里不管后面的 id 是什么,junit测试总是绿条通过。但id对应的用户不存在时,控制台会抛出异常。
所以我觉得这个测试方法没有完成其测试的作用。应该还需要修改。
ERROR com.jdon.persistence.hibernate.HibernateTemplate - exception while execute
org.hibernate.SessionException: Session is closed!
...
似乎是 hibernate 的 session 开关不正常。但数据没有问题。我用的是 sql server 2000 数据库测试的,不知是不是这个的问题引起的错误。
banq,不好意思,我因为想用这个框架开发项目,所以可能有点太过于较真了 :P
23:45:28,280 INFO [STDOUT] 23:45:28,280 ERROR [PARSER] line 1:1: unexpected token: form
23:45:28,280 INFO [STDOUT] 23:45:28,280 ERROR [HibernateTemplate] exception while execute
java.lang.IllegalArgumentException: node to traverse cannot be null!
。。。。。。。。
ERROR [STDERR] java.lang.Exception: java.lang.IllegalArgumentException: node to traverse cannot be null!
23:45:28,280 ERROR [STDERR] at com.jdon.persistence.hibernate.HibernateTemplate.doHibernate(HibernateTemplate.java:86)
23:45:28,280 ERROR [STDERR] at com.jdon.persistence.hibernate.HibernateTemplate.find(HibernateTemplate.java:450)
23:45:28,280 ERROR [STDERR] at com.jdon.persistence.hibernate.HibernateTemplate.find(HibernateTemplate.java:442)
23:45:28,280 ERROR [STDERR] at org.mark.sample.dao.JdbcDaoImp.getDepts(JdbcDaoImp.java:40)
23:45:28,280 ERROR [STDERR] at org.mark.sample.service.UserServiceImp.getDepts(UserServiceImp.java:67)
23:45:28,280 ERROR [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
23:45:28,280 ERROR [STDERR] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
23:45:28,280 ERROR [STDERR] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
23:45:28,280 ERROR [STDERR] at java.lang.reflect.Method.invoke(Method.java:585)
23:45:28,280 ERROR [STDERR] at com.jdon.aop.reflection.MethodInvokerUtil.execute(MethodInvokerUtil.java:54)
23:45:28,280 ERROR [STDERR] at com.jdon.aop.reflection.ProxyMethodInvocation.methodInvoke(ProxyMethodInvocation.java:108)
23:45:28,280 ERROR [STDERR] at com.jdon.aop.reflection.ProxyMethodInvocation.proceed(ProxyMethodInvocation.java:76)
23:45:28,280 ERROR [STDERR] at com.jdon.aop.interceptor.SessionContextInterceptor.invoke(SessionContextInterceptor.java:76)
23:45:28,280 ERROR [STDERR] at com.jdon.aop.reflection.ProxyMethodInvocation.proceed(ProxyMethodInvocation.java:84)
23:45:28,280 ERROR [STDERR] at com.jdon.aop.interceptor.StatefulInterceptor.invoke(StatefulInterceptor.java:82)
23:45:28,296 ERROR [STDERR] at com.jdon.aop.reflection.ProxyMethodInvocation.proceed(ProxyMethodInvocation.java:84)
23:45:28,296 ERROR [STDERR] at com.jdon.aop.interceptor.PoolInterceptor.invoke(PoolInterceptor.java:91)
23:45:28,296 ERROR [STDERR] at com.jdon.aop.reflection.ProxyMethodInvocation.proceed(ProxyMethodInvocation.java:84)
23:45:28,296 ERROR [STDERR] at com.jdon.aop.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:58)
jdk?Hibernate?数据库?
1、方法:testCreate()中,在第93行语句
ht.save(user);
后必须加上关闭 session 的语句,否则如果单独测试这个方法,数据是不会更新保存到数据库中。
2、测试“lazy櫴加载”的方法:testGetUser()中,必须把第108行语句:
session.close();
改为:
ht.getSessionProvider().closeSession();
否则后面所有的方法测试都会抛出 session 已关闭的异常。
同时,可以把已被注释掉的第104、105、106行语句
// User user = (User)session.get(User.class, 402881e614ed5dbd0114ed5dbf660004");
// System.out.print(" ++++++++deptname=" + user.getDept().getName());
//System.out.print(" ++++++++address=" + user.getAddress().getName());
的注释去掉,并把第104行改为:
User user = (User)session.get(User.class, 1);
这样,这个方法就可以正常运行。
3、方法testUpdate()在删除属性语句:
properties.remove(deleteprop);//删除操作
的后面,应该加上删除属性的操作语句:
ht.delete(deleteprop);
这样才能真正从数据库删除这条属性记录。否则的话,hibernate 只把这个属性对应于数据库中的记录的 userid 清为 null,而不会删除这条记录。原因是,虽然在 User.hbm.xml 中,定义了
呵呵,帮 banq 改点小 bug ,也算是对 jdon 的支持吧。
部署在 jboss 后,如果不手工删除其中冲突的一些日志包,如 log4j.jar ,那程序可以正常运行,但日志输出会有错误。
[该贴被lqixv于2008-03-18 18:10修改过]