我正在尝试实现一个Guice模块,它允许鳄梨酱使用SQLite作为后端。Guacamole项目有一个通用的JDBC基模块。这允许您用较少的代码实现特定数据存储的模块。大多数代码行都位于mapper XML文件中。该项目提供PostgreSQL和MySQL实现。
我把这个SQLite模块建立在MySQL模块的基础上。对于mapper文件,SQLite和MySQL非常相似,因此我不需要做任何更改。但是,当我尝试使用SQLite模块时,会得到以下错误:
### Error querying database. Cause: java.lang.ArrayIndexOutOfBoundsException: 2
### The error may exist in org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: SELECT guacamole_connection_group.connection_group_id, connection_group_name, parent_id, type, max_connections, max_connections_per_user, enable_session_affinity FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE guacamole_connection_group.connection_group_id IN ( ? ) AND user_id = ? AND permission = 'READ'; SELECT parent_id, guacamole_connection_group.connection_group_id FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE parent_id IN ( ? ) AND user_id = ? AND permission = 'READ'; SELECT parent_id, guacamole_connection.connection_id FROM guacamole_connection JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id WHERE parent_id IN ( ? ) AND user_id = ? AND permission = 'READ';
### Cause: java.lang.ArrayIndexOutOfBoundsException: 2问题似乎是两个参数被传递给查询,但每个参数都重复了三次。当MyBatis生成PreparedStatement时,它的作用就好像需要传入六个参数一样。
下面是它有一个问题的查询:
<!-- Select multiple connection groups by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
SELECT
guacamole_connection_group.connection_group_id,
connection_group_name,
parent_id,
type,
max_connections,
max_connections_per_user,
enable_session_affinity
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE guacamole_connection_group.connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT parent_id, guacamole_connection_group.connection_group_id
FROM guacamole_connection_group
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id
WHERE parent_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT parent_id, guacamole_connection.connection_id
FROM guacamole_connection
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id
WHERE parent_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>如果手动填充参数,则可以对SQLite数据库执行此操作。而且,MySQL版本运行良好。
到底是怎么回事?我能做些什么来调试这个呢?是MyBatis问题还是JDBC连接器的问题?
如果有帮助,您可以看到模块这里的代码。
下面是映射器与此查询相关的参数的方法。ConnectionGroup的完整映射类是这里和这里。我的SQLite模块的完整映射器XML是这里。
Collection<ModelType> selectReadable(@Param("user") UserModel user,
@Param("identifiers") Collection<String> identifiers);这就是ConnectionGroupResultMap的样子:
<resultMap id="ConnectionGroupResultMap" type="org.apache.guacamole.auth.jdbc.connectiongroup.ConnectionGroupModel" >
<!-- Connection group properties -->
<id column="connection_group_id" property="objectID" jdbcType="INTEGER"/>
<result column="connection_group_name" property="name" jdbcType="VARCHAR"/>
<result column="parent_id" property="parentIdentifier" jdbcType="INTEGER"/>
<result column="type" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.ConnectionGroup$Type"/>
<result column="max_connections" property="maxConnections" jdbcType="INTEGER"/>
<result column="max_connections_per_user" property="maxConnectionsPerUser" jdbcType="INTEGER"/>
<result column="enable_session_affinity" property="sessionAffinityEnabled" jdbcType="BOOLEAN"/>
<!-- Child connection groups -->
<collection property="connectionGroupIdentifiers" resultSet="childConnectionGroups" ofType="java.lang.String"
column="connection_group_id" foreignColumn="parent_id">
<result column="connection_group_id"/>
</collection>
<!-- Child connections -->
<collection property="connectionIdentifiers" resultSet="childConnections" ofType="java.lang.String"
column="connection_group_id" foreignColumn="parent_id">
<result column="connection_id"/>
</collection>
</resultMap>发布于 2017-10-13 16:18:05
大卫,
我知道这有点旧,但我也试图实现一个SQLite JDBC模块,并遇到了完全相同的问题。我已经找到了问题的来源,并在JDBC SQLite github页面上提交了一个问题:
https://github.com/xerial/sqlite-jdbc/issues/277
基本上,SQLite JDBC驱动程序根据准备好的语句的参数计数计算其数组大小之一。但是,在您提到的情况下,有多个SELECT语句接受相同的参数,因此数组需要是x*y (x =参数计数,y= select语句的数量),而不仅仅是参数的数量。当它试图准备语句时,它会击中参数计数之外的第一个位置,并生成此异常。
其他JDBC模块-- MySQL、PostgreSQL和Server,以及我正在处理的Oracle和H2 --似乎正确地处理了这种情况(嗯,Oracle是一个little...special.),但是SQLite驱动程序没有。
通过创建两个不同的结果映射,一个用于泛型select,另一个用于read,检查读取权限,然后将每个select查询分解到自己的SELECT块中,并调用结果映射中的集合,从而解决了这个问题。它远不如现有代码那么优雅,但它可以工作。
https://stackoverflow.com/questions/41969037
复制相似问题