com.itfsw.mybatis.generator.plugins.OptimisticLockerPluginTest.java Source code

Java tutorial

Introduction

Here is the source code for com.itfsw.mybatis.generator.plugins.OptimisticLockerPluginTest.java

Source

/*
 * Copyright (c) 2018.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.itfsw.mybatis.generator.plugins;

import com.itfsw.mybatis.generator.plugins.tools.*;
import org.apache.ibatis.session.SqlSession;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

import java.io.IOException;
import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * ---------------------------------------------------------------------------
 *
 * ---------------------------------------------------------------------------
 * 
 * @author: hewei
 * @time:2018/5/2 17:05
 *                --------------------------------------------------------------
 *                -------------
 */
public class OptimisticLockerPluginTest {
    /**
     * ??
     */
    @BeforeClass
    public static void init() throws SQLException, IOException, ClassNotFoundException {
        DBHelper.createDB("scripts/OptimisticLockerPlugin/init.sql");
    }

    /**
     * ?
     */
    @Test
    public void testWarnings() throws Exception {
        // 2. ?
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-with-unfind-version-column.xml");
        tool.generate();
        Assert.assertEquals(tool.getWarnings().get(0),
                "itfsw(???):tb?(ttssss)?");
    }

    /**
     *  deleteWithVersionByExample
     */
    @Test
    public void testDeleteWithVersionByExample() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "deleteWithVersionByExample", 100L,
                        tbExample.getObject());
                Assert.assertEquals(sql, "delete from tb WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100??
                Object result = tbMapper.invoke("deleteWithVersionByExample", 100L, tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("deleteWithVersionByExample", 0L, tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ?
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                Assert.assertEquals(rs.first(), false);
            }
        });
    }

    /**
     *  deleteWithVersionByPrimaryKey
     */
    @Test
    public void testDeleteWithVersionByPrimaryKey() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");

        // ???key@Param("key")
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "deleteWithVersionByPrimaryKey",
                        100L, 1L);
                Assert.assertEquals(sql, "delete from tb where inc_f1 = 100 and id = 1");

                // ?100??
                Object result = tbMapper.invoke("deleteWithVersionByPrimaryKey", 100L, 1L);
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("deleteWithVersionByPrimaryKey", 0L, 1L);
                Assert.assertEquals(result, 1);

                // ?
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                Assert.assertEquals(rs.first(), false);
            }
        });

        // ?key@Param("record")
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbKeysMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbKeysMapper")));

                ObjectUtil tbKeysKey = new ObjectUtil(loader, packagz + ".TbKeysKey");
                tbKeysKey.set("key1", 1L);
                tbKeysKey.set("key2", "k1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbKeysMapper.getObject(), "deleteWithVersionByPrimaryKey",
                        100L, tbKeysKey.getObject());
                Assert.assertEquals(sql, "delete from tb_keys where inc_f1 = 100 and key1 = 1 and key2 = 'k1'");

                // ?100??
                Object result = tbKeysMapper.invoke("deleteWithVersionByPrimaryKey", 100L, tbKeysKey.getObject());
                Assert.assertEquals(result, 0);

                // key1 = 1, key2 = k1 ?1
                result = tbKeysMapper.invoke("deleteWithVersionByPrimaryKey", 1L, tbKeysKey.getObject());
                Assert.assertEquals(result, 1);

                // ?
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(),
                        "select * from tb_keys where key1 = 1 and key2 = 'k1'");
                Assert.assertEquals(rs.first(), false);
            }
        });
    }

    /**
     *  updateWithVersionByExampleSelective
     */
    @Test
    public void testUpdateWithVersionByExampleSelective() throws Exception {
        // ?
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByExampleSelective", 100L, tb.getObject(), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1, inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExampleSelective", 100L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByExampleSelective", 0L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        // ?
        tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-customizedNextVersion.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.invoke("setIncF1", 152L); // nextVersion
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByExampleSelective", 100L, tb.getObject(), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = 152, id = 1, inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExampleSelective", 100L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByExampleSelective", 0L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
            }
        });
    }

    /**
     *  updateWithVersionByExample
     */
    @Test
    public void testUpdateWithVersionByExample() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");
        // ?or
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByExample", 100L,
                        tb.getObject(), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = inc_f1 + 1, id = 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExample", 100L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByExample", 0L, tb.getObject(), tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        //  byExample or ???
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil orCriteria = new ObjectUtil(tbExample.invoke("or"));
                orCriteria.invoke("andField1EqualTo", "ts1");

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByExample", 100L,
                        tb.getObject(), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = inc_f1 + 1, id = 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) or( field1 = 'ts1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExample", 100L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 0);
            }
        });

        // ?
        tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-customizedNextVersion.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.invoke("nextVersion", 152L); // nextVersion
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByExample", 100L,
                        tb.getObject(), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = 152, id = 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExample", 100L, tb.getObject(),
                        tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByExample", 0L, tb.getObject(), tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
            }
        });
    }

    /**
     *  updateWithVersionByExampleWithBLOBs
     */
    @Test
    public void testUpdateWithVersionByExampleWithBLOBs() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");

        // withoutBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsExample = new ObjectUtil(loader, packagz + ".TbBlobsExample");
                ObjectUtil criteria = new ObjectUtil(tbBlobsExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBlobs = new ObjectUtil(loader, packagz + ".TbBlobs");
                tbBlobs.set("id", 1L);
                tbBlobs.set("incF1", 152L); // ?sql?
                tbBlobs.set("incF2", 10L);
                tbBlobs.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(), "updateWithVersionByExample",
                        100L, tbBlobs.getObject(), tbBlobsExample.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, id = 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByExample", 100L, tbBlobs.getObject(),
                        tbBlobsExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByExample", 1L, tbBlobs.getObject(),
                        tbBlobsExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
            }
        });

        // withBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsExample = new ObjectUtil(loader, packagz + ".TbBlobsExample");
                ObjectUtil criteria = new ObjectUtil(tbBlobsExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBlobsWithBLOBs = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs");
                tbBlobsWithBLOBs.set("id", 1L);
                tbBlobsWithBLOBs.set("incF1", 152L); // ?sql?
                tbBlobsWithBLOBs.set("incF2", 10L);
                tbBlobsWithBLOBs.set("incF3", 5L);
                tbBlobsWithBLOBs.set("field1", "ts1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByExampleWithBLOBs", 100L, tbBlobsWithBLOBs.getObject(),
                        tbBlobsExample.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, id = 1, field1 = 'ts1', inc_f2 = 10, inc_f3 = 5, field2 = 'null', field3 = 'null' WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByExampleWithBLOBs", 100L,
                        tbBlobsWithBLOBs.getObject(), tbBlobsExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByExampleWithBLOBs", 1L,
                        tbBlobsWithBLOBs.getObject(), tbBlobsExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
                Assert.assertEquals(rs.getString("field1"), "ts1");
            }
        });

        // ================================================ ?
        // =======================================================
        tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-customizedNextVersion.xml");
        // withoutBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsExample = new ObjectUtil(loader, packagz + ".TbBlobsExample");
                ObjectUtil criteria = new ObjectUtil(tbBlobsExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBlobsBuilder = new ObjectUtil(loader, packagz + ".TbBlobs$Builder");
                tbBlobsBuilder.invoke("id", 1L);
                tbBlobsBuilder.invoke("incF1", 152L); // set
                tbBlobsBuilder.invoke("incF2", 10L);
                tbBlobsBuilder.invoke("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(), "updateWithVersionByExample",
                        100L, tbBlobsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = 152, id = 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByExample", 100L,
                        tbBlobsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByExample", 1L, tbBlobsBuilder.invoke("build"),
                        tbBlobsExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
            }
        });

        // withBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsExample = new ObjectUtil(loader, packagz + ".TbBlobsExample");
                ObjectUtil criteria = new ObjectUtil(tbBlobsExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBlobsBuilder = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs$Builder");
                tbBlobsBuilder.invoke("id", 1L);
                tbBlobsBuilder.invoke("nextVersion", 152L); // nextVersion 
                tbBlobsBuilder.invoke("incF2", 10L);
                tbBlobsBuilder.invoke("incF3", 5L);
                tbBlobsBuilder.invoke("field1", "ts1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByExampleWithBLOBs", 100L, tbBlobsBuilder.invoke("build"),
                        tbBlobsExample.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = 152, id = 1, field1 = 'ts1', inc_f2 = 10, inc_f3 = 5, field2 = 'null', field3 = 'null' WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByExampleWithBLOBs", 100L,
                        tbBlobsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByExampleWithBLOBs", 1L,
                        tbBlobsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
                Assert.assertEquals(rs.getString("field1"), "ts1");
            }
        });
    }

    /**
     *  updateWithVersionByPrimaryKeySelective
     */
    @Test
    public void testUpdateWithVersionByPrimaryKeySelective() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByPrimaryKeySelective", 100L, tb.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 100L, tb.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 0L, tb.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        // ?
        tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-customizedNextVersion.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.invoke("nextVersion", 152L);
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByPrimaryKeySelective", 100L, tb.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = 152, inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 100L, tb.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 0L, tb.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
            }
        });
    }

    /**
     *  updateWithVersionByPrimaryKey
     */
    @Test
    public void testUpdateWithVersionByPrimaryKey() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByPrimaryKey",
                        100L, tb.getObject());
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = inc_f1 + 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKey", 100L, tb.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByPrimaryKey", 0L, tb.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        // ?
        tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-customizedNextVersion.xml");
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.invoke("nextVersion", 152L);
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByPrimaryKey",
                        100L, tb.getObject());
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = 152, field1 = 'null', inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKey", 100L, tb.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByPrimaryKey", 0L, tb.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
            }
        });
    }

    /**
     *  updateWithVersionByPrimaryKeyWithBLOBs
     */
    @Test
    public void testUpdateWithVersionByPrimaryKeyWithBLOBs() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator.xml");

        // withoutBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobs = new ObjectUtil(loader, packagz + ".TbBlobs");
                tbBlobs.set("id", 1L);
                tbBlobs.set("incF1", 152L); // ?sql?
                tbBlobs.set("incF2", 10L);
                tbBlobs.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByPrimaryKey", 100L, tbBlobs.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, field1 = 'null', inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKey", 100L, tbBlobs.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKey", 1L, tbBlobs.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
            }
        });

        // withBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsWithBLOBs = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs");
                tbBlobsWithBLOBs.set("id", 1L);
                tbBlobsWithBLOBs.set("incF1", 152L); // ?sql?
                tbBlobsWithBLOBs.set("incF2", 10L);
                tbBlobsWithBLOBs.set("incF3", 5L);
                tbBlobsWithBLOBs.set("field1", "ts1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByPrimaryKeyWithBLOBs", 100L, tbBlobsWithBLOBs.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, field1 = 'ts1', inc_f2 = 10, inc_f3 = 5, field2 = 'null', field3 = 'null' where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKeyWithBLOBs", 100L,
                        tbBlobsWithBLOBs.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKeyWithBLOBs", 1L,
                        tbBlobsWithBLOBs.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
                Assert.assertEquals(rs.getString("field1"), "ts1");
            }
        });

        // ====================================== ?
        // ==========================================
        tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-customizedNextVersion.xml");
        // withoutBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobs = new ObjectUtil(loader, packagz + ".TbBlobs");
                tbBlobs.set("id", 1L);
                tbBlobs.invoke("nextVersion", 152L);
                tbBlobs.set("incF2", 10L);
                tbBlobs.set("incF3", 5L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByPrimaryKey", 100L, tbBlobs.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = 152, field1 = 'null', inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKey", 100L, tbBlobs.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKey", 1L, tbBlobs.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
            }
        });

        // withBLOBs
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsWithBLOBs = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs");
                tbBlobsWithBLOBs.set("id", 1L);
                tbBlobsWithBLOBs.invoke("nextVersion", 152L);
                tbBlobsWithBLOBs.set("incF2", 10L);
                tbBlobsWithBLOBs.set("incF3", 5L);
                tbBlobsWithBLOBs.set("field1", "ts1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByPrimaryKeyWithBLOBs", 100L, tbBlobsWithBLOBs.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = 152, field1 = 'ts1', inc_f2 = 10, inc_f3 = 5, field2 = 'null', field3 = 'null' where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKeyWithBLOBs", 100L,
                        tbBlobsWithBLOBs.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKeyWithBLOBs", 1L,
                        tbBlobsWithBLOBs.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 152);
                Assert.assertEquals(rs.getString("field1"), "ts1");
            }
        });
    }

    /**
     * ?IncrementsPlugin?
     */
    @Test
    public void testWithIncrementsPlugin() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-with-IncrementsPlugin.xml");

        // updateWithVersionByExampleSelective
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBuilder = new ObjectUtil(loader, packagz + ".Tb$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".Tb$Builder$Inc#INC");
                tbBuilder.invoke("id", 1L);
                tbBuilder.invoke("incF1", 121l, tbBuilderInc.getObject()); // ?sql?
                tbBuilder.invoke("incF2", 5l, tbBuilderInc.getObject());
                tbBuilder.invoke("incF3", 10l);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByExampleSelective", 100L, tbBuilder.invoke("build"),
                        tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1, inc_f2 = inc_f2 + 5 , inc_f3 = 10 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExampleSelective", 100L,
                        tbBuilder.invoke("build"), tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByExampleSelective", 0L, tbBuilder.invoke("build"),
                        tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
                Assert.assertEquals(rs.getInt("inc_f2"), 7);
            }
        });

        // updateWithVersionByExample
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBuilder = new ObjectUtil(loader, packagz + ".Tb$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".Tb$Builder$Inc#INC");
                tbBuilder.invoke("id", 1L);
                tbBuilder.invoke("incF1", 121l, tbBuilderInc.getObject()); // ?sql?
                tbBuilder.invoke("incF2", 5l, tbBuilderInc.getObject());
                tbBuilder.invoke("incF3", 10l);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByExample", 100L,
                        tbBuilder.invoke("build"), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = inc_f1 + 1, id = 1, field1 = 'null', inc_f2 = inc_f2 + 5 , inc_f3 = 10 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByExample", 100L, tbBuilder.invoke("build"),
                        tbExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByExample", 0L, tbBuilder.invoke("build"),
                        tbExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        // withBLOBs?BLOBs?
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsExample = new ObjectUtil(loader, packagz + ".TbBlobsExample");
                ObjectUtil criteria = new ObjectUtil(tbBlobsExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBlobsWithBLOBsBuilder = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".TbBlobs$Builder$Inc#INC");
                tbBlobsWithBLOBsBuilder.invoke("id", 1L);
                tbBlobsWithBLOBsBuilder.invoke("incF2", 5L, tbBuilderInc.getObject());
                tbBlobsWithBLOBsBuilder.invoke("incF3", 10L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(), "updateWithVersionByExample",
                        100L, tbBlobsWithBLOBsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, id = 1, field1 = 'null', inc_f2 = inc_f2 + 5 , inc_f3 = 10 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByExample", 100L,
                        tbBlobsWithBLOBsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByExample", 1L,
                        tbBlobsWithBLOBsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
            }
        });

        // withBLOBs?BLOBs?
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsExample = new ObjectUtil(loader, packagz + ".TbBlobsExample");
                ObjectUtil criteria = new ObjectUtil(tbBlobsExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBlobsWithBLOBsBuilder = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".TbBlobs$Builder$Inc#INC");
                tbBlobsWithBLOBsBuilder.invoke("id", 1L);
                tbBlobsWithBLOBsBuilder.invoke("incF2", 5L, tbBuilderInc.getObject());
                tbBlobsWithBLOBsBuilder.invoke("incF3", 10L);
                tbBlobsWithBLOBsBuilder.invoke("field1", "ts1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByExampleWithBLOBs", 100L, tbBlobsWithBLOBsBuilder.invoke("build"),
                        tbBlobsExample.getObject());
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, id = 1, field1 = 'ts1', inc_f2 = inc_f2 + 5 , inc_f3 = 10, field2 = 'null', field3 = 'null' WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByExampleWithBLOBs", 100L,
                        tbBlobsWithBLOBsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByExampleWithBLOBs", 1L,
                        tbBlobsWithBLOBsBuilder.invoke("build"), tbBlobsExample.getObject());
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
                Assert.assertEquals(rs.getString("field1"), "ts1");
            }
        });

        // updateWithVersionByPrimaryKeySelective
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbBuilder = new ObjectUtil(loader, packagz + ".Tb$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".Tb$Builder$Inc#INC");
                tbBuilder.invoke("id", 1L);
                tbBuilder.invoke("incF1", 121l, tbBuilderInc.getObject()); // ?sql?
                tbBuilder.invoke("incF2", 5l, tbBuilderInc.getObject());
                tbBuilder.invoke("incF3", 10l);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByPrimaryKeySelective", 100L, tbBuilder.invoke("build"));
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, inc_f2 = inc_f2 + 5 , inc_f3 = 10 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 100L,
                        tbBuilder.invoke("build"));
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 0L, tbBuilder.invoke("build"));
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        // updateWithVersionByPrimaryKey
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbBuilder = new ObjectUtil(loader, packagz + ".Tb$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".Tb$Builder$Inc#INC");
                tbBuilder.invoke("id", 1L);
                tbBuilder.invoke("incF1", 121l, tbBuilderInc.getObject()); // ?sql?
                tbBuilder.invoke("incF2", 5l, tbBuilderInc.getObject());
                tbBuilder.invoke("incF3", 10l);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByPrimaryKey",
                        100L, tbBuilder.invoke("build"));
                Assert.assertEquals(sql,
                        "update tb set inc_f1 = inc_f1 + 1, field1 = 'null', inc_f2 = inc_f2 + 5 , inc_f3 = 10 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKey", 100L, tbBuilder.invoke("build"));
                Assert.assertEquals(result, 0);

                // id = 1 ?0
                result = tbMapper.invoke("updateWithVersionByPrimaryKey", 0L, tbBuilder.invoke("build"));
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
            }
        });

        // withBLOBs?BLOBs?
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsWithBLOBsBuilder = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".TbBlobs$Builder$Inc#INC");
                tbBlobsWithBLOBsBuilder.invoke("id", 1L);
                tbBlobsWithBLOBsBuilder.invoke("incF2", 5L, tbBuilderInc.getObject());
                tbBlobsWithBLOBsBuilder.invoke("incF3", 10L);

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByPrimaryKey", 100L, tbBlobsWithBLOBsBuilder.invoke("build"));
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, field1 = 'null', inc_f2 = inc_f2 + 5 , inc_f3 = 10 where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKey", 100L,
                        tbBlobsWithBLOBsBuilder.invoke("build"));
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKey", 1L,
                        tbBlobsWithBLOBsBuilder.invoke("build"));
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
            }
        });

        // withBLOBs?BLOBs?
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbBlobsMapper = new ObjectUtil(
                        sqlSession.getMapper(loader.loadClass(packagz + ".TbBlobsMapper")));

                ObjectUtil tbBlobsWithBLOBsBuilder = new ObjectUtil(loader, packagz + ".TbBlobsWithBLOBs$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".TbBlobs$Builder$Inc#INC");
                tbBlobsWithBLOBsBuilder.invoke("id", 1L);
                tbBlobsWithBLOBsBuilder.invoke("incF2", 5L, tbBuilderInc.getObject());
                tbBlobsWithBLOBsBuilder.invoke("incF3", 10L);
                tbBlobsWithBLOBsBuilder.invoke("field1", "ts1");

                // sql
                String sql = SqlHelper.getFormatMapperSql(tbBlobsMapper.getObject(),
                        "updateWithVersionByPrimaryKeyWithBLOBs", 100L, tbBlobsWithBLOBsBuilder.invoke("build"));
                Assert.assertEquals(sql,
                        "update tb_blobs set inc_f1 = inc_f1 + 1, field1 = 'ts1', inc_f2 = inc_f2 + 5 , inc_f3 = 10, field2 = 'null', field3 = 'null' where inc_f1 = 100 and id = 1");

                // ?100?0
                Object result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKeyWithBLOBs", 100L,
                        tbBlobsWithBLOBsBuilder.invoke("build"));
                Assert.assertEquals(result, 0);

                // id = 1 ?1
                result = tbBlobsMapper.invoke("updateWithVersionByPrimaryKeyWithBLOBs", 1L,
                        tbBlobsWithBLOBsBuilder.invoke("build"));
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb_blobs where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 2);
                Assert.assertEquals(rs.getString("field1"), "ts1");
            }
        });
    }

    /**
     * ?SelectiveEnhancedPlugin?
     */
    @Test
    public void testWithSelectiveEnhancedPlugin() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool
                .create("scripts/OptimisticLockerPlugin/mybatis-generator-with-SelectiveEnhancedPlugin.xml");

        // updateWithVersionByExampleSelective
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // selective
                ObjectUtil TbColumnId = new ObjectUtil(loader, packagz + ".Tb$Column#id");
                ObjectUtil TbColumnField1 = new ObjectUtil(loader, packagz + ".Tb$Column#field1");
                ObjectUtil TbColumnIncF1 = new ObjectUtil(loader, packagz + ".Tb$Column#incF1"); // ?sql?
                ObjectUtil TbColumnIncF2 = new ObjectUtil(loader, packagz + ".Tb$Column#incF2");
                Object columns = Array.newInstance(TbColumnField1.getCls(), 4);
                Array.set(columns, 0, TbColumnId.getObject());
                Array.set(columns, 1, TbColumnField1.getObject());
                Array.set(columns, 2, TbColumnIncF1.getObject());
                Array.set(columns, 3, TbColumnIncF2.getObject());

                // sql(?)
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByExampleSelective", 100L, tb.getObject(), tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1, inc_f2 = 10, inc_f3 = 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");
                // sql(selective)
                sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByExampleSelective",
                        100L, tb.getObject(), tbExample.getObject(), columns);
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1 , field1 = 'null' , inc_f2 = 10 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0(?)
                Object result = tbMapper.invoke("updateWithVersionByExampleSelective", 100L, tb.getObject(),
                        tbExample.getObject(), null);
                Assert.assertEquals(result, 0);

                // id = 1 ?0(selective )
                result = tbMapper.invoke("updateWithVersionByExampleSelective", 0L, tb.getObject(),
                        tbExample.getObject(), columns);
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
                Assert.assertEquals(rs.getInt("inc_f2"), 10);
            }
        });

        // updateWithVersionByPrimaryKeySelective
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tb = new ObjectUtil(loader, packagz + ".Tb");
                tb.set("id", 1L);
                tb.set("incF1", 152L); // ?sql?
                tb.set("incF2", 10L);
                tb.set("incF3", 5L);

                // selective
                ObjectUtil TbColumnId = new ObjectUtil(loader, packagz + ".Tb$Column#id");
                ObjectUtil TbColumnField1 = new ObjectUtil(loader, packagz + ".Tb$Column#field1");
                ObjectUtil TbColumnIncF1 = new ObjectUtil(loader, packagz + ".Tb$Column#incF1"); // ?sql?
                ObjectUtil TbColumnIncF2 = new ObjectUtil(loader, packagz + ".Tb$Column#incF2");
                Object columns = Array.newInstance(TbColumnField1.getCls(), 4);
                Array.set(columns, 0, TbColumnId.getObject());
                Array.set(columns, 1, TbColumnField1.getObject());
                Array.set(columns, 2, TbColumnIncF1.getObject());
                Array.set(columns, 3, TbColumnIncF2.getObject());

                // sql(?)
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByPrimaryKeySelective", 100L, tb.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, inc_f2 = 10, inc_f3 = 5 where inc_f1 = 100 and id = 1");
                // sql(selective)
                sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByPrimaryKeySelective",
                        100L, tb.getObject(), columns);
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1 , field1 = 'null' , inc_f2 = 10 where inc_f1 = 100 and id = 1");

                // ?100?0(?)
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 100L, tb.getObject(),
                        null);
                Assert.assertEquals(result, 0);

                // id = 1 ?0(selective )
                result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 0L, tb.getObject(), columns);
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
                Assert.assertEquals(rs.getInt("inc_f2"), 10);
            }
        });
    }

    /**
     * ?SelectiveEnhancedPlugin?IncrementsPlugin?
     */
    @Test
    public void testWithSelectiveEnhancedPluginAndIncrementsPlugin() throws Exception {
        MyBatisGeneratorTool tool = MyBatisGeneratorTool.create(
                "scripts/OptimisticLockerPlugin/mybatis-generator-with-SelectiveEnhancedPlugin-IncrementsPlugin.xml");

        // updateWithVersionByExampleSelective
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbExample = new ObjectUtil(loader, packagz + ".TbExample");
                ObjectUtil criteria = new ObjectUtil(tbExample.invoke("createCriteria"));
                criteria.invoke("andIdEqualTo", 1l);

                ObjectUtil tbBuilder = new ObjectUtil(loader, packagz + ".Tb$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".Tb$Builder$Inc#INC");
                tbBuilder.invoke("id", 1L);
                tbBuilder.invoke("incF1", 121l, tbBuilderInc.getObject()); // ?sql?
                tbBuilder.invoke("incF2", 5l, tbBuilderInc.getObject());
                tbBuilder.invoke("incF3", 10l);

                // selective
                ObjectUtil TbColumnId = new ObjectUtil(loader, packagz + ".Tb$Column#id");
                ObjectUtil TbColumnField1 = new ObjectUtil(loader, packagz + ".Tb$Column#field1");
                ObjectUtil TbColumnIncF1 = new ObjectUtil(loader, packagz + ".Tb$Column#incF1"); // ?sql?
                ObjectUtil TbColumnIncF2 = new ObjectUtil(loader, packagz + ".Tb$Column#incF2");
                Object columns = Array.newInstance(TbColumnField1.getCls(), 4);
                Array.set(columns, 0, TbColumnId.getObject());
                Array.set(columns, 1, TbColumnField1.getObject());
                Array.set(columns, 2, TbColumnIncF1.getObject());
                Array.set(columns, 3, TbColumnIncF2.getObject());

                // sql(?)
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByExampleSelective", 100L, tbBuilder.invoke("build"),
                        tbExample.getObject());
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1, inc_f2 = inc_f2 + 5 , inc_f3 = 10 WHERE inc_f1 = 100 and ( ( id = '1' ) )");
                // sql(selective)
                sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByExampleSelective",
                        100L, tbBuilder.invoke("build"), tbExample.getObject(), columns);
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1 , field1 = 'null' , inc_f2 = inc_f2 + 5 WHERE inc_f1 = 100 and ( ( id = '1' ) )");

                // ?100?0(?)
                Object result = tbMapper.invoke("updateWithVersionByExampleSelective", 100L,
                        tbBuilder.invoke("build"), tbExample.getObject(), null);
                Assert.assertEquals(result, 0);

                // id = 1 ?0(selective )
                result = tbMapper.invoke("updateWithVersionByExampleSelective", 0L, tbBuilder.invoke("build"),
                        tbExample.getObject(), columns);
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
                Assert.assertEquals(rs.getInt("inc_f2"), 7);
            }
        });

        // updateWithVersionByPrimaryKeySelective
        tool.generate(new IBeforeCallback() {
            @Override
            public void run() throws Exception {
                DBHelper.resetDB("scripts/OptimisticLockerPlugin/init.sql");
            }
        }, new AbstractShellCallback() {
            @Override
            public void reloadProject(SqlSession sqlSession, ClassLoader loader, String packagz) throws Exception {
                ObjectUtil tbMapper = new ObjectUtil(sqlSession.getMapper(loader.loadClass(packagz + ".TbMapper")));

                ObjectUtil tbBuilder = new ObjectUtil(loader, packagz + ".Tb$Builder");
                ObjectUtil tbBuilderInc = new ObjectUtil(loader, packagz + ".Tb$Builder$Inc#INC");
                tbBuilder.invoke("id", 1L);
                tbBuilder.invoke("incF1", 121l, tbBuilderInc.getObject()); // ?sql?
                tbBuilder.invoke("incF2", 5l, tbBuilderInc.getObject());
                tbBuilder.invoke("incF3", 10l);

                // selective
                ObjectUtil TbColumnId = new ObjectUtil(loader, packagz + ".Tb$Column#id");
                ObjectUtil TbColumnField1 = new ObjectUtil(loader, packagz + ".Tb$Column#field1");
                ObjectUtil TbColumnIncF1 = new ObjectUtil(loader, packagz + ".Tb$Column#incF1"); // ?sql?
                ObjectUtil TbColumnIncF2 = new ObjectUtil(loader, packagz + ".Tb$Column#incF2");
                Object columns = Array.newInstance(TbColumnField1.getCls(), 4);
                Array.set(columns, 0, TbColumnId.getObject());
                Array.set(columns, 1, TbColumnField1.getObject());
                Array.set(columns, 2, TbColumnIncF1.getObject());
                Array.set(columns, 3, TbColumnIncF2.getObject());

                // sql(?)
                String sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(),
                        "updateWithVersionByPrimaryKeySelective", 100L, tbBuilder.invoke("build"));
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, inc_f2 = inc_f2 + 5 , inc_f3 = 10 where inc_f1 = 100 and id = 1");
                // sql(selective)
                sql = SqlHelper.getFormatMapperSql(tbMapper.getObject(), "updateWithVersionByPrimaryKeySelective",
                        100L, tbBuilder.invoke("build"), columns);
                Assert.assertEquals(sql,
                        "update tb SET inc_f1 = inc_f1 + 1, id = 1 , field1 = 'null' , inc_f2 = inc_f2 + 5 where inc_f1 = 100 and id = 1");

                // ?100?0(?)
                Object result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 100L,
                        tbBuilder.invoke("build"), null);
                Assert.assertEquals(result, 0);

                // id = 1 ?0(selective )
                result = tbMapper.invoke("updateWithVersionByPrimaryKeySelective", 0L, tbBuilder.invoke("build"),
                        columns);
                Assert.assertEquals(result, 1);

                // ???1
                ResultSet rs = DBHelper.execute(sqlSession.getConnection(), "select * from tb where id = 1");
                rs.first();
                Assert.assertEquals(rs.getInt("inc_f1"), 1);
                Assert.assertEquals(rs.getInt("inc_f2"), 7);
            }
        });
    }
}