hibernate的save 以及 flush 之坑

最近在用spring项目做接口开发  数据库用的是Hibernate4.0。 在做业务的时候有一个非常奇怪的错误,

[ERROR][SqlExceptionHelper] ORA-00942: 表或视图不存在

[2021-03-26 12:07:55,753][ERROR][BatchingBatch] HHH000315: Exception executing batch [could not execute batch]
[2021-03-26 12:07:55,754][ERROR][BaseDao] oracle error query: sql: select nvl(b.xmlx,0) as XMLX,b.FYGB as FYGB,a.FYDJ as YLDJ,1 as YLSL ,1 as ZFBL,a.FYDJ  as HJJE,1 as DZBL  from GY_YLMX a,GY_YLSF b  where a.JGID=:JGID and a.FYXH=:FYXH and a.FYXH=b.FYXH,parameters:{FYXH=13764, JGID=4}
org.hibernate.HibernateException: org.hibernate.exception.SQLGrammarException: could not execute batch

错误是由于我在公共调用方法里面捕获了错误信息,把错误时候的日志打印出来

public List<Map<String, Object>>  doSqlQuery(String sql,Map<String, Object> parameters) 
			throws PersistentDataOperationException{
		Session session =getCurrentSession();
		List<Map<String, Object>> l =null;
		try {
			l=getList(sql, session, parameters);
		} catch (HibernateException e) {
			logger.error("oracle error query:"+" sql:"+sql+",parameters:"+parameters,e);
			throw	new PersistentDataOperationException(e);
		}
		return l;
	}

注意这里:

catch (HibernateException e) {
            logger.error("oracle error query:"+" sql:"+sql+",parameters:"+parameters,e);
            throw    new PersistentDataOperationException(e);
        }

    重点来了:GY_YLMX a,GY_YLSF b   这两张表在数据库里面都有着的,一开始以为是多数据源切换的问题,还停留在老的数据源那边 但是把表换成另外一个数据源里面的表依旧报这个错,说明不是。于是又怀疑是上面的save保存问题,由于对Hibernate的save保存机制不熟悉但是上面日志没报错说是save那几张表导致的错误(如果有错应该都是捕捉到了) 。   查的怀疑人生了。

    后面把日志级别从error调成debug,让更多的日志打印出来。发现报错还真在save(Object)这里。 为了方便理解,我把部分代码贴上来:

phiszzDao.save(ghmx);
phiszzDao.saveObj(jzls);
phiszzDao.saveObj(bcjl);//注意这个bcjl表在当前数据源中的表是不存在的
phiszzDao.saveObj(brzd);
phiszzDao.saveObj(yj01);
StringBuffer querySFXM = new StringBuffer(" select nvl(b.xmlx,0) as XMLX,b.FYGB as FYGB,a.FYDJ as YLDJ,1 as YLSL ,1 as ZFBL,a.FYDJ  as HJJE,1 as DZBL ")
		.append(" from GY_YLMX a,GY_YLSF b " )
		.append(" where a.JGID=:JGID and a.FYXH=:FYXH and a.FYXH=b.FYXH");
Map<String, Object> FYXXMap = phiszzDao.doMapQuery(querySFXM.toString(), fyxxparameters);

在debug日志里面显示的是phiszzDao.saveObj(bcjl); 这里报表或视图不存在,但是在日志级别为error由于没有输出详细信息报错的问题是在queryDFXM这条语句这里。

思考:

  1、为什么save(bcjl) 报错后还可以走下去

   2、为什么会在queryMap这个查询方法里面才会抛出。

为了便于理解 我把查询方法贴在下面:

/**
	 * 查询单一返回主键
	 * @param sql
	 * @param parameters
	 * @return
	 * @throws PersistentDataOperationException
	 */
	public Map<String, Object> doMapQuery(String sql,Map<String, Object> parameters) 
			throws PersistentDataOperationException{
		Session session =getCurrentSession();
		Map<String, Object> l =null;
		try {
			l=doLoad(sql, session, parameters);
		} catch (HibernateException e) {
			logger.error("oracle error query:"+" sql:"+sql+",parameters:"+parameters,e);
			throw	new PersistentDataOperationException(e);
		}
		return l;
	}

	/**
	 * 查询单一主键 返回
	 * @param sql
	 * @param session
	 * @param parameters
	 * @return
	 * @throws HibernateException
	 */
	public Map<String, Object> doLoad(String sql,Session session ,Map<String, Object> parameters)
	throws HibernateException{
		Map<String, Object> m=null;
		try {
				SQLQuery query = session.createSQLQuery(sql);
				if (parameters != null && !parameters.isEmpty()) {
					for (String key : parameters.keySet()) {
						if (key.equals("first")) {
							query.setFirstResult((Integer) parameters.get(key));
						} else if (key.equals("max")) {
							query.setMaxResults((Integer) parameters.get(key));
						} else {
							setParameter(query, key, parameters.get(key));
						}
					}
				}
				if (sql.indexOf(" as ") > 0) {
					query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
				}
				m=(Map<String, Object>) query.uniqueResult();
				session.flush();
		} catch (HibernateException e) {
			throw new HibernateException(e);
		}
			return m;
	}

可能细心的朋友已经看出猫腻了,在query里面多了一个session.flush()方法。

    那session的flush方法去做了什么呢,跟上面的save报错为什么提示在查询这里有没有关系呢?由于这个方法是事务控制   ,flush方法的主要作用就是清理缓存,强制数据库与Hibernate缓存同步,以保证数据的一致性。它 的主要动作就是向数据库发送一系列的sql语句,并执行这些sql语句,但是不会向数据库提交

   注意上面的加粗字体:这时候才会真正去执行sql 由于执行的时候 会把上面的save方法都先预先执行一遍(注意这里只是执行 还并未向数据库发起提交!)如果有错误就会抛出错误,所以就解释的通上面为什么会在查询 doSqlQuery方法是提示表或视图不存在!!!其实说的是save 里面的bcjl这张表不存在而并非是GY_YLMX a,GY_YLSF b 这两张表不存在。

   那什么时候去提交呢?由于上面方法是事务控制的,要到整个方法走完才会提交到数据库。而commit方法则会首先调用flush方法,然后提交 事务。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值