001/** 002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package com.mybatisflex.core.row; 017 018import com.mybatisflex.core.FlexConsts; 019import com.mybatisflex.core.exception.FlexExceptions; 020import com.mybatisflex.core.paginate.Page; 021import com.mybatisflex.core.provider.RowSqlProvider; 022import com.mybatisflex.core.query.CPI; 023import com.mybatisflex.core.query.QueryColumn; 024import com.mybatisflex.core.query.QueryWrapper; 025import com.mybatisflex.core.util.StringUtil; 026import org.apache.ibatis.annotations.*; 027import org.apache.ibatis.exceptions.TooManyResultsException; 028 029import java.util.Collection; 030import java.util.List; 031import java.util.Map; 032 033 034public interface RowMapper { 035 036 //////insert ////// 037 038 /** 039 * 插入 row 到数据表 040 * 041 * @param tableName 表名 042 * @param row 数据内容,当设置有主键时,主键会自动填充 043 * @return 执行影响的行数 044 * @see RowSqlProvider#insert(Map) 045 */ 046 @InsertProvider(value = RowSqlProvider.class, method = "insert") 047 int insert(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.ROW) Row row); 048 049 050 /** 051 * 执行 insert sql 语句 052 * 053 * @param sql insert sql 语句 054 * @param args 参数 055 * @return 执行影响的行数 056 * @see Db#insertBySql(String, Object...) 057 */ 058 @InsertProvider(value = RowSqlProvider.class, method = RowSqlProvider.METHOD_RAW_SQL) 059 int insertBySql(@Param(FlexConsts.SQL) String sql, @Param(FlexConsts.SQL_ARGS) Object... args); 060 061 062 /** 063 * 批量插入 rows 到数据表 064 * <p> 065 * 注意,批量插入中,只会根据第一条 row 数据来构建 Sql 插入字段,若每条数据字段不一致,可能造成个别字段无法插入的情况 066 * 067 * @param tableName 表名 068 * @param rows 数据内容,当设置有主键时,主键会自动填充 069 * @return 执行影响的行数 070 * @see RowSqlProvider#insertBatchWithFirstRowColumns(Map) 071 */ 072 @InsertProvider(value = RowSqlProvider.class, method = "insertBatchWithFirstRowColumns") 073 int insertBatchWithFirstRowColumns(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.ROWS) List<Row> rows); 074 075 076 /////// delete ///// 077 078 /** 079 * 执行 delete sql 语言 080 * 081 * @param sql delete sql 语句 082 * @param args 参数 083 * @return 执行影响的行数 084 */ 085 @DeleteProvider(value = RowSqlProvider.class, method = RowSqlProvider.METHOD_RAW_SQL) 086 int deleteBySql(@Param(FlexConsts.SQL) String sql, @Param(FlexConsts.SQL_ARGS) Object... args); 087 088 /** 089 * 根据 id 删除数据 090 * 091 * @param tableName 表名 092 * @param row id 和 值的数据,可以通过 {@link Row#ofKey(String, Object)} 来创建 093 * @return 执行影响的行数 094 */ 095 default int deleteById(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.ROW) Row row) { 096 return deleteById(tableName, StringUtil.join(",", row.obtainsPrimaryKeyStrings()), row.obtainsPrimaryValues()); 097 } 098 099 /** 100 * 根据 id 删除数据 101 * 102 * @param tableName 表名 103 * @param primaryKey 主键,多个主键用英文逗号隔开 104 * @param id 数据,多个主键时传入数组,例如 new Object[]{1,2} 105 * @return 执行影响的行数 106 * @see RowSqlProvider#deleteById(Map) 107 */ 108 @DeleteProvider(value = RowSqlProvider.class, method = "deleteById") 109 int deleteById(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.PRIMARY_KEY) String primaryKey, @Param(FlexConsts.PRIMARY_VALUE) Object id); 110 111 112 /** 113 * 根据 多个 id 值删除多条数据 114 * 115 * @param tableName 表名 116 * @param primaryKey 主键 117 * @param ids id 的集合 118 * @return 执行影响的行数 119 * @see RowSqlProvider#deleteBatchByIds(Map) 120 */ 121 @DeleteProvider(value = RowSqlProvider.class, method = "deleteBatchByIds") 122 int deleteBatchByIds(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.PRIMARY_KEY) String primaryKey, @Param(FlexConsts.PRIMARY_VALUE) Collection<?> ids); 123 124 125 /** 126 * 根据 queryWrapper 构建 where 条件来删除数据 127 * 128 * @param tableName 表名 129 * @param queryWrapper queryWrapper 130 * @return 执行影响的行数 131 * @see RowSqlProvider#deleteByQuery(Map) 132 */ 133 @DeleteProvider(value = RowSqlProvider.class, method = "deleteByQuery") 134 int deleteByQuery(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); 135 136 137 ////////update //// 138 139 /** 140 * 执行 update sql 语句 141 * 142 * @param sql sql 语句 143 * @param args 参数内容 144 * @return 执行影响的行数 145 */ 146 @UpdateProvider(value = RowSqlProvider.class, method = RowSqlProvider.METHOD_RAW_SQL) 147 int updateBySql(@Param(FlexConsts.SQL) String sql, @Param(FlexConsts.SQL_ARGS) Object... args); 148 149 150 /** 151 * 根据主键来更新数据 152 * 153 * @param tableName 表名 154 * @param row 数据,其必须包含主键数据列名和值 155 * @return 执行影响的行数 156 * @see RowSqlProvider#updateById(Map) 157 */ 158 @UpdateProvider(value = RowSqlProvider.class, method = "updateById") 159 int updateById(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.ROW) Row row); 160 161 162 /** 163 * 根据 queryWrapper 来构建 where 条件更新数据 164 * 165 * @param tableName 表名 166 * @param data 更新数据 167 * @param queryWrapper queryWrapper 168 * @return 执行影响的行数 169 * @see RowSqlProvider#updateByQuery(Map) 170 */ 171 @UpdateProvider(value = RowSqlProvider.class, method = "updateByQuery") 172 int updateByQuery(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.ROW) Row data, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); 173 174 175 /** 176 * 根据主键来批量更新数据 177 * 注意: 178 * 1、此方法需要在 mysql 等链接配置需要开启 allowMultiQueries=true 179 * 2、更新成功返回的结果也可能为 0 180 * 181 * @param tableName 表名 182 * @param rows 数据,其必须包含主键数据列名和值 183 * @return 执行影响的行数 184 * @see RowSqlProvider#updateBatchById(Map) 185 */ 186 @UpdateProvider(value = RowSqlProvider.class, method = "updateBatchById") 187 int updateBatchById(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.ROWS) List<Row> rows); 188 189 ///////select ///// 190 191 /** 192 * 通过原生 SQL 查询 1 条数据,要求数据必须返回 1 条内容,否则会报错 193 * 194 * @param sql select sql 语句 195 * @param args 参数 196 * @return 返回一条数据 197 */ 198 default Row selectOneBySql(String sql, Object... args) { 199 List<Row> rows = selectListBySql(sql, args); 200 if (rows == null || rows.isEmpty()) { 201 return null; 202 } else if (rows.size() == 1) { 203 return rows.get(0); 204 } else { 205 /** 当返回多条数据时,抛出异常, 保持和 Mybatis DefaultSqlSession 的统一逻辑, 206 * see: {@link org.apache.ibatis.session.defaults.DefaultSqlSession#selectOne(String, Object)} **/ 207 throw new TooManyResultsException("Expected one result (or null) to be returned by selectOneBySql(), but found: " + rows.size()); 208 } 209 } 210 211 /** 212 * 通过主键来查询数据 213 * 214 * @param tableName 表名 215 * @param row 主键和ID的描述,通过 {@link Row#ofKey(String, Object)} 来进行构建 216 * @return 返回一条数据,或者 null 217 */ 218 default Row selectOneById(String tableName, Row row) { 219 return selectOneById(tableName, StringUtil.join(",", row.obtainsPrimaryKeyStrings()), row.obtainsPrimaryValues()); 220 } 221 222 223 /** 224 * 根据主键来查询数据 225 * 226 * @param tableName 表名 227 * @param primaryKey 主键 228 * @param id id 值 229 * @return row or null 230 * @see RowSqlProvider#selectOneById(Map) 231 */ 232 @SelectProvider(value = RowSqlProvider.class, method = "selectOneById") 233 Row selectOneById(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.PRIMARY_KEY) String primaryKey, @Param(FlexConsts.PRIMARY_VALUE) Object id); 234 235 236 /** 237 * 根据 queryWrapper 来查询 1 条数据 238 * 239 * @param tableName 表名 240 * @param queryWrapper queryWrapper 241 * @return row or null 242 */ 243 default Row selectOneByQuery(String tableName, QueryWrapper queryWrapper) { 244 List<Row> rows = selectListByQuery(tableName, queryWrapper.limit(1)); 245 if (rows == null || rows.isEmpty()) { 246 return null; 247 } else { 248 return rows.get(0); 249 } 250 } 251 252 /** 253 * 通过自定义 sql 来查询一个 Row 列表 254 * 255 * @param sql 自定义的 sql 256 * @param args sql 参数 257 * @return row 列表 258 */ 259 @SelectProvider(value = RowSqlProvider.class, method = RowSqlProvider.METHOD_RAW_SQL) 260 List<Row> selectListBySql(@Param(FlexConsts.SQL) String sql, @Param(FlexConsts.SQL_ARGS) Object... args); 261 262 263 /** 264 * 根据 queryWrapper 来查询一个 row 列表 265 * 266 * @param tableName 表名 267 * @param queryWrapper queryWrapper 268 * @return row 列表 269 * @see RowSqlProvider#selectListByQuery(Map) 270 */ 271 @SelectProvider(value = RowSqlProvider.class, method = "selectListByQuery") 272 List<Row> selectListByQuery(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); 273 274 275 /** 276 * 查询某张表的全部数据 277 * 278 * @param tableName 表名 279 * @return row 列表 280 */ 281 default List<Row> selectAll(@Param(FlexConsts.TABLE_NAME) String tableName) { 282 return selectListByQuery(tableName, QueryWrapper.create()); 283 } 284 285 /** 286 * 通过 sql 查询某一个数据,sql 执行的结果应该只有 1 行 1 列 287 * 若返回有多列,则只取第一列的值,若有多行,则会出现 TooManyResultsException 错误 288 * 289 * @param sql sql 290 * @param args sql 参数 291 * @return object 292 */ 293 @SelectProvider(value = RowSqlProvider.class, method = RowSqlProvider.METHOD_RAW_SQL) 294 Object selectObject(@Param(FlexConsts.SQL) String sql, @Param(FlexConsts.SQL_ARGS) Object... args); 295 296 297 /** 298 * 通过 sql 查询多行数据,sql 执行的结果应该只有 1 列 299 * 300 * @param sql sql 语句 301 * @param args sql 参数 302 * @return object list 303 */ 304 @SelectProvider(value = RowSqlProvider.class, method = RowSqlProvider.METHOD_RAW_SQL) 305 List<Object> selectObjectList(@Param(FlexConsts.SQL) String sql, @Param(FlexConsts.SQL_ARGS) Object... args); 306 307 308 /** 309 * 查询数据,一般用于 select count(*)... 的语言,也可用于执行的结果只有一个数值的其他 sql 310 * 311 * @param sql sql 语句 312 * @param args sql 参数 313 * @return 返回数据 314 */ 315 default long selectCount(String sql, Object... args) { 316 Object object = selectObject(sql, args); 317 if (object == null) { 318 return 0; 319 } else if (object instanceof Number) { 320 return ((Number) object).longValue(); 321 } else { 322 throw FlexExceptions.wrap("selectCount error, Can not get number value for sql: %s", sql); 323 } 324 } 325 326 327 /** 328 * 根据 queryWrapper 来查询数量 329 * 330 * @param tableName 表名 331 * @param queryWrapper queryWrapper 332 * @return 数量 333 * @see RowSqlProvider#selectCountByQuery(Map) 334 */ 335 @SelectProvider(value = RowSqlProvider.class, method = "selectCountByQuery") 336 long selectCountByQuery(@Param(FlexConsts.TABLE_NAME) String tableName, @Param(FlexConsts.QUERY) QueryWrapper queryWrapper); 337 338 339 /** 340 * 分页查询数据 341 * 342 * @param tableName 表名 343 * @param page page 封装类 344 * @param queryWrapper 条件 345 * @return 346 */ 347 default Page<Row> paginate(String tableName, Page<Row> page, QueryWrapper queryWrapper) { 348 349 List<QueryColumn> groupByColumns = CPI.getGroupByColumns(queryWrapper); 350 351 // 只有 totalRow 小于 0 的时候才会去查询总量 352 // 这样方便用户做总数缓存,而非每次都要去查询总量 353 // 一般的分页场景中,只有第一页的时候有必要去查询总量,第二页以后是不需要的 354 if (page.getTotalRow() < 0) { 355 356 //清除group by 去查询数据 357 CPI.setGroupByColumns(queryWrapper, null); 358 long count = selectCountByQuery(tableName, queryWrapper); 359 page.setTotalRow(count); 360 } 361 362 if (page.getTotalRow() == 0 || page.getPageNumber() > page.getTotalPage()) { 363 return page; 364 } 365 366 //恢复数量查询清除的 groupBy 367 CPI.setGroupByColumns(queryWrapper, groupByColumns); 368 int offset = page.getPageSize() * (page.getPageNumber() - 1); 369 queryWrapper.limit(offset, page.getPageSize()); 370 List<Row> records = selectListByQuery(tableName, queryWrapper); 371 page.setRecords(records); 372 return page; 373 } 374 375 376}