|
1 | 1 | ## Changelog
|
2 | 2 |
|
| 3 | +### 5.2.0 - 2020-07-26 |
| 4 | + |
| 5 | +- Upgrading jsqlparser to version 3.2 makes sql parsing better and supports sqlserver better. |
| 6 | + |
| 7 | +- Modify the substitution regularity in sqlserver mode, and now allow spaces in `with( nolock)` brackets. |
| 8 | + |
| 9 | +- Solving the bugs in reasonable, pageSizeZero and offset usage, the meaning and result are more consistent now. |
| 10 | + |
| 11 | +- In the process of splicing paging SQL, a new line character is added to avoid invalid paging part caused by comments in the original SQL. |
| 12 | + |
| 13 | +- ROW_ID alias in Oracle and Db2 is changed to PAGEHELPER_ROW_ID to avoid conflict with common names. |
| 14 | + |
| 15 | +- Solve the special problem when using other interceptors with a single parameter ProviderSql (support mybatis 3.4.0+) [by Luo Zhenyu](https://github.com/luozhenyu) |
| 16 | + |
| 17 | +- Automatic identification of clickhouse is supported, and paging is performed by MySQL. |
| 18 | + |
| 19 | +- Change startRow, endRow type from int to long. |
| 20 | + |
| 21 | +- Page adds a `public <T> PageInfo<T> toPageInfo(Function<E, T> function)` method to convert the data in the query results. |
| 22 | + |
| 23 | +- Refer to `Oracle9iDialect` provided by pr#476, which is also a paging method used before. You can test and select the appropriate paging method by yourself. |
| 24 | + |
| 25 | + At present, there are two kinds of Oracle pagination as follows: |
| 26 | + ```sql |
| 27 | + -- OracleDialect outer control range |
| 28 | + WHERE ROW_ID <= ? AND ROW_ID > ? |
| 29 | + -- Oracle9iDialect's internal and external control scope respectively |
| 30 | + TMP_PAGE WHERE ROWNUM <= ? ) WHERE ROW_ID > ? |
| 31 | + ``` |
| 32 | +- Adding `BoundSqlInterceptor` of PageHelper plug-in can process or simply read SQL in three stages, adding `boundSqlInterceptors`, and configuring multiple implementation class names that implement `BoundSqlInterceptor` interface, separated by English commas. PageHelper can also be set for this paging through a `PageHelper.startPage(x,x).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`. |
| 33 | + |
| 34 | +The biggest change of this update is the addition of `BoundSqlInterceptor`, which can intercept the SQL(BoundSQL object) of paging processing at runtime: |
| 35 | + |
| 36 | +```java |
| 37 | +/** |
| 38 | + * BoundSql 处理器 |
| 39 | + */ |
| 40 | +public interface BoundSqlInterceptor { |
| 41 | + /** |
| 42 | + * boundsql 处理 |
| 43 | + * |
| 44 | + * @param type 类型 |
| 45 | + * @param boundSql 当前类型的 boundSql |
| 46 | + * @param cacheKey 缓存 key |
| 47 | + * @param chain 处理器链,通过 chain.doBoundSql 方法继续执行后续方法,也可以直接返回 boundSql 终止后续方法的执行 |
| 48 | + * @return 允许修改 boundSql 并返回修改后的 |
| 49 | + */ |
| 50 | + BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain); |
| 51 | + |
| 52 | + enum Type { |
| 53 | + /** |
| 54 | + * 原始SQL,分页插件执行前,先执行这个类型 |
| 55 | + */ |
| 56 | + ORIGINAL, |
| 57 | + /** |
| 58 | + * count SQL,第二个执行这里 |
| 59 | + */ |
| 60 | + COUNT_SQL, |
| 61 | + /** |
| 62 | + * 分页 SQL,最后执行这里 |
| 63 | + */ |
| 64 | + PAGE_SQL |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * 处理器链,可以控制是否继续执行 |
| 69 | + */ |
| 70 | + interface Chain { |
| 71 | + Chain DO_NOTHING = new Chain() { |
| 72 | + @Override |
| 73 | + public BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey) { |
| 74 | + return boundSql; |
| 75 | + } |
| 76 | + }; |
| 77 | + |
| 78 | + BoundSql doBoundSql(Type type, BoundSql boundSql, CacheKey cacheKey); |
| 79 | + } |
| 80 | +} |
| 81 | +``` |
| 82 | + |
| 83 | +The interface includes boundSql interface method, Type enumeration, and the definition of Chain interface, and you don't need to consider Chain when you implement it yourself. |
| 84 | + |
| 85 | +The interceptor is configured by `boundSqlInterceptors` parameter, and there are three situations when executing: |
| 86 | + |
| 87 | +1. Regardless of whether the currently executed SQL will be paged or not, interceptor methods of `Type.ORIGINAL` will be executed. |
| 88 | + |
| 89 | +2. When the paging method is called, the interceptor will continue to execute the interceptor method of `Type.COUNT_SQL`, which will only be executed when paging is executed and count query is specified. |
| 90 | + |
| 91 | +3. When paging method is called, if count > 0, interceptor method of `Type.PAGE_SQL` will be executed, which will only be executed when paging is executed. |
| 92 | + |
| 93 | +>With the specified parameter `PageHelper.startPage(1, Integer.MAX_VALUE, false).boundSqlInterceptor(BoundSqlInterceptor boundSqlInterceptor)`, it can also play the role of not paging and count query, but can execute interceptor method of `Type.ORIGINAL`. |
| 94 | +
|
| 95 | +If you want to get the page before SQL execution, you only need to pay attention to `Type.ORIGINAL`, and the other two are before count execution and before page execution (when count=0, the page method will not be executed and will not be executed here). |
| 96 | + |
| 97 | +Take the test code as an example: |
| 98 | + |
| 99 | +```java |
| 100 | +public class TestBoundSqlInterceptor implements BoundSqlInterceptor { |
| 101 | + public static final String COMMENT = "\n /* TestBoundSqlInterceptor */\n"; |
| 102 | + |
| 103 | + @Override |
| 104 | + public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { |
| 105 | + if (type == Type.ORIGINAL) { |
| 106 | + String sql = boundSql.getSql(); |
| 107 | + MetaObject metaObject = MetaObjectUtil.forObject(boundSql); |
| 108 | + metaObject.setValue("sql", sql + COMMENT); |
| 109 | + } |
| 110 | + return chain.doBoundSql(type, boundSql, cacheKey); |
| 111 | + } |
| 112 | + |
| 113 | +} |
| 114 | +``` |
| 115 | +The above code modifies the original sql before SQL execution, but only adds a comment at the end, which does not affect SQL execution. It is configured in the following way: |
| 116 | + |
| 117 | +```xml |
| 118 | +<plugin interceptor="com.github.pagehelper.PageInterceptor"> |
| 119 | + <!-- 支持通过Mapper接口参数来传递分页参数 --> |
| 120 | + <property name="helperDialect" value="mysql"/> |
| 121 | + <property name="boundSqlInterceptors" |
| 122 | + value="com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor,com.github.pagehelper.test.basic.provider.TestBoundSqlInterceptor"/> |
| 123 | +</plugin> |
| 124 | +``` |
| 125 | + |
| 126 | +Here, in order to explain that the parameter value can be multiple, it is repeatedly configured once, that is, the above interceptor will execute it twice. |
| 127 | + |
| 128 | +With this configuration, the above SQL will modify the SQL when the page is executed. |
| 129 | + |
| 130 | +In addition to this configuration mode, temporary designation when PageHelper.startPage is also supported. This mode will put the interceptor at the chain head and execute it first, so you can control whether to execute it later or not, or you can do the final processing before returning after all subsequent executions. |
| 131 | + |
| 132 | +Example: |
| 133 | + |
| 134 | +```java |
| 135 | +PageHelper.startPage(1, 10).boundSqlInterceptor(new BoundSqlInterceptor() { |
| 136 | + @Override |
| 137 | + public BoundSql boundSql(Type type, BoundSql boundSql, CacheKey cacheKey, Chain chain) { |
| 138 | + System.out.println("before: " + boundSql.getSql()); |
| 139 | + BoundSql doBoundSql = chain.doBoundSql(type, boundSql, cacheKey); |
| 140 | + System.out.println("after: " + doBoundSql.getSql()); |
| 141 | + if (type == Type.ORIGINAL) { |
| 142 | + Assert.assertTrue(doBoundSql.getSql().contains(TestBoundSqlInterceptor.COMMENT)); |
| 143 | + } |
| 144 | + return doBoundSql; |
| 145 | + } |
| 146 | +}); |
| 147 | +``` |
| 148 | + |
| 149 | + |
| 150 | + |
3 | 151 | ### 5.1.11 - 2019-11-26
|
4 | 152 |
|
5 | 153 | - Added support for Shentong database **wangss**
|
|
0 commit comments