Hibernate jpa 自定义sql语句的解析(如:interval)

在Repository接口中定义的方法,有时候根据业务需要会自定义自己的sql语句,如@Query(“select * from table where create_time > (now() - (:overTime||‘min’)::::interval)”, nativeQuery = true),框架对这个sql语句的解析会把双 【::】 识别为单个【:】,对这个sql语句的解析放在这个ParameterParser.java类中,所以我们写成::::interval而不能写成::interval

以下为解析的核心代码:

// org.hibernate.engine.query.spi.ParameterParser.java
public static void parse(String sqlString, Recognizer recognizer) throws QueryException {
		final boolean hasMainOutputParameter = startsWithEscapeCallTemplate( sqlString );
		boolean foundMainOutputParam = false;

		final int stringLength = sqlString.length();

		boolean inSingleQuotes = false;
		boolean inDoubleQuotes = false;
		boolean inLineComment = false;
		boolean inDelimitedComment = false;

		for ( int indx = 0; indx < stringLength; indx++ ) {
			final char c = sqlString.charAt( indx );
			final boolean lastCharacter = indx == stringLength-1;

			// if we are "in" a certain context, check first for the end of that context
			if ( inSingleQuotes ) {
				recognizer.other( c );
				if ( '\'' == c ) {
					inSingleQuotes = false;
				}
			}
			else if ( inDoubleQuotes ) {
				recognizer.other( c );
				if ( '\"' == c ) {
					inDoubleQuotes = false;
				}
			}
			else if ( inDelimitedComment ) {
				recognizer.other( c );
				if ( !lastCharacter && '*' == c && '/' == sqlString.charAt( indx+1 ) ) {
					inDelimitedComment = false;
					recognizer.other( sqlString.charAt( indx+1 ) );
					indx++;
				}
			}
			else if ( inLineComment ) {
				recognizer.other( c );
				// see if the character ends the line
				if ( '\n' == c ) {
					inLineComment = false;
				}
				else if ( '\r' == c ) {
					inLineComment = false;
					if ( !lastCharacter && '\n' == sqlString.charAt( indx+1 ) ) {
						recognizer.other( sqlString.charAt( indx+1 ) );
						indx++;
					}
				}
			}
			// otherwise, see if we start such a context
			else if ( !lastCharacter && '/' == c && '*' == sqlString.charAt( indx+1 ) ) {
				inDelimitedComment = true;
				recognizer.other( c );
				recognizer.other( sqlString.charAt( indx+1 ) );
				indx++;
			}
			else if ( '-' == c ) {
				recognizer.other( c );
				if ( !lastCharacter && '-' == sqlString.charAt( indx+1 ) ) {
					inLineComment = true;
					recognizer.other( sqlString.charAt( indx+1 ) );
					indx++;
				}
			}
			else if ( '\"' == c ) {
				inDoubleQuotes = true;
				recognizer.other( c );
			}
			else if ( '\'' == c ) {
				inSingleQuotes = true;
				recognizer.other( c );
			}
			// special handling for backslash
			else if ( '\\' == c ) {
				// skip sending the backslash and instead send then next character, treating is as a literal
				recognizer.other( sqlString.charAt( ++indx ) );
			}
			// otherwise
			else {
				if ( c == ':' && indx < stringLength - 1 && sqlString.charAt( indx + 1 ) == ':') {
					// colon character has been escaped
					recognizer.other( c );
					indx++;
				}
				else if ( c == ':' ) {
					// named parameter
					final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS_BITSET, indx + 1 );
					final int chopLocation = right < 0 ? sqlString.length() : right;
					final String param = sqlString.substring( indx + 1, chopLocation );
					if ( param.isEmpty() ) {
						throw new QueryException(
								"Space is not allowed after parameter prefix ':' [" + sqlString + "]"
						);
					}
					recognizer.namedParameter( param, indx );
					indx = chopLocation - 1;
				}
				else if ( c == '?' ) {
					// could be either an ordinal or JPA-positional parameter
					if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
						// a peek ahead showed this as a JPA-positional parameter
						final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
						final int chopLocation = right < 0 ? sqlString.length() : right;
						final String param = sqlString.substring( indx + 1, chopLocation );
						// make sure this "name" is an integral
						try {
							recognizer.jpaPositionalParameter( Integer.parseInt( param ), indx );
							indx = chopLocation - 1;
						}
						catch( NumberFormatException e ) {
							throw new QueryException( "JPA-style positional param was not an integral ordinal" );
						}
					}
					else {
						if ( hasMainOutputParameter && !foundMainOutputParam ) {
							foundMainOutputParam = true;
							recognizer.outParameter( indx );
						}
						else {
							recognizer.ordinalParameter( indx );
						}
					}
				}
				else {
					recognizer.other( c );
				}
			}
		}

		recognizer.complete();
	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,您的问题是关于JPA自定义SQL的操作。 在JPA中,可以使用@Query注解来自定义SQL语句。下面是一些常见的JPA自定义SQL操作示例: 1. 查询操作 (1)查询返回单个结果 ``` @Query("select u from User u where u.email = ?1") User findByEmail(String email); ``` (2)查询返回多个结果 ``` @Query("select u from User u where u.age between ?1 and ?2") List<User> findByAgeBetween(int minAge, int maxAge); ``` 2. 更新操作 ``` @Modifying @Query("update User u set u.nickname = ?1 where u.id = ?2") int updateNicknameById(String nickname, Long id); ``` 需要注意的是,执行更新操作时需要使用@Modifying注解标识该方法是修改数据的操作。 3. 删除操作 ``` @Modifying @Query("delete from User u where u.id = ?1") void deleteById(Long id); ``` 同样需要使用@Modifying注解标识该方法是修改数据的操作。 在编写JPA自定义SQL时,需要注意以下几点: 1. JPA自定义SQL语句中的参数占位符使用?号表示,从1开始编号。 2. 如果需要传入多个参数,可以使用@Param注解来指定参数名。例如: ``` @Query("select u from User u where u.name = :name and u.age = :age") List<User> findByNameAndAge(@Param("name") String name, @Param("age") int age); ``` 3. 在执行JPA自定义SQL语句时,需要使用EntityManager对象的createNativeQuery方法或createQuery方法,具体使用哪种方法取决于自定义SQL语句的类型。 以上就是JPA自定义SQL的操作方法,希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值