View Javadoc
1   /*
2    *    Copyright 2009-2023 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.executor;
17  
18  import static org.junit.jupiter.api.Assertions.assertEquals;
19  import static org.junit.jupiter.api.Assertions.assertNotNull;
20  import static org.junit.jupiter.api.Assertions.assertNull;
21  import static org.junit.jupiter.api.Assertions.assertTrue;
22  
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javassist.util.proxy.Proxy;
29  
30  import javax.sql.DataSource;
31  
32  import org.apache.ibatis.BaseDataTest;
33  import org.apache.ibatis.builder.StaticSqlSource;
34  import org.apache.ibatis.cache.CacheKey;
35  import org.apache.ibatis.domain.blog.Author;
36  import org.apache.ibatis.domain.blog.Blog;
37  import org.apache.ibatis.domain.blog.Post;
38  import org.apache.ibatis.domain.blog.Section;
39  import org.apache.ibatis.mapping.BoundSql;
40  import org.apache.ibatis.mapping.MappedStatement;
41  import org.apache.ibatis.mapping.ParameterMapping;
42  import org.apache.ibatis.mapping.SqlCommandType;
43  import org.apache.ibatis.session.Configuration;
44  import org.apache.ibatis.session.RowBounds;
45  import org.apache.ibatis.transaction.Transaction;
46  import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
47  import org.apache.ibatis.type.JdbcType;
48  import org.apache.ibatis.type.TypeHandlerRegistry;
49  import org.junit.jupiter.api.BeforeAll;
50  import org.junit.jupiter.api.Test;
51  
52  class BaseExecutorTest extends BaseDataTest {
53    protected final Configuration config;
54    private static DataSource ds;
55  
56    @BeforeAll
57    static void setup() throws Exception {
58      ds = createBlogDataSource();
59    }
60  
61    BaseExecutorTest() {
62      config = new Configuration();
63      config.setLazyLoadingEnabled(true);
64      config.setUseGeneratedKeys(false);
65      config.setMultipleResultSetsEnabled(true);
66      config.setUseColumnLabel(true);
67      config.setDefaultStatementTimeout(5000);
68      config.setDefaultFetchSize(100);
69    }
70  
71    @Test
72    void shouldInsertNewAuthorWithBeforeAutoKey() throws Exception {
73  
74      Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
75      try {
76        Author author = new Author(-1, "someone", "******", "someone@apache.org", null, Section.NEWS);
77        MappedStatement insertStatement = ExecutorTestHelper.prepareInsertAuthorMappedStatementWithBeforeAutoKey(config);
78        MappedStatement selectStatement = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
79        int rows = executor.update(insertStatement, author);
80        assertTrue(rows > 0 || rows == BatchExecutor.BATCH_UPDATE_RETURN_VALUE);
81        if (rows == BatchExecutor.BATCH_UPDATE_RETURN_VALUE) {
82          executor.flushStatements();
83        }
84        assertEquals(123456, author.getId());
85        if (author.getId() != BatchExecutor.BATCH_UPDATE_RETURN_VALUE) {
86          List<Author> authors = executor.query(selectStatement, author.getId(), RowBounds.DEFAULT,
87              Executor.NO_RESULT_HANDLER);
88          executor.rollback(true);
89          assertEquals(1, authors.size());
90          assertEquals(author.toString(), authors.get(0).toString());
91          assertTrue(author.getId() >= 10000);
92        }
93      } finally {
94        executor.rollback(true);
95        executor.close(false);
96      }
97    }
98  
99    @Test
100   void shouldInsertNewAuthor() throws Exception {
101 
102     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
103     try {
104       Author author = new Author(99, "someone", "******", "someone@apache.org", null, Section.NEWS);
105       MappedStatement insertStatement = ExecutorTestHelper.prepareInsertAuthorMappedStatement(config);
106       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
107       int rows = executor.update(insertStatement, author);
108       List<Author> authors = executor.query(selectStatement, 99, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
109       executor.flushStatements();
110       executor.rollback(true);
111       assertEquals(1, authors.size());
112       assertEquals(author.toString(), authors.get(0).toString());
113       assertTrue(1 == rows || BatchExecutor.BATCH_UPDATE_RETURN_VALUE == rows);
114     } finally {
115       executor.rollback(true);
116       executor.close(false);
117     }
118   }
119 
120   @Test
121   void shouldSelectAllAuthorsAutoMapped() throws Exception {
122 
123     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
124     try {
125       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectAllAuthorsAutoMappedStatement(config);
126       List<Author> authors = executor.query(selectStatement, null, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
127       assertEquals(2, authors.size());
128       Author author = authors.get(0);
129       // id,username, password, email, bio, favourite_section
130       // (101,'jim','********','jim@ibatis.apache.org','','NEWS');
131       assertEquals(101, author.getId());
132       assertEquals("jim", author.getUsername());
133       assertEquals("jim@ibatis.apache.org", author.getEmail());
134       assertEquals("", author.getBio());
135       assertEquals(Section.NEWS, author.getFavouriteSection());
136     } finally {
137       executor.rollback(true);
138       executor.close(false);
139     }
140   }
141 
142   @Test
143   void shouldInsertNewAuthorWithAutoKey() throws Exception {
144 
145     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
146     try {
147       Author author = new Author(-1, "someone", "******", "someone@apache.org", null, Section.NEWS);
148       MappedStatement insertStatement = ExecutorTestHelper.prepareInsertAuthorMappedStatementWithAutoKey(config);
149       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
150       int rows = executor.update(insertStatement, author);
151       assertTrue(rows > 0 || rows == BatchExecutor.BATCH_UPDATE_RETURN_VALUE);
152       if (rows == BatchExecutor.BATCH_UPDATE_RETURN_VALUE) {
153         executor.flushStatements();
154       }
155       assertTrue(-1 != author.getId());
156       if (author.getId() != BatchExecutor.BATCH_UPDATE_RETURN_VALUE) {
157         List<Author> authors = executor.query(selectStatement, author.getId(), RowBounds.DEFAULT,
158             Executor.NO_RESULT_HANDLER);
159         executor.rollback(true);
160         assertEquals(1, authors.size());
161         assertEquals(author.toString(), authors.get(0).toString());
162         assertTrue(author.getId() >= 10000);
163       }
164     } finally {
165       executor.rollback(true);
166       executor.close(false);
167     }
168   }
169 
170   @Test
171   void shouldInsertNewAuthorByProc() throws Exception {
172 
173     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
174     try {
175       Author author = new Author(97, "someone", "******", "someone@apache.org", null, null);
176       MappedStatement insertStatement = ExecutorTestHelper.prepareInsertAuthorProc(config);
177       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
178       executor.update(insertStatement, author);
179       List<Author> authors = executor.query(selectStatement, 97, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
180       executor.flushStatements();
181       executor.rollback(true);
182       assertEquals(1, authors.size());
183       assertEquals(author.toString(), authors.get(0).toString());
184     } finally {
185       executor.rollback(true);
186       executor.close(false);
187     }
188   }
189 
190   @Test
191   void shouldInsertNewAuthorUsingSimpleNonPreparedStatements() throws Exception {
192 
193     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
194     try {
195       Author author = new Author(99, "someone", "******", "someone@apache.org", null, null);
196       MappedStatement insertStatement = ExecutorTestHelper.createInsertAuthorWithIDof99MappedStatement(config);
197       MappedStatement selectStatement = ExecutorTestHelper.createSelectAuthorWithIDof99MappedStatement(config);
198       int rows = executor.update(insertStatement, null);
199       List<Author> authors = executor.query(selectStatement, 99, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
200       executor.flushStatements();
201       executor.rollback(true);
202       assertEquals(1, authors.size());
203       assertEquals(author.toString(), authors.get(0).toString());
204       assertTrue(1 == rows || BatchExecutor.BATCH_UPDATE_RETURN_VALUE == rows);
205     } finally {
206       executor.rollback(true);
207       executor.close(false);
208     }
209   }
210 
211   @Test
212   void shouldUpdateAuthor() throws Exception {
213 
214     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
215     try {
216       Author author = new Author(101, "someone", "******", "someone@apache.org", null, Section.NEWS);
217       MappedStatement updateStatement = ExecutorTestHelper.prepareUpdateAuthorMappedStatement(config);
218       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
219       int rows = executor.update(updateStatement, author);
220       List<Author> authors = executor.query(selectStatement, 101, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
221       executor.flushStatements();
222       executor.rollback(true);
223       assertEquals(1, authors.size());
224       assertEquals(author.toString(), authors.get(0).toString());
225       assertTrue(1 == rows || BatchExecutor.BATCH_UPDATE_RETURN_VALUE == rows);
226     } finally {
227       executor.rollback(true);
228       executor.close(false);
229     }
230   }
231 
232   @Test
233   void shouldDeleteAuthor() throws Exception {
234 
235     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
236     try {
237       Author author = new Author(101, null, null, null, null, null);
238       MappedStatement deleteStatement = ExecutorTestHelper.prepareDeleteAuthorMappedStatement(config);
239       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
240       int rows = executor.update(deleteStatement, author);
241       List<Author> authors = executor.query(selectStatement, 101, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
242       executor.flushStatements();
243       executor.rollback(true);
244       assertEquals(0, authors.size());
245       assertTrue(1 == rows || BatchExecutor.BATCH_UPDATE_RETURN_VALUE == rows);
246     } finally {
247       executor.rollback(true);
248       executor.close(false);
249     }
250   }
251 
252   @Test
253   void shouldSelectDiscriminatedPost() throws Exception {
254 
255     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
256     try {
257       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectDiscriminatedPost(config);
258       List<Map<String, String>> products = executor.query(selectStatement, null, RowBounds.DEFAULT,
259           Executor.NO_RESULT_HANDLER);
260       assertEquals(5, products.size());
261       for (Map<String, String> m : products) {
262         if ("IMAGES".equals(m.get("SECTION"))) {
263           assertNull(m.get("subject"));
264           assertNotNull(m.get("id"));
265         } else {
266           assertNotNull(m.get("subject"));
267           assertNull(m.get("id"));
268         }
269       }
270     } finally {
271       executor.close(false);
272     }
273   }
274 
275   @Test
276   void shouldSelect2DiscriminatedPosts() throws Exception {
277 
278     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
279     try {
280       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectDiscriminatedPost(config);
281       List<Map<String, String>> products = executor.query(selectStatement, null, new RowBounds(2, 2),
282           Executor.NO_RESULT_HANDLER);
283       assertEquals(2, products.size());
284       for (Map<String, String> m : products) {
285         if ("IMAGES".equals(m.get("SECTION"))) {
286           assertNull(m.get("subject"));
287           assertNotNull(m.get("id"));
288         } else {
289           assertNotNull(m.get("subject"));
290           assertNull(m.get("id"));
291         }
292       }
293     } finally {
294       executor.rollback(true);
295       executor.close(false);
296     }
297   }
298 
299   @Test
300   void shouldSelectTwoSetsOfAuthorsViaProc() throws Exception {
301     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
302     try {
303       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectTwoSetsOfAuthorsProc(config);
304       List<List<Author>> authorSets = executor.query(selectStatement, new HashMap<String, Object>() {
305         private static final long serialVersionUID = 1L;
306         {
307           put("id1", 101);
308           put("id2", 102);
309         }
310       }, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
311       assertEquals(2, authorSets.size());
312       for (List<Author> authors : authorSets) {
313         assertEquals(2, authors.size());
314         for (Object author : authors) {
315           assertTrue(author instanceof Author);
316         }
317       }
318     } finally {
319       executor.rollback(true);
320       executor.close(false);
321     }
322   }
323 
324   @Test
325   void shouldSelectAuthorViaOutParams() throws Exception {
326 
327     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
328     try {
329       MappedStatement selectStatement = ExecutorTestHelper.prepareSelectAuthorViaOutParams(config);
330       Author author = new Author(102, null, null, null, null, null);
331       executor.query(selectStatement, author, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
332       assertEquals("sally", author.getUsername());
333       assertEquals("********", author.getPassword());
334       assertEquals("sally@ibatis.apache.org", author.getEmail());
335       assertNull(author.getBio());
336     } catch (ExecutorException e) {
337       if (!(executor instanceof CachingExecutor)) {
338         throw e;
339       }
340       // TODO see issue #464. Fail is OK.
341       assertTrue(e.getMessage().contains("OUT params is not supported"));
342     } finally {
343       executor.rollback(true);
344       executor.close(false);
345     }
346   }
347 
348   @Test
349   void shouldFetchPostsForBlog() throws Exception {
350 
351     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
352     try {
353       MappedStatement selectBlog = ExecutorTestHelper.prepareComplexSelectBlogMappedStatement(config);
354       MappedStatement selectPosts = ExecutorTestHelper.prepareSelectPostsForBlogMappedStatement(config);
355       config.addMappedStatement(selectBlog);
356       config.addMappedStatement(selectPosts);
357       List<Post> posts = executor.query(selectPosts, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
358       executor.flushStatements();
359       assertEquals(2, posts.size());
360       assertTrue(posts.get(1) instanceof Proxy);
361       assertNotNull(posts.get(1).getBlog());
362       assertEquals(1, posts.get(1).getBlog().getId());
363       executor.rollback(true);
364     } finally {
365       executor.rollback(true);
366       executor.close(false);
367     }
368   }
369 
370   @Test
371   void shouldFetchOneOrphanedPostWithNoBlog() throws Exception {
372 
373     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
374     try {
375       MappedStatement selectBlog = ExecutorTestHelper.prepareComplexSelectBlogMappedStatement(config);
376       MappedStatement selectPost = ExecutorTestHelper.prepareSelectPostMappedStatement(config);
377       config.addMappedStatement(selectBlog);
378       config.addMappedStatement(selectPost);
379       List<Post> posts = executor.query(selectPost, 5, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
380       executor.flushStatements();
381       executor.rollback(true);
382       assertEquals(1, posts.size());
383       Post post = posts.get(0);
384       assertNull(post.getBlog());
385     } finally {
386       executor.rollback(true);
387       executor.close(false);
388     }
389   }
390 
391   @Test
392   void shouldFetchPostWithBlogWithCompositeKey() throws Exception {
393 
394     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
395     try {
396       MappedStatement selectBlog = ExecutorTestHelper.prepareSelectBlogByIdAndAuthor(config);
397       MappedStatement selectPost = ExecutorTestHelper.prepareSelectPostWithBlogByAuthorMappedStatement(config);
398       config.addMappedStatement(selectBlog);
399       config.addMappedStatement(selectPost);
400       List<Post> posts = executor.query(selectPost, 2, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
401       executor.flushStatements();
402       assertEquals(1, posts.size());
403       Post post = posts.get(0);
404       assertNotNull(post.getBlog());
405       assertEquals(101, post.getBlog().getAuthor().getId());
406       executor.rollback(true);
407     } finally {
408       executor.rollback(true);
409       executor.close(false);
410     }
411   }
412 
413   @Test
414   void shouldFetchComplexBlogs() throws Exception {
415 
416     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
417     try {
418       MappedStatement selectBlog = ExecutorTestHelper.prepareComplexSelectBlogMappedStatement(config);
419       MappedStatement selectPosts = ExecutorTestHelper.prepareSelectPostsForBlogMappedStatement(config);
420       config.addMappedStatement(selectBlog);
421       config.addMappedStatement(selectPosts);
422       List<Blog> blogs = executor.query(selectBlog, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
423       executor.flushStatements();
424       assertEquals(1, blogs.size());
425       assertNotNull(blogs.get(0).getPosts());
426       assertEquals(2, blogs.get(0).getPosts().size());
427       assertEquals(1, blogs.get(0).getPosts().get(1).getBlog().getPosts().get(1).getBlog().getId());
428       executor.rollback(true);
429     } finally {
430       executor.rollback(true);
431       executor.close(false);
432     }
433   }
434 
435   @Test
436   void shouldMapConstructorResults() throws Exception {
437 
438     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
439     try {
440       MappedStatement selectStatement = ExecutorTestHelper
441           .prepareSelectOneAuthorMappedStatementWithConstructorResults(config);
442       List<Author> authors = executor.query(selectStatement, 102, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
443       executor.flushStatements();
444       executor.rollback(true);
445       assertEquals(1, authors.size());
446 
447       Author author = authors.get(0);
448       assertEquals(102, author.getId());
449     } finally {
450       executor.rollback(true);
451       executor.close(false);
452     }
453   }
454 
455   @Test
456   void shouldClearDeferredLoads() throws Exception {
457 
458     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
459     try {
460       MappedStatement selectBlog = ExecutorTestHelper.prepareComplexSelectBlogMappedStatement(config);
461       MappedStatement selectPosts = ExecutorTestHelper.prepareSelectPostsForBlogMappedStatement(config);
462       config.addMappedStatement(selectBlog);
463       config.addMappedStatement(selectPosts);
464       MappedStatement selectAuthor = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
465       MappedStatement insertAuthor = ExecutorTestHelper.prepareInsertAuthorMappedStatement(config);
466 
467       // generate DeferredLoads
468       executor.query(selectPosts, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
469 
470       Author author = new Author(-1, "someone", "******", "someone@apache.org", null, Section.NEWS);
471       executor.update(insertAuthor, author);
472       executor.query(selectAuthor, -1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
473       executor.flushStatements();
474       executor.rollback(true);
475     } finally {
476       executor.rollback(true);
477       executor.close(false);
478     }
479   }
480 
481   @Test
482   void testCreateCacheKeyWithAdditionalParameter() {
483     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
484 
485     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
486         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
487 
488     Object parameterObject = 1;
489 
490     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
491       {
492         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
493       }
494     }, parameterObject) {
495       {
496         setAdditionalParameter("id", 2);
497       }
498     };
499 
500     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
501     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
502 
503     CacheKey expected = new CacheKey();
504     expected.update(mappedStatement.getId());
505     expected.update(RowBounds.DEFAULT.getOffset());
506     expected.update(RowBounds.DEFAULT.getLimit());
507     expected.update(boundSql.getSql());
508     expected.update(2);
509 
510     assertEquals(expected, cacheKey);
511   }
512 
513   @Test
514   void testCreateCacheKeyWithNull() {
515     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
516 
517     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
518         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
519 
520     Object parameterObject = null;
521 
522     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
523       {
524         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
525       }
526     }, parameterObject);
527 
528     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
529     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
530 
531     CacheKey expected = new CacheKey();
532     expected.update(mappedStatement.getId());
533     expected.update(RowBounds.DEFAULT.getOffset());
534     expected.update(RowBounds.DEFAULT.getLimit());
535     expected.update(boundSql.getSql());
536     expected.update(null);
537 
538     assertEquals(expected, cacheKey);
539   }
540 
541   @Test
542   void testCreateCacheKeyWithTypeHandler() {
543     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
544 
545     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
546         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
547 
548     Object parameterObject = 1;
549 
550     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
551       {
552         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
553       }
554     }, parameterObject);
555 
556     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
557     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
558 
559     CacheKey expected = new CacheKey();
560     expected.update(mappedStatement.getId());
561     expected.update(RowBounds.DEFAULT.getOffset());
562     expected.update(RowBounds.DEFAULT.getLimit());
563     expected.update(boundSql.getSql());
564     expected.update(1);
565 
566     assertEquals(expected, cacheKey);
567   }
568 
569   @Test
570   void testCreateCacheKeyWithMetaObject() {
571     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
572 
573     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
574         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
575 
576     Author parameterObject = new Author(-1, "cbegin", "******", "cbegin@nowhere.com", "N/A", Section.NEWS);
577 
578     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
579       {
580         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
581         add(new ParameterMapping.Builder(config, "username", registry.getTypeHandler(String.class)).build());
582         add(new ParameterMapping.Builder(config, "password", registry.getTypeHandler(String.class)).build());
583         add(new ParameterMapping.Builder(config, "email", registry.getTypeHandler(String.class)).build());
584         add(new ParameterMapping.Builder(config, "bio", registry.getTypeHandler(String.class))
585             .jdbcType(JdbcType.VARCHAR).build());
586         add(new ParameterMapping.Builder(config, "favouriteSection", registry.getTypeHandler(Section.class))
587             .jdbcType(JdbcType.VARCHAR).build());
588       }
589     }, parameterObject);
590 
591     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
592     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
593 
594     CacheKey expected = new CacheKey();
595     expected.update(mappedStatement.getId());
596     expected.update(RowBounds.DEFAULT.getOffset());
597     expected.update(RowBounds.DEFAULT.getLimit());
598     expected.update(boundSql.getSql());
599     expected.update(parameterObject.getId());
600     expected.update(parameterObject.getUsername());
601     expected.update(parameterObject.getPassword());
602     expected.update(parameterObject.getEmail());
603     expected.update(parameterObject.getBio());
604     expected.update(parameterObject.getFavouriteSection());
605 
606     assertEquals(expected, cacheKey);
607   }
608 
609   protected Executor createExecutor(Transaction transaction) {
610     return new SimpleExecutor(config, transaction);
611   }
612 
613 }