View Javadoc
1   /*
2    *    Copyright 2009-2024 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.assertDoesNotThrow;
19  import static org.junit.jupiter.api.Assertions.assertEquals;
20  import static org.junit.jupiter.api.Assertions.assertNotNull;
21  import static org.junit.jupiter.api.Assertions.assertNull;
22  import static org.junit.jupiter.api.Assertions.assertTrue;
23  
24  import java.util.ArrayList;
25  import java.util.HashMap;
26  import java.util.List;
27  import java.util.Map;
28  
29  import javassist.util.proxy.Proxy;
30  
31  import javax.sql.DataSource;
32  
33  import org.apache.ibatis.BaseDataTest;
34  import org.apache.ibatis.builder.StaticSqlSource;
35  import org.apache.ibatis.cache.CacheKey;
36  import org.apache.ibatis.domain.blog.Author;
37  import org.apache.ibatis.domain.blog.Blog;
38  import org.apache.ibatis.domain.blog.Post;
39  import org.apache.ibatis.domain.blog.Section;
40  import org.apache.ibatis.mapping.BoundSql;
41  import org.apache.ibatis.mapping.MappedStatement;
42  import org.apache.ibatis.mapping.ParameterMapping;
43  import org.apache.ibatis.mapping.SqlCommandType;
44  import org.apache.ibatis.session.Configuration;
45  import org.apache.ibatis.session.RowBounds;
46  import org.apache.ibatis.transaction.Transaction;
47  import org.apache.ibatis.transaction.jdbc.JdbcTransaction;
48  import org.apache.ibatis.type.JdbcType;
49  import org.apache.ibatis.type.TypeHandlerRegistry;
50  import org.junit.jupiter.api.BeforeAll;
51  import org.junit.jupiter.api.Test;
52  
53  class BaseExecutorTest extends BaseDataTest {
54    protected final Configuration config;
55    private static DataSource ds;
56  
57    @BeforeAll
58    static void setup() throws Exception {
59      ds = createBlogDataSource();
60    }
61  
62    BaseExecutorTest() {
63      config = new Configuration();
64      config.setLazyLoadingEnabled(true);
65      config.setUseGeneratedKeys(false);
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() {
457     assertDoesNotThrow(() -> {
458 
459       Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
460       try {
461         MappedStatement selectBlog = ExecutorTestHelper.prepareComplexSelectBlogMappedStatement(config);
462         MappedStatement selectPosts = ExecutorTestHelper.prepareSelectPostsForBlogMappedStatement(config);
463         config.addMappedStatement(selectBlog);
464         config.addMappedStatement(selectPosts);
465         MappedStatement selectAuthor = ExecutorTestHelper.prepareSelectOneAuthorMappedStatement(config);
466         MappedStatement insertAuthor = ExecutorTestHelper.prepareInsertAuthorMappedStatement(config);
467 
468         // generate DeferredLoads
469         executor.query(selectPosts, 1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
470 
471         Author author = new Author(-1, "someone", "******", "someone@apache.org", null, Section.NEWS);
472         executor.update(insertAuthor, author);
473         executor.query(selectAuthor, -1, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
474         executor.flushStatements();
475         executor.rollback(true);
476       } finally {
477         executor.rollback(true);
478         executor.close(false);
479       }
480     });
481   }
482 
483   @Test
484   void createCacheKeyWithAdditionalParameter() {
485     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
486 
487     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
488         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
489 
490     Object parameterObject = 1;
491 
492     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
493       private static final long serialVersionUID = 1L;
494 
495       {
496         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
497       }
498     }, parameterObject) {
499       {
500         setAdditionalParameter("id", 2);
501       }
502     };
503 
504     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
505     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
506 
507     CacheKey expected = new CacheKey();
508     expected.update(mappedStatement.getId());
509     expected.update(RowBounds.DEFAULT.getOffset());
510     expected.update(RowBounds.DEFAULT.getLimit());
511     expected.update(boundSql.getSql());
512     expected.update(2);
513 
514     assertEquals(expected, cacheKey);
515   }
516 
517   @Test
518   void createCacheKeyWithNull() {
519     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
520 
521     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
522         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
523 
524     Object parameterObject = null;
525 
526     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
527       private static final long serialVersionUID = 1L;
528 
529       {
530         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
531       }
532     }, parameterObject);
533 
534     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
535     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
536 
537     CacheKey expected = new CacheKey();
538     expected.update(mappedStatement.getId());
539     expected.update(RowBounds.DEFAULT.getOffset());
540     expected.update(RowBounds.DEFAULT.getLimit());
541     expected.update(boundSql.getSql());
542     expected.update(null);
543 
544     assertEquals(expected, cacheKey);
545   }
546 
547   @Test
548   void createCacheKeyWithTypeHandler() {
549     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
550 
551     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
552         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
553 
554     Object parameterObject = 1;
555 
556     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
557       private static final long serialVersionUID = 1L;
558 
559       {
560         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
561       }
562     }, parameterObject);
563 
564     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
565     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
566 
567     CacheKey expected = new CacheKey();
568     expected.update(mappedStatement.getId());
569     expected.update(RowBounds.DEFAULT.getOffset());
570     expected.update(RowBounds.DEFAULT.getLimit());
571     expected.update(boundSql.getSql());
572     expected.update(1);
573 
574     assertEquals(expected, cacheKey);
575   }
576 
577   @Test
578   void createCacheKeyWithMetaObject() {
579     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
580 
581     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
582         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
583 
584     Author parameterObject = new Author(-1, "cbegin", "******", "cbegin@nowhere.com", "N/A", Section.NEWS);
585 
586     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
587       private static final long serialVersionUID = 1L;
588 
589       {
590         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
591         add(new ParameterMapping.Builder(config, "username", registry.getTypeHandler(String.class)).build());
592         add(new ParameterMapping.Builder(config, "password", registry.getTypeHandler(String.class)).build());
593         add(new ParameterMapping.Builder(config, "email", registry.getTypeHandler(String.class)).build());
594         add(new ParameterMapping.Builder(config, "bio", registry.getTypeHandler(String.class))
595             .jdbcType(JdbcType.VARCHAR).build());
596         add(new ParameterMapping.Builder(config, "favouriteSection", registry.getTypeHandler(Section.class))
597             .jdbcType(JdbcType.VARCHAR).build());
598       }
599     }, parameterObject);
600 
601     Executor executor = createExecutor(new JdbcTransaction(ds, null, false));
602     CacheKey cacheKey = executor.createCacheKey(mappedStatement, parameterObject, RowBounds.DEFAULT, boundSql);
603 
604     CacheKey expected = new CacheKey();
605     expected.update(mappedStatement.getId());
606     expected.update(RowBounds.DEFAULT.getOffset());
607     expected.update(RowBounds.DEFAULT.getLimit());
608     expected.update(boundSql.getSql());
609     expected.update(parameterObject.getId());
610     expected.update(parameterObject.getUsername());
611     expected.update(parameterObject.getPassword());
612     expected.update(parameterObject.getEmail());
613     expected.update(parameterObject.getBio());
614     expected.update(parameterObject.getFavouriteSection());
615 
616     assertEquals(expected, cacheKey);
617   }
618 
619   protected Executor createExecutor(Transaction transaction) {
620     return new SimpleExecutor(config, transaction);
621   }
622 
623 }