{"release":{"tag":{"name":"v6.2.0","path":"/zycgit/dbvisitor/tags/v6.2.0","tree_path":"/zycgit/dbvisitor/tree/v6.2.0","message":"","commit":{"id":"02305a779bb26ffa612e5d7b7ad1fc84fcaa22e4","short_id":"02305a7","title":"[maven-release-plugin] prepare release v6.2.0","title_markdown":"[maven-release-plugin] prepare release v6.2.0","description":"","description_markdown":"","message":"[maven-release-plugin] prepare release v6.2.0\n","message_markdown":"[maven-release-plugin] prepare release v6.2.0","detail_path":"/zycgit/dbvisitor/commit/02305a779bb26ffa612e5d7b7ad1fc84fcaa22e4","commits_path":"/zycgit/dbvisitor/commits/02305a779bb26ffa612e5d7b7ad1fc84fcaa22e4","tree_path":"/zycgit/dbvisitor/tree/02305a779bb26ffa612e5d7b7ad1fc84fcaa22e4","author":{"name":"阿库玛","email":"zyc@hasor.net","username":"zycgit","user_path":"/zycgit","enterprise_user_path":null,"image_path":"https://foruda.gitee.com/avatar/1676895704409117540/10885_zycgit_1578914733.png!avatar30","is_gitee_user":true,"is_enterprise_user":null,"widget_url":""},"committer":{"name":"阿库玛","email":"zyc@hasor.net","username":"zycgit","user_path":"/zycgit","enterprise_user_path":null,"image_path":"https://foruda.gitee.com/avatar/1676895704409117540/10885_zycgit_1578914733.png!avatar30","is_gitee_user":true,"is_enterprise_user":null,"widget_url":""},"authored_date":"2025-11-22T15:46:50+08:00","committed_date":"2025-11-22T15:47:39+08:00","signature":null,"build_state":null},"archive_path":"/zycgit/dbvisitor/repository/archive/v6.2.0","signature":null},"operating":{"edit":false,"download":true,"destroy":false,"enterprise_forbid_zip":false},"release":{"title":"v6.2.0","path":"/zycgit/dbvisitor/releases/tag/v6.2.0","tag_path":"/zycgit/dbvisitor/tree/v6.2.0","project_id":17089389,"created_at":"2025-11-22T17:17:52+08:00","is_prerelease":false,"description":"```xml\r\n\u003Cdependency\u003E\r\n    \u003CgroupId\u003Enet.hasor\u003C/groupId\u003E\r\n    \u003CartifactId\u003Ejdbc-redis\u003C/artifactId\u003E\r\n    \u003Cversion\u003E6.2.0\u003C/version\u003E\r\n\u003C/dependency\u003E\r\n```\r\n\r\n## 影响范围\r\n\r\n- JdbcOperations 接口和 JdbcTemplate 类\r\n- dbvisitor-driver 项目\r\n- [jdbc-redis 驱动](https://www.dbvisitor.net/docs/guides/drivers/redis/usecase)\r\n\r\n## 更新内容\r\n\r\n- 新增\r\n  - 在 [Mapper 注解化](https://www.dbvisitor.net/docs/guides/core/annotation/about)、[Mapper File](https://www.dbvisitor.net/docs/guides/core/file/about)、[JdbcTemplate](https://www.dbvisitor.net/docs/guides/core/jdbc/about) 级别 API 上适配 jdbc-redis 驱动。\r\n  - 恢复 5.x 版本中的 BindTypeHandler 注解。\r\n  - XmlMapper 和 Query 注解，添加 resultTypeHandler 属性可以配置 TypeHandler\r\n  - TypeHandlerColumnRowMapper 可以将 TypeHandler 作为 RowMapper 使用。\r\n  - jdbc-redis 驱动新支持 PING、ECHO、SELECT、INFO 命令。\r\n  - 对于 DataGrip 和 IDEA 内嵌 Database 插件中使用 jdbc-redis 驱动连接 Redis 的支持。\r\n  - ResultSetExtractor 接口新增 PairsResultSetExtractor 实现，用于将结果集转换为键值对集合。\r\n  - JdbcOperations/JdbcTemplate 新增三个 queryForPairs 方法，可以将查询结果的每一行数据都转换为一个键值对。\r\n  - 新的 pairs 规则，用于遍历 Map/List/Array 等集合类型，并使用固定模版生成查询条件。\r\n- 变更\r\n  - queryForLong 方法返回值类型从 long 变更为 Long。\r\n  - queryForInt 方法返回值类型从 int 变更为 Integer。\r\n  - AbstractRowMapper 类的 getResultSetTypeHandler(ResultSet, int, Class) 方法移动到 TypeHandlerRegistry 类中。\r\n  - jdbc-redis 驱动在执行 MSET/MSETNX 命令时，返回值为添加的 Key 数量（此之前始终返回 1）\r\n  - jdbc-redis 驱动中涉及 StoreSet 类型的相关命令在同时输出 SCORE、ELEMENT 字段时，结果集字段顺序调整为 ELEMENT、SCORE。具体命令有：\r\n    - ZPOPMAX、ZPOPMIN、ZDIFF、ZINTER、ZRANDMEMBER、ZRANGE、ZRANGEBYSCORE、ZREVRANGE、ZREVRANGEBYSCORE、ZUNION、ZMPOP、BZMPOP、BZPOPMAX、BZPOPMIN、ZSCAN\r\n- 优化\r\n  - jdbc-redis 驱动支持 ResultSet 的 isLast 方法。\r\n  - 对于部分命令在执行完毕后通过使用 updateCount 方法返回执行结果，这些命令有：\r\n    - HKEYS、HDEL、DEL、SET、HSET、HMSET、HSETNX、EXPIRE、EXPIREAT、PEXPIRE、PEXPIREAT、PERSIST、RENAME、RENAMENX、\r\n      TOUCH、LINSERT、LPUSH、LPUSHX、RPUSH、RPUSHX、LREM、LSET、LTRIM、MOVE、SADD、SDIFFSTORE、SINTERSTORE、SMOVE、\r\n      SREM、SUNIONSTORE、ZDIFFSTORE、ZINTERSTORE、ZRANGESTORE、ZREM、ZREMRANGEBYLEX、ZREMRANGEBYRANK、ZREMRANGEBYSCORE、\r\n      ZUNIONSTORE、MSET、MSETNX、PSETEX、SETEX、SETNX、SETRANGE\r\n  - 对于 antlr4 的依赖，内嵌到 jdbc-redis 驱动 jar 包中，以减少外部依赖。\r\n  - 优化 jdbc-redis 驱动报错信息。\r\n  - dbvisitor-driver 中的 ConvertUtils 在处理 toBytes 时兼容 Byte[] 类型。\r\n- 修复\r\n  - jdbc-redis 驱动中 Statement 的 getLargeUpdateCount 和 getUpdateCount 没有结果集时会抛出 SQLException 的问题。保持和 jdbc 描述一致，在没有更多结果时返回 -1。\r\n  - jdbc-redis 驱动中 keys 命令无法执行的问题。\r\n\r\n\r\n## queryForPairs 作用\r\n\r\n```java title='使用 JdbcTemplate 查询键值对'\r\n// 查询用户表，将用户 ID 和用户名作为 Map 返回\r\nMap\u003CLong, String\u003E userMap = jdbc.queryForPairs(\"select uid, name from user\", Long.class, String.class);\r\n```\r\n\r\n## Redis 兼容如何使用?\r\n\r\n```java title='使用 JdbcTemplate 存取对象'\r\n// 1. 使用 BindTypeHandler 注释标记 UserInfo 类，指定使用 JsonTypeHandler 来处理该类的序列化和反序列化\r\n@BindTypeHandler(JsonTypeHandler.class)\r\npublic class UserInfo {\r\n    ...\r\n}\r\n\r\n// 2. 获取 Redis 连接，并构建 JdbcTemplate\r\nConnection redisConn = ...; // 参考文档：驱动适配器 \u003E JDBC Redis \u003E 如何使用\r\nJdbcTemplate jdbc = new JdbcTemplate(redisConn);\r\n\r\n// 3. 创建 UserInfo 对象，将其插入到 Redis 中，并使用 Json 序列化存储\r\nUserInfo user = new UserInfo();\r\nuser.setUid(\"j1111\");\r\nuser.setName(\"username\");\r\nuser.setLoginName(\"login_123\");\r\nuser.setLoginPassword(\"password\");\r\n\r\n// 4. 使用 user_ + uid 作为键名，arg0 为 user 对象\r\nint affected = jdbc.executeUpdate(\"set #{'user_' + arg0.uid} #{arg0}\", user);\r\n\r\n// 5. 从 Redis 中查询 UserInfo 对象，并进行反序列化\r\nUserInfo info = jdbc.queryForObject(\"get #{'user_' + arg0}\", \"j1111\", UserInfo.class);\r\n\r\n// 6. 删除 Redis 中的 UserInfo 对象\r\nint deleteCount = jdbc.executeUpdate(\"del #{'user_' + arg0.uid}\", user);\r\n```\r\n\r\n```java title='使用 Mapper 注解存取对象'\r\n// 1. 使用 BindTypeHandler 注释标记 UserInfo 类，指定使用 JsonTypeHandler 来处理该类的序列化和反序列化\r\n@BindTypeHandler(JsonTypeHandler.class)\r\npublic class UserInfo {\r\n    ...\r\n}\r\n\r\n@SimpleMapper()\r\npublic interface UserInfo1Mapper {\r\n  // 1. 生成参数化命令：set ? ? \r\n  // 2. 决定键名：     #{'user_' + info.uid} \r\n  // 3. 键的值：       #{info}\r\n  @Insert(\"set #{'user_' + info.uid} #{info}\")\r\n  int saveUser(@Param(\"info\") UserInfo info);\r\n\r\n  // 1. 生成参数化命令：get ?\r\n  // 2. 决定键名：     #{'user_' + uid}\r\n  @Query(\"get #{'user_' + uid}\")\r\n  UserInfo loadUser(@Param(\"uid\") String uid);\r\n\r\n  // 1. 生成参数化命令：del ?\r\n  // 2. 决定键名：     #{'user_' + uid}\r\n  @Delete(\"del #{'user_' + uid}\")\r\n  int deleteUser(@Param(\"uid\") String uid);\r\n}\r\n```\r\n\r\n```java title='使用 Mapper File 管理命令(Mapper)'\r\n@RefMapper(\"dbvisitor_scene/redis/user-mapper.xml\")\r\npublic interface UserInfoMapper {\r\n  int saveUser(@Param(\"info\") UserInfo info);\r\n\r\n  UserInfo loadUser1(@Param(\"uid\") String uid);\r\n\r\n  UserInfo loadUser2(@Param(\"uid\") String uid);\r\n\r\n  int deleteUser(@Param(\"uid\") String uid);\r\n}\r\n```\r\n\r\n```xml title='使用 Mapper File 管理命令(Mapper File)'\r\n\u003C?xml version=\"1.0\" encoding=\"UTF-8\"?\u003E\r\n\u003C!DOCTYPE mapper PUBLIC \"-//dbvisitor.net//DTD Mapper 1.0//EN\"\r\n        \"https://www.dbvisitor.net/schema/dbvisitor-mapper.dtd\"\u003E\r\n\u003Cmapper namespace=\"net.hasor.scene.UserInfoMapper\"\u003E\r\n  \u003Cinsert id=\"saveUser\"\u003E\r\n    set #{'user_' + uid} #{info}\r\n  \u003C/insert\u003E\r\n\r\n  \u003Cselect id=\"loadUser\" resultType=\"net.hasor.scene.UserInfo\"\u003E\r\n    get #{'user_' + uid}\r\n  \u003C/select\u003E\r\n\r\n  \u003Cdelete id=\"deleteUser\"\u003E\r\n    del #{'user_' + uid}\r\n  \u003C/delete\u003E\r\n\u003C/mapper\u003E\r\n```","author":{"name":"阿库玛","username":"zycgit","path":"/zycgit","avatar_url":"https://foruda.gitee.com/avatar/1676895704409117540/10885_zycgit_1578914733.png!avatar30"},"attach_files":[],"zip_download_url":"/zycgit/dbvisitor/releases/tag/v6.2.0.zip","tar_download_url":"/zycgit/dbvisitor/releases/tag/v6.2.0.tar.gz"}}}