hibernate 使用面向对象的思想,
将数据表抽象为类,
数据记录抽象为对象,
比较完美的减少了对sql的显式使用,用起来也是比较方便,通过操作对象就能增删改数据库记录.
优点:
- 单表查询简单,
- crud完美移植到方法的调用,
- 对开发人员sql的要求比较低
缺点: - 多表查询比较麻烦,
- 映射比较繁琐
- 字段完全查出,性能有消耗
这些优缺点只是个人理解.
接下来才是本文重点:
主角登场–遇到的问题
起初学习hibernate也没有考虑hibernate 对象的状态问题:
最近项目是用到hibernate开发,出现一个奇妙的错误:
博主在代码中执行查询,查询出数据库的一条记录,使用的是与数据表有着映射关系的Pojo类.
java伪代码如下:
@Service
class myService{
@Transactional
Map<String,Object> getById(Integer pojoId){
Pojo object=PojoDao.get(pojoId);
if(object!=null){
object.setRemark("object from database");
}
Map<String,Object> result=new HashMap<>();
result.put("data",object);
return object;
}
}
bug 登场
实际测试接口调用此方法,发现是500错误,并且报错是字段被截断的错误,心想,显而易见是使用的select,如果是insert或者是update还能说的过去,仅仅是select,爆出这个错误,真是令人费解.
接着打断点,一直执行到 return object都是没有排除异常的,return之后就是@Transactional的地盘了,提交事务,抛出异常,此时控制台输出了一条sql
update Pojo set = … where id=**
出来了一条update的sql,接着是一条字段被截断的错误
想想,应该是那个setRemark 方法调用导致的问题,很久以前马马虎虎看过hibertnate的三态,由于没有遇到问题,只是似懂非懂的一扫而过,这下遇到问题,就往这个方向考虑.
快刀登场
将setReark()的那一行代码注释掉,启动测试,接口200,没有问题,进一步证实了猜测.
提交事务会引起对象同步到数据库.
具体的还是来理解一下hiberbate的三态吧:
理论支持
三态=临时+持久+游离 1
临时(Transient): new 操作创建,并且还没和session相关联. 使用session执行必要的sql可以将其转换为持久态
持久态(Peristent):对象和数据库的一条记录存在映射,对象拥有持久化标识.hibernate会检测到持久化对象的所有改动,并且在当前操作单元执行完毕,自动将当前的新的状态(包含对象属性值)
同步到数据库.
游离态(Detached:与持久对象关联的session关闭后,对象变为游离态.对游离态的引用依然有效,游离对象如果余新的session关联,会再次转变为持久态,处于游离状态期间,该对象发生变化,也能够同步到数据库
三态的理解来自此博客
回到此问题,pojo对象应该还是处于持久态,人为修改,自动提交事务,导致将修改同步到数据库,以至于出现此错误.
三态问题还需要仔细研究. ↩︎