MyBatis Dynamic SQL Usage Notes

This page is a short introduction to using the classes generated for the MyBatis3DynamicSQL runtime. These classes are dependent on the MyBatis Dynamic SQL library. Please refer to that site for full information about how the library works.

For each introspected table, the generator will generate three objects:

  1. A "record" class that represents a row in the table. This is the same as other runtimes
  2. A "support" class that includes a table definition and column definitions for the database table
  3. A mapper interface with all the typical methods generated by the other runtimes.

Important notes about the generated objects:

  • No XML is generated
  • No separate "Example" class is generated
  • There are no separate "with BLOBs" and "without BLOBs" methods. If your table includes BLOB fields, then they are included in all operations.
  • Model classes are always generated in the "flat" model meaning there is no separate primary key class or BLOBs class
  • Java 8 or higher is required
  • MyBatis 3.4.2 or higher is required
  • MyBatis Dynamic SQL 1.3.1 or higher is required

Format of the "Support" classes

A "support" class is created for each table. The support class includes a definition of the table and all the columns in the table. These items are used as input to the code generated in the mappers - most often for the where clauses you will write.

For example, suppose there is a table "TABLE_CODE" in schema "MYSCHEMA". Further suppose that table has "ID" and "DESCRIPTION" columns. The generated support class will look like this:

package example;

import java.sql.JDBCType;
import org.mybatis.dynamic.sql.SqlColumn;
import org.mybatis.dynamic.sql.SqlTable;

public final class TableCodeDynamicSqlSupport {
    public static final TableCode tableCode = new TableCode();
    public static final SqlColumn<Integer> id = tableCode.id;
    public static final SqlColumn<String> description = tableCode.description;

    public static final class TableCode extends AliasableSqlTable<TableCode> {
        public final SqlColumn<Integer> id = column("ID", JDBCType.INTEGER);
        public final SqlColumn<String> description = column("DESCRIPTION", JDBCType.VARCHAR);

        public TableCode() {
            super("MYSCHEMA.TABLE_CODE", TableCode::new);
        }
    }
}

In your code, it is typical to import the static elements of this support class so they can be used directly in the code you write. With this static import you can refer to the fields in either a direct or qualified manner - "id" or "tableCode.id".

Usage of the Mapper Classes

The following methods work the same as the other runtimes and we won't cover them here:

  • deleteByPrimaryKey
  • insert - insert a single row (will insert nulls)
  • insertMultiple - insert multiple rows (will insert nulls)
  • insertSelective - insert a single row and ignore null properties
  • selectByPrimaryKey
  • updateByPrimaryKey - will set null values
  • updateByPrimaryKey Selective - ignores null values

There are no "by example" methods. Instead, there are general purpose methods that allow you to specify a where clause with a lambda. The generator will create the following general methods:

  • count
  • delete
  • select
  • selectDistinct
  • selectOne
  • update

Each of these methods includes support for a very flexible WHERE clause that can be specified with a lambda. If you don't need a where clauses, there are utility functions that mean "all rows".

For example, you can retrieve the total number of rows in a table by calling the count method without a WHERE clause. That code looks like this:

  long totalRows = mapper.count(c -> c);
Or...
  long totalRows = mapper.count(CountDSLCompleter.allRows());

You can retrieve all rows in a table by calling select without a WHERE clause like this:

  List<TableCode> allRecords = mapper.select(c -> c);
Or...
  List<TableCode> allRecords = mapper.select(SelectDSLCompleter.allRows());

It is far more interesting to add WHERE clauses to these methods. To add support for WHERE clauses, you should import the static elements from the support class as shown above, and you should also import the SqlBuilder support. Then you can code arbitrarily complex where clauses, and "ORDER BY" phrases as shown below:

import static example.TableCodeDynamicSqlSupport.*;  // import the generated "support" items
import static org.mybatis.dynamic.sql.SqlBuilder.*;  // import MyBatis Dynamic SQL where support

public class SomeService {

    public void simpleWhere() {
        ...
        // Simple WHERE clause
        List<TableCode> records = mapper.select(c ->
                c.where(id, isEqualTo(3)));
        ...
    }

    public void complexWhere1() {
        ...
        // Simple WHERE clause with OR
        List<TableCode> records = mapper.select(c ->
                c.where(id, isEqualTo(3))
                .or(description, isLike("f%")));
        ...
    }

    public void complexWhere2() {
        ...
        // complex WHERE and ORDER BY
        List<TableCode> records = mapper.select(c ->
                c.where(id, isLessThan(10), and(description, isEqualTo("foo")))
                .or(description, isLike("b%"))
                .orderBy(id.descending()));
        ...
    }
}

Update Method Usage

The generated update statement is very flexible. You can now create any arbitrary update, as well as updates that mimic the old updateByExample and updateByExampleSelective methods.

import static example.TableCodeDynamicSqlSupport.*;  // import the generated "support" items
import static org.mybatis.dynamic.sql.SqlBuilder.*;  // import MyBatis Dynamic SQL where support

public class SomeService {

    public void simpleUpdate() {
        ...
        // Flexible update - no backing record needed
        int rows = mapper.update(c ->
                c.set(id).equalTo(1)
                .set(description).equalToNull()
                .where(id, isEqualTo(3)));
        ...
    }

    public void updateByExample(TableCode row) {
        ...
        // Update like the old updateByExample method
        int rows =  mapper.update(c ->
                TableCodeMapper.updateAllColumns(row, c)
                .where(id, isEqualTo(3))
                .or(description, isLike("f%")));
        ...
    }

    public void updateByExampleSelective(TableCode row) {
        ...
        // Update like the old updateByExampleSelective method
        int rows =  mapper.update(c ->
                TableCodeMapper.updateSelectiveColumns(row, c)
                .where(id, isEqualTo(3))
                .or(description, isLike("f%")));
        ...
    }
}

New Plugins

Because the *ByExample methods are removed, it no longer makes sense to control method generation via the properties on an XML <table> configuration like enableInsert, enableSelectByExample, etc. So this new runtime will ignore any of those properties. If you wish to have this level of control over what is generated, you can accomplish that with a plugin. We have also included the following new plugins for general use with this runtime:

  • org.mybatis.generator.plugins.dsql.DisableDeletePlugin - disables all generated delete methods
  • org.mybatis.generator.plugins.dsql.DisableInsertPlugin - disables all generated insert methods
  • org.mybatis.generator.plugins.dsql.DisableUpdatePlugin - disables all generated update methods
  • org.mybatis.generator.plugins.dsql.ReadOnlyPlugin - disables all generated delete, insert, and update methods