org.apache.shiro.session.UnknownSessionException--jpa查询语句自动变成了delete

       项目一直用shiro做权限认证,今天碰到了一个问题,一个原本正常的项目,因为更新,忽然间登录不上了,看错误提示,显示如下:

Exception occurred during processing request: org.apache.shiro.session.UnknownSessionException: There is no session with id [67a486f5-f495-4359-af2c-143ff253b514]

可是程序更新的内容并不涉及shiro部分,百思不得其解。后来再往上翻,又发现了一个异常,定位异常,又发现了自己之前就百思不得其解的一个问题,我好好的一个查询语句,一到执行,就去执行一个delete语句,然后查询函数上没有标注事务,所以执行不成功,报异常。

2018-08-31 12:11:48,244 [http-8811-3] ERROR [jdbc.sqltiming] - 22. PreparedStatement.executeUpdate() FAILED! delete from mg_sys_user_role where user_id=7211 and role_id=66 
 {FAILED after 0 msec}
java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
...
2018-08-31 12:11:48,246 [http-8811-3] WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - SQL Error: 0, SQLState: S1009
2018-08-31 12:11:48,246 [http-8811-3] ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - Connection is read-only. Queries leading to data modification are not allowed
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement
...
Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed
...
org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
...
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly

然而,定位异常发生的地方,不过是一个再简单不过的查询函数,只不过用的是NativeQuery :

public Set<String> findPermission(String roleids) {
		try {
			Set<String> permissions = new HashSet<String>();
			String queryStr = "select permission from mg_sys_role_permission where role_id in ("
					+ roleids + ")";
			Query query = em.createNativeQuery(queryStr);
			List<String> perms = (List<String>) query.getResultList();
			permissions.addAll(perms);
			perms.clear();
			perms=null;
			return permissions;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

设置断点,每执行到这个函数的getResultList后,便报上述异常。

       之前也碰到过类似的问题,也是一个查找语句,也用的是NativeQuery,不晓得为何最终会衍生一个update语句,之前博客也有记录,解决的方案是将NativeQuery改为标准Query执行,便可以了。可这个方法在这里行不通了,因为我这里用到的表并未做实体映射,如果再改实体类,未免改动太多,再说,我之前程序登录一直正常,这次不正常,不应该是程序上改动的问题,肯定跟某些数据有关。

       这个函数的用意是根据用户对应的role_id(会是多个),查找用户对应的权限。于是核对数据库中数据,发现当前登录用户对应的role_id为三个,但在这个函数查找时,只查找两个,查另外一个role_id对应记录状态,发现这条记录状态为不可用,改为可用就不再出现这个问题。

************************

       上面的问题其实我没写完,当时写了一半去忙了,回来也忘记补上了,时至今日,当初想说什么也忘了。

        我今天又来续写这篇文章,实在是又碰到了这个问题。

        如果说前几次碰到的查询变update或delete还跟我正在查询的数据有关的话,这次我碰到的问题是,我查询的数据,压根儿和最终变成的update语句不沾边。

        在此之前百度的时候,看到一篇文章,提到持久化的问题,当时也没太在意具体说的是什么,但这次碰到的问题给我折腾的够呛,死活都找不出来原因。于是只好跟踪代码,当跟踪到org.hibernate.jpa.internal.QueryImpl中的beforeQuery函数中时,终于发现了问题所在:

private void beforeQuery() {
		final org.hibernate.Query query = getHibernateQuery();
		if ( !SQLQuery.class.isInstance( query ) ) {
			// this need only exists for native SQL queries, not JPQL or Criteria queries (both of which do
			// partial auto flushing already).
			return;
		}

		final SQLQuery sqlQuery = (SQLQuery) query;
		if ( sqlQuery.getSynchronizedQuerySpaces() != null && !sqlQuery.getSynchronizedQuerySpaces().isEmpty() ) {
			// The application defined query spaces on the Hibernate native SQLQuery which means the query will already
			// perform a partial flush according to the defined query spaces, no need to do a full flush.
			return;
		}

		// otherwise we need to flush.  the query itself is not required to execute in a transaction; if there is
		// no transaction, the flush would throw a TransactionRequiredException which would potentially break existing
		// apps, so we only do the flush if a transaction is in progress.
		if ( getEntityManager().isTransactionInProgress() ) {
			getEntityManager().flush();
		}
	}

这个函数里注解写的很明白,我的语句首先是nativeQuery,所以过滤掉第一个条件;第二个条件也不符合,就只能进第三个if,这里说的是“we only do the flush if a transaction is in progress”,既然只flush一个进行中的transaction,那我哪里有这个一个transaction呢?这时想起前面说持久化问题的文章,好像提到他解决的方案是把查询到的实体另行复制出来再改变其中的属性,受到启发,我也回看我在执行自己的查询语句前有没有查询出来实体度对其进行更改的,一查果然有,我先是查询出来一个实体,并对该实体某一属性赋值,然后执行的这个查询函数,再然后才又执行保存实体的动作。OK,我把对实体某一属性赋值这个操作放在查询之后,亦即查询出来的实体不做 更改,发现一切正常了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值